[PATCH] drm/amd: Fix shutdown (again) on some SMU v13.0.4/11 platforms

2024-05-26 Thread Mario Limonciello
commit cd94d1b182d2 ("dm/amd/pm: Fix problems with reboot/shutdown for
some SMU 13.0.4/13.0.11 users") attempted to fix shutdown issues
that were reported since commit 31729e8c21ec ("drm/amd/pm: fixes a
random hang in S4 for SMU v13.0.4/11") but caused issues for some
people.

Adjust the workaround flow to properly only apply in the S4 case:
-> For shutdown go through SMU_MSG_PrepareMp1ForUnload
-> For S4 go through SMU_MSG_GfxDeviceDriverReset and
   SMU_MSG_PrepareMp1ForUnload

Reported-and-tested-by: lectrode 
Closes: https://github.com/void-linux/void-packages/issues/50417
Cc: sta...@vger.kernel.org
Fixes: cd94d1b182d2 ("dm/amd/pm: Fix problems with reboot/shutdown for some SMU 
13.0.4/13.0.11 users")
Signed-off-by: Mario Limonciello 
---
Cc: regressi...@lists.linux.dev
---
 .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c  | 20 ++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c 
b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index 4abfcd32747d..c7ab0d7027d9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -226,15 +226,17 @@ static int smu_v13_0_4_system_features_control(struct 
smu_context *smu, bool en)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
 
-   if (!en && adev->in_s4) {
-   /* Adds a GFX reset as workaround just before sending the
-* MP1_UNLOAD message to prevent GC/RLC/PMFW from entering
-* an invalid state.
-*/
-   ret = smu_cmn_send_smc_msg_with_param(smu, 
SMU_MSG_GfxDeviceDriverReset,
- SMU_RESET_MODE_2, NULL);
-   if (ret)
-   return ret;
+   if (!en && !adev->in_s0ix) {
+   if (adev->in_s4) {
+   /* Adds a GFX reset as workaround just before sending 
the
+* MP1_UNLOAD message to prevent GC/RLC/PMFW from 
entering
+* an invalid state.
+*/
+   ret = smu_cmn_send_smc_msg_with_param(smu, 
SMU_MSG_GfxDeviceDriverReset,
+   SMU_RESET_MODE_2, NULL);
+   if (ret)
+   return ret;
+   }
 
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, 
NULL);
}
-- 
2.43.0



[PATCH v2 3/4] tests/amdgpu/amd_abm: Add support for panel_power_saving property

2024-05-22 Thread Mario Limonciello
From: Mario Limonciello 

When the "panel power saving" property is set to forbidden the
compositor has indicated that userspace prefers to have color
accuracy and fidelity instead of power saving.

Verify that the sysfs file behaves as expected in this situation.

Signed-off-by: Mario Limonciello 
---
 tests/amdgpu/amd_abm.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
index f74c3012c..3fa1366fa 100644
--- a/tests/amdgpu/amd_abm.c
+++ b/tests/amdgpu/amd_abm.c
@@ -365,6 +365,43 @@ static void abm_gradual(data_t *data)
}
 }
 
+
+static void abm_forbidden(data_t *data)
+{
+   igt_output_t *output;
+   enum pipe pipe;
+   int target, r;
+
+   for_each_pipe_with_valid_output(>display, pipe, output) {
+   if (output->config.connector->connector_type != 
DRM_MODE_CONNECTOR_eDP)
+   continue;
+
+   r = clear_power_saving_policy(data->drm_fd, output);
+   if (r == -ENODEV) {
+   igt_skip("No power saving policy prop\n");
+   return;
+   }
+   igt_assert_eq(r, 0);
+
+   target = 3;
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, 0);
+
+   r = set_panel_power_saving_policy(data->drm_fd, output, 
DRM_MODE_REQUIRE_COLOR_ACCURACY);
+   igt_assert_eq(r, 0);
+
+   target = 0;
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, -1);
+
+   r = clear_power_saving_policy(data->drm_fd, output);
+   igt_assert_eq(r, 0);
+
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, 0);
+   }
+}
+
 igt_main
 {
data_t data = {};
@@ -393,6 +430,8 @@ igt_main
abm_enabled();
igt_subtest("abm_gradual")
abm_gradual();
+   igt_subtest("abm_forbidden")
+   abm_forbidden();
 
igt_fixture {
igt_display_fini();
-- 
2.43.0



[PATCH v2 2/4] tests/amdgpu/amd_abm: Make set_abm_level return type int

2024-05-22 Thread Mario Limonciello
From: Mario Limonciello 

In order to bubble of cases of expeted errors on set_abm_level()
change the return type to int.

Signed-off-by: Mario Limonciello 
---
 tests/amdgpu/amd_abm.c | 33 +++--
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
index 2882c2c18..f74c3012c 100644
--- a/tests/amdgpu/amd_abm.c
+++ b/tests/amdgpu/amd_abm.c
@@ -104,10 +104,11 @@ static int backlight_write_brightness(int value)
return 0;
 }
 
-static void set_abm_level(data_t *data, igt_output_t *output, int level)
+static int set_abm_level(data_t *data, igt_output_t *output, int level)
 {
char buf[PATH_MAX];
int fd;
+   int ret;
 
igt_assert(snprintf(buf, PATH_MAX, PANEL_POWER_SAVINGS_PATH,
output->name) < PATH_MAX);
@@ -116,8 +117,12 @@ static void set_abm_level(data_t *data, igt_output_t 
*output, int level)
 
igt_assert(fd != -1);
 
-   igt_assert_eq(snprintf(buf, sizeof(buf), "%d", level),
- write(fd, buf, 1));
+   snprintf(buf, sizeof(buf), "%d", level);
+   ret = write(fd, buf, 1);
+   if (ret < 0) {
+   close(fd);
+   return ret;
+   }
 
igt_assert_eq(close(fd), 0);
 
@@ -129,6 +134,7 @@ static void set_abm_level(data_t *data, igt_output_t 
*output, int level)
 DRM_MODE_DPMS_OFF);
kmstest_set_connector_dpms(data->drm_fd, output->config.connector,
 DRM_MODE_DPMS_ON);
+   return 0;
 }
 
 static int backlight_read_max_brightness(int *result)
@@ -192,7 +198,8 @@ static void backlight_dpms_cycle(data_t *data)
ret = backlight_read_max_brightness(_brightness);
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness / 2);
usleep(10);
pwm_1 = read_target_backlight_pwm(data->drm_fd, output->name);
@@ -223,7 +230,8 @@ static void backlight_monotonic_basic(data_t *data)
 
brightness_step = max_brightness / 10;
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
@@ -257,7 +265,8 @@ static void backlight_monotonic_abm(data_t *data)
 
brightness_step = max_brightness / 10;
for (i = 1; i < 5; i++) {
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
@@ -289,14 +298,16 @@ static void abm_enabled(data_t *data)
ret = backlight_read_max_brightness(_brightness);
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
pwm_without_abm = prev_pwm;
 
for (i = 1; i < 5; i++) {
-   set_abm_level(data, output, i);
+   ret = set_abm_level(data, output, i);
+   igt_assert_eq(ret, 0);
usleep(10);
pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
igt_assert(pwm <= prev_pwm);
@@ -323,7 +334,8 @@ static void abm_gradual(data_t *data)
 
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
 
sleep(convergence_delay);
@@ -331,7 +343,8 @@ static void abm_gradual(data_t *data)
curr = read_current_backlight_pwm(data->drm_fd, output->name);
 
igt_assert_eq(prev_pwm, curr);
-   set_abm_level(data, output, 4);
+   ret = set_abm_level(data, output, 4);
+   igt_assert_eq(ret, 0);
for (i = 0; i < 10; i++) {
usleep(10);
pwm = read_current_backlight_pwm(data->drm_fd, 
output->name);
-- 
2.43.0



[PATCH v2 4/4] tests/amdgpu/amd_psr: Add support for `power saving policy` property

2024-05-22 Thread Mario Limonciello
Verify that the property has disabled PSR
---
 tests/amdgpu/amd_psr.c | 74 ++
 1 file changed, 74 insertions(+)

diff --git a/tests/amdgpu/amd_psr.c b/tests/amdgpu/amd_psr.c
index 9da161a09..a9f4a6aa5 100644
--- a/tests/amdgpu/amd_psr.c
+++ b/tests/amdgpu/amd_psr.c
@@ -338,6 +338,78 @@ static void run_check_psr(data_t *data, bool 
test_null_crtc) {
test_fini(data);
 }
 
+static void psr_forbidden(data_t *data)
+{
+   int edp_idx, ret, i, psr_state;
+   igt_fb_t ref_fb, ref_fb2;
+   igt_fb_t *flip_fb;
+   igt_output_t *output;
+
+   test_init(data);
+
+   edp_idx = check_conn_type(data, DRM_MODE_CONNECTOR_eDP);
+   igt_skip_on_f(edp_idx == -1, "no eDP connector found\n");
+
+   /* check if eDP support PSR1, PSR-SU.
+*/
+   igt_skip_on(!psr_mode_supported(data, PSR_MODE_1) && 
!psr_mode_supported(data, PSR_MODE_2));
+   for_each_connected_output(>display, output) {
+
+   if (output->config.connector->connector_type != 
DRM_MODE_CONNECTOR_eDP)
+   continue;
+   ret = clear_power_saving_policy(data->fd, output);
+   if (ret == -ENODEV) {
+   igt_skip("No power saving policy prop\n");
+   return;
+   }
+   igt_require(ret == 0);
+
+   /* try to engage PSR */
+   ret = set_panel_power_saving_policy(data->fd, output, 
DRM_MODE_REQUIRE_LOW_LATENCY);
+   igt_assert_eq(ret, 0);
+
+   igt_create_color_fb(data->fd, data->mode->hdisplay,
+   data->mode->vdisplay, DRM_FORMAT_XRGB, 
0, 1.0,
+   0.0, 0.0, _fb);
+   igt_create_color_fb(data->fd, data->mode->hdisplay,
+   data->mode->vdisplay, DRM_FORMAT_XRGB, 
0, 0.0,
+   1.0, 0.0, _fb2);
+
+   igt_plane_set_fb(data->primary, _fb);
+
+   igt_display_commit_atomic(>display, 
DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+   for (i = 0; i < N_FLIPS; i++) {
+   if (i % 2 == 0)
+   flip_fb = _fb2;
+   else
+   flip_fb = _fb;
+
+   ret = drmModePageFlip(data->fd, 
output->config.crtc->crtc_id,
+ flip_fb->fb_id, 
DRM_MODE_PAGE_FLIP_EVENT, NULL);
+   igt_require(ret == 0);
+   kmstest_wait_for_pageflip(data->fd);
+   }
+
+   /* PSR state takes some time to settle its value on static 
screen */
+   sleep(PSR_SETTLE_DELAY);
+
+   psr_state =  igt_amd_read_psr_state(data->fd, output->name);
+   igt_require(psr_state == PSR_STATE3);
+
+   igt_remove_fb(data->fd, _fb);
+   igt_remove_fb(data->fd, _fb2);
+
+   ret = clear_power_saving_policy(data->fd, output);
+   if (ret == -ENODEV) {
+   igt_skip("No power saving policy prop\n");
+   return;
+   }
+   igt_require(ret == 0);
+
+   }
+}
+
 static void run_check_psr_su_mpo(data_t *data, bool scaling, float 
scaling_ratio)
 {
int edp_idx = check_conn_type(data, DRM_MODE_CONNECTOR_eDP);
@@ -756,6 +828,8 @@ igt_main_args("", long_options, help_str, opt_handler, NULL)
igt_describe("Test to validate PSR SU enablement with Visual Confirm "
 "and to validate PSR SU disable/re-enable w/ primary 
scaling ratio 0.75");
igt_subtest("psr_su_mpo_scaling_0_75") run_check_psr_su_mpo(, 
true, .75);
+   igt_describe("Test whether PSR can be forbidden");
+   igt_subtest("psr_forbidden") psr_forbidden();
 
igt_fixture
{
-- 
2.43.0



[PATCH v2 1/4] Add support for API for drivers to set power saving policy

2024-05-22 Thread Mario Limonciello
---
 lib/igt_kms.c | 26 ++
 lib/igt_kms.h |  6 ++
 2 files changed, 32 insertions(+)

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index af63d13b1..4ce5e4a95 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -6581,3 +6581,29 @@ int get_num_scalers(int drm_fd, enum pipe pipe)
 
return num_scalers;
 }
+
+static int toggle_power_saving_policy_prop(int drm_fd, igt_output_t *output, 
uint64_t policy)
+{
+   uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
+   bool prop_exists;
+   uint32_t prop_id;
+
+   prop_exists = kmstest_get_property(
+   drm_fd, output->id, type, "power saving policy",
+   _id, NULL, NULL);
+
+   if (!prop_exists)
+   return -ENODEV;
+
+   return drmModeObjectSetProperty(drm_fd, output->id, type, prop_id, 
policy);
+}
+
+int clear_power_saving_policy(int drm_fd, igt_output_t *output)
+{
+   return toggle_power_saving_policy_prop(drm_fd, output, 0);
+}
+
+int set_panel_power_saving_policy(int drm_fd, igt_output_t *output, uint64_t 
policy)
+{
+   return toggle_power_saving_policy_prop(drm_fd, output, policy);
+}
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index 01604dac9..129b88576 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -1223,4 +1223,10 @@ bool igt_check_output_is_dp_mst(igt_output_t *output);
 int igt_get_dp_mst_connector_id(igt_output_t *output);
 int get_num_scalers(int drm_fd, enum pipe pipe);
 
+#define DRM_MODE_REQUIRE_COLOR_ACCURACYBIT(0)  /* Compositor requires 
color accuracy */
+#define DRM_MODE_REQUIRE_LOW_LATENCY   BIT(1)  /* Compositor requires low 
latency */
+
+int clear_power_saving_policy(int drm_fd, igt_output_t *output);
+int set_panel_power_saving_policy(int drm_fd, igt_output_t *output, uint64_t 
policy);
+
 #endif /* __IGT_KMS_H__ */
-- 
2.43.0



[PATCH v2 0/4] Add support for testing power saving policy DRM property

2024-05-22 Thread Mario Limonciello
During the Display Next hackfest 2024 one of the topics discussed
was the need for compositor to be able to relay intention to drivers
that color fidelity or low latency is preferred over power savings.

To accomplish this a new optional DRM property is being introduced called
"power saving policy".  This property is a bit mask that can be configured
by the compositor to for it's requirements.

When a driver advertises support for this property and the compositor
sets requirements then the driver will disable any appplicable power saving
features that can compromise the requirements.

This set of IGT changes introduces a new subtest that will cover the
expected kernel behavior when switching between requirements.

Mario Limonciello (4):
  Add support for API for drivers to set power saving policy
  tests/amdgpu/amd_abm: Make set_abm_level return type int
  tests/amdgpu/amd_abm: Add support for panel_power_saving property
  tests/amdgpu/amd_psr: Add support for `power saving policy` property

 lib/igt_kms.c  | 26 +++
 lib/igt_kms.h  |  6 
 tests/amdgpu/amd_abm.c | 72 ++--
 tests/amdgpu/amd_psr.c | 74 ++
 4 files changed, 168 insertions(+), 10 deletions(-)

-- 
2.43.0



[PATCH v2 0/2] Add support for 'power saving policy' property

2024-05-22 Thread Mario Limonciello
During the Display Next hackfest 2024 one of the topics discussed
was the need for compositor to be able to relay intention to drivers
that color fidelity is preferred over power savings.

To accomplish this a new optional DRM property is being introduced called
"power saving policy".  This property is a bit mask that can be configured
with requests of "Require color accuracy" or "Require low latency"
that can be configured by the compositor.

When a driver advertises support for this property and the compositor
sets it to "Require color accuracy" then the driver will disable any power
saving features that can compromise color fidelity.

In practice the main feature this currently applies to is the
"Adaptive Backlight Modulation" feature within AMD DCN on eDP panels.

When the compositor has marked the property  "Require color accuracy" then
this feature will be disabled and any userspace that tries to turn it on
will get an -EBUSY return code.

Compositors can also request that low latency is critical which in practice
should cause PSR and PSR2 to be disabled.

When the compositor has restored the value back to no requirements then the
previous value that would have been programmed will be restored.

---
v1->v2:
 * New property as a bitmask
 * Handle both ABM and PSR/PSR2
 * Add documentation

Mario Limonciello (2):
  drm: Introduce 'power saving policy' drm property
  drm/amd: Add power_saving_policy drm property to eDP connectors

 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 51 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 drivers/gpu/drm/drm_connector.c   | 46 +
 include/drm/drm_connector.h   |  2 +
 include/drm/drm_mode_config.h |  5 ++
 include/uapi/drm/drm_mode.h   |  7 +++
 7 files changed, 112 insertions(+), 5 deletions(-)

-- 
2.43.0



[PATCH v2 2/2] drm/amd: Add power_saving_policy drm property to eDP connectors

2024-05-22 Thread Mario Limonciello
When the `power_saving_policy` property is set to bit mask
"Require color accuracy" ABM should be disabled immediately and
any requests by sysfs to update will return an -EBUSY error.

When the `power_saving_policy` property is set to bit mask
"Require low latency" PSR should be disabled.

When the property is restored to an empty bit mask the previous
value of ABM and pSR will be restored.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 51 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 3 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 3ecc7ef95172..cfb5220cf182 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -1350,6 +1350,10 @@ int amdgpu_display_modeset_create_props(struct 
amdgpu_device *adev)
 "dither",
 amdgpu_dither_enum_list, sz);
 
+   if (adev->dc_enabled)
+   drm_mode_create_power_saving_policy_property(adev_to_drm(adev),
+
DRM_MODE_POWER_SAVING_POLICY_ALL);
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 01b0a331e4a6..a480e86892de 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6421,6 +6421,13 @@ int amdgpu_dm_connector_atomic_set_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
dm_new_state->underscan_enable = val;
ret = 0;
+   } else if (property == dev->mode_config.power_saving_policy) {
+   dm_new_state->abm_forbidden = val & 
DRM_MODE_REQUIRE_COLOR_ACCURACY;
+   dm_new_state->abm_level = (dm_new_state->abm_forbidden || 
!amdgpu_dm_abm_level) ?
+   ABM_LEVEL_IMMEDIATE_DISABLE :
+   amdgpu_dm_abm_level;
+   dm_new_state->psr_forbidden = val & 
DRM_MODE_REQUIRE_LOW_LATENCY;
+   ret = 0;
}
 
return ret;
@@ -6463,6 +6470,13 @@ int amdgpu_dm_connector_atomic_get_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
*val = dm_state->underscan_enable;
ret = 0;
+   } else if (property == dev->mode_config.power_saving_policy) {
+   *val = 0;
+   if (dm_state->psr_forbidden)
+   *val |= DRM_MODE_REQUIRE_LOW_LATENCY;
+   if (dm_state->abm_forbidden)
+   *val |= DRM_MODE_REQUIRE_COLOR_ACCURACY;
+   ret = 0;
}
 
return ret;
@@ -6489,9 +6503,12 @@ static ssize_t panel_power_savings_show(struct device 
*device,
u8 val;
 
drm_modeset_lock(>mode_config.connection_mutex, NULL);
-   val = to_dm_connector_state(connector->state)->abm_level ==
-   ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
-   to_dm_connector_state(connector->state)->abm_level;
+   if (to_dm_connector_state(connector->state)->abm_forbidden)
+   val = 0;
+   else
+   val = to_dm_connector_state(connector->state)->abm_level ==
+   ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
+   to_dm_connector_state(connector->state)->abm_level;
drm_modeset_unlock(>mode_config.connection_mutex);
 
return sysfs_emit(buf, "%u\n", val);
@@ -6515,10 +6532,16 @@ static ssize_t panel_power_savings_store(struct device 
*device,
return -EINVAL;
 
drm_modeset_lock(>mode_config.connection_mutex, NULL);
-   to_dm_connector_state(connector->state)->abm_level = val ?:
-   ABM_LEVEL_IMMEDIATE_DISABLE;
+   if (to_dm_connector_state(connector->state)->abm_forbidden)
+   ret = -EBUSY;
+   else
+   to_dm_connector_state(connector->state)->abm_level = val ?:
+   ABM_LEVEL_IMMEDIATE_DISABLE;
drm_modeset_unlock(>mode_config.connection_mutex);
 
+   if (ret)
+   return ret;
+
drm_kms_helper_hotplug_event(dev);
 
return count;
@@ -7689,6 +7712,13 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_requested_bpc = 
aconnector->base.state->max_bpc;
 
+   if (connector_type == DRM_MODE_CONNECTOR_eDP &&
+   

[PATCH v2 1/2] drm: Introduce 'power saving policy' drm property

2024-05-22 Thread Mario Limonciello
The `power saving policy` DRM property is an optional property that
can be added to a connector by a driver.

This property is for compositors to indicate intent of policy of
whether a driver can use power saving features that may compromise
the experience intended by the compositor.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/drm_connector.c | 46 +
 include/drm/drm_connector.h |  2 ++
 include/drm/drm_mode_config.h   |  5 
 include/uapi/drm/drm_mode.h |  7 +
 4 files changed, 60 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4d2df7f64dc5..088a5874c7a4 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -961,6 +961,11 @@ static const struct drm_prop_enum_list 
drm_scaling_mode_enum_list[] = {
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
 };
 
+static const struct drm_prop_enum_list drm_power_saving_policy_enum_list[] = {
+   { __builtin_ffs(DRM_MODE_REQUIRE_COLOR_ACCURACY) - 1, "Require color 
accuracy" },
+   { __builtin_ffs(DRM_MODE_REQUIRE_LOW_LATENCY) - 1, "Require low 
latency" },
+};
+
 static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
{ DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
{ DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
@@ -1499,6 +1504,16 @@ static const u32 dp_colorspaces =
  *
  * Drivers can set up these properties by calling
  * drm_mode_create_tv_margin_properties().
+ * power saving policy:
+ * This property is used to set the power saving policy for the connector.
+ * This property is populated with a bitmask of optional requirements set
+ * by the drm master for the drm driver to respect:
+ * - "Require color accuracy": Disable power saving features that will
+ *   affect color fidelity.
+ *   For example: Hardware assisted backlight modulation.
+ * - "Require low latency": Disable power saving features that will
+ *   affect latency.
+ *   For example: Panel self refresh (PSR)
  */
 
 int drm_connector_create_standard_properties(struct drm_device *dev)
@@ -1963,6 +1978,37 @@ int drm_mode_create_scaling_mode_property(struct 
drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
+/**
+ * drm_mode_create_power_saving_policy_property - create power saving policy 
property
+ * @dev: DRM device
+ * @supported_policies: bitmask of supported power saving policies
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ *
+ * Returns: %0
+ */
+int drm_mode_create_power_saving_policy_property(struct drm_device *dev,
+uint64_t supported_policies)
+{
+   struct drm_property *power_saving;
+
+   if (dev->mode_config.power_saving_policy)
+   return 0;
+   WARN_ON((supported_policies & DRM_MODE_POWER_SAVING_POLICY_ALL) == 0);
+
+   power_saving =
+   drm_property_create_bitmask(dev, 0, "power saving policy",
+   drm_power_saving_policy_enum_list,
+   
ARRAY_SIZE(drm_power_saving_policy_enum_list),
+   supported_policies);
+
+   dev->mode_config.power_saving_policy = power_saving;
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_power_saving_policy_property);
+
 /**
  * DOC: Variable refresh properties
  *
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index fe88d7fc6b8f..b0ec2ec48de7 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2025,6 +2025,8 @@ int drm_mode_create_dp_colorspace_property(struct 
drm_connector *connector,
   u32 supported_colorspaces);
 int drm_mode_create_content_type_property(struct drm_device *dev);
 int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
+int drm_mode_create_power_saving_policy_property(struct drm_device *dev,
+uint64_t supported_policies);
 
 int drm_connector_set_path_property(struct drm_connector *connector,
const char *path);
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 973119a9176b..32077e701e2f 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -954,6 +954,11 @@ struct drm_mode_config {
 */
struct drm_atomic_state *suspend_state;
 
+   /**
+* @power_saving_policy: bitmask for power saving policy requests.
+*/
+   struct drm_property *power_saving_policy;
+
const struct drm_mode_config_helper_funcs *helper_private;
 };
 
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 7040e7ea80c7..c2c86623552c 100644
--- a/include/uapi/d

Re: [PATCH v2] drm/amd/display: Add pixel encoding info to debugfs

2024-05-22 Thread Mario Limonciello

+ Simon

On 5/22/2024 05:07, Rino André Johnsen wrote:

To be perfectly honest with you, I haven't given that much though. I
used the 'bpc' and 'colorspace' property in debugfs, since I could not
find that information anywhere else. And since I also needed to verify
the pixel encoding being used, I added it where those other values
were. That made for a simple and easy addition for this property.

If you want me to do this differently, let me know. And please point
me to the standardized DRM property where I should expose the values.


Here's a pointer to where the colorspace property is created:

https://github.com/torvalds/linux/blob/v6.9/drivers/gpu/drm/drm_connector.c#L2147

I would expect you can make another property for the information you're 
looking for and then can get it from userspace using standard property

APIs.



Rino

On Tue, May 21, 2024 at 10:55 PM Mario Limonciello
 wrote:


On 5/21/2024 15:06, Rino André Johnsen wrote:

What is already there in debugfs is 'bpc' and 'colorspace', but not
the pixel encoding/format.
I have searched high and low for that to be able to verify that my
monitor and computer are using my preferred combination of all those
three values.

I do think it should be available as a standard DRM CRTC property, but
for the time being, I figured that a simple debugfs property would be
sufficient for time being.



It's just about as much work either way to populate it though, why do it
twice instead of just doing it right the first time?


Rino


On Tue, May 21, 2024 at 9:04 PM Christian König
 wrote:


Am 21.05.24 um 07:11 schrieb Rino Andre Johnsen:

[Why]
For debugging and testing purposes.

[How]
Create amdgpu_current_pixelencoding debugfs entry.
Usage: cat /sys/kernel/debug/dri/1/crtc-0/amdgpu_current_pixelencoding


Why isn't that available as standard DRM CRTC property in either sysfs
or debugfs?

I think the format specifiers should already be available somewhere there.

Regards,
Christian.



Signed-off-by: Rino Andre Johnsen 
---

Changes in v2:
1. Do not initialize dm_crtc_state to NULL.
---
.../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 47 +++
1 file changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 27d5c6077630..4254d4a4b56b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -1160,6 +1160,51 @@ static int amdgpu_current_colorspace_show(struct 
seq_file *m, void *data)
}
DEFINE_SHOW_ATTRIBUTE(amdgpu_current_colorspace);

+/*
+ * Returns the current pixelencoding for the crtc.
+ * Example usage: cat 
/sys/kernel/debug/dri/0/crtc-0/amdgpu_current_pixelencoding
+ */
+static int amdgpu_current_pixelencoding_show(struct seq_file *m, void *data)
+{
+ struct drm_crtc *crtc = m->private;
+ struct drm_device *dev = crtc->dev;
+ struct dm_crtc_state *dm_crtc_state;
+ int res = -ENODEV;
+
+ mutex_lock(>mode_config.mutex);
+ drm_modeset_lock(>mutex, NULL);
+ if (crtc->state == NULL)
+ goto unlock;
+
+ dm_crtc_state = to_dm_crtc_state(crtc->state);
+ if (dm_crtc_state->stream == NULL)
+ goto unlock;
+
+ switch (dm_crtc_state->stream->timing.pixel_encoding) {
+ case PIXEL_ENCODING_RGB:
+ seq_puts(m, "RGB");
+ break;
+ case PIXEL_ENCODING_YCBCR422:
+ seq_puts(m, "YCBCR422");
+ break;
+ case PIXEL_ENCODING_YCBCR444:
+ seq_puts(m, "YCBCR444");
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ seq_puts(m, "YCBCR420");
+ break;
+ default:
+ goto unlock;
+ }
+ res = 0;
+
+unlock:
+ drm_modeset_unlock(>mutex);
+ mutex_unlock(>mode_config.mutex);
+
+ return res;
+}
+DEFINE_SHOW_ATTRIBUTE(amdgpu_current_pixelencoding);

/*
 * Example usage:
@@ -3688,6 +3733,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc)
crtc, _current_bpc_fops);
debugfs_create_file("amdgpu_current_colorspace", 0644, 
crtc->debugfs_entry,
crtc, _current_colorspace_fops);
+ debugfs_create_file("amdgpu_current_pixelencoding", 0644, 
crtc->debugfs_entry,
+ crtc, _current_pixelencoding_fops);
}

/*








Re: [PATCH v2] drm/amd/display: Add pixel encoding info to debugfs

2024-05-21 Thread Mario Limonciello

On 5/21/2024 15:06, Rino André Johnsen wrote:

What is already there in debugfs is 'bpc' and 'colorspace', but not
the pixel encoding/format.
I have searched high and low for that to be able to verify that my
monitor and computer are using my preferred combination of all those
three values.

I do think it should be available as a standard DRM CRTC property, but
for the time being, I figured that a simple debugfs property would be
sufficient for time being.



It's just about as much work either way to populate it though, why do it 
twice instead of just doing it right the first time?



Rino


On Tue, May 21, 2024 at 9:04 PM Christian König
 wrote:


Am 21.05.24 um 07:11 schrieb Rino Andre Johnsen:

[Why]
For debugging and testing purposes.

[How]
Create amdgpu_current_pixelencoding debugfs entry.
Usage: cat /sys/kernel/debug/dri/1/crtc-0/amdgpu_current_pixelencoding


Why isn't that available as standard DRM CRTC property in either sysfs
or debugfs?

I think the format specifiers should already be available somewhere there.

Regards,
Christian.



Signed-off-by: Rino Andre Johnsen 
---

Changes in v2:
1. Do not initialize dm_crtc_state to NULL.
---
   .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 47 +++
   1 file changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 27d5c6077630..4254d4a4b56b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -1160,6 +1160,51 @@ static int amdgpu_current_colorspace_show(struct 
seq_file *m, void *data)
   }
   DEFINE_SHOW_ATTRIBUTE(amdgpu_current_colorspace);

+/*
+ * Returns the current pixelencoding for the crtc.
+ * Example usage: cat 
/sys/kernel/debug/dri/0/crtc-0/amdgpu_current_pixelencoding
+ */
+static int amdgpu_current_pixelencoding_show(struct seq_file *m, void *data)
+{
+ struct drm_crtc *crtc = m->private;
+ struct drm_device *dev = crtc->dev;
+ struct dm_crtc_state *dm_crtc_state;
+ int res = -ENODEV;
+
+ mutex_lock(>mode_config.mutex);
+ drm_modeset_lock(>mutex, NULL);
+ if (crtc->state == NULL)
+ goto unlock;
+
+ dm_crtc_state = to_dm_crtc_state(crtc->state);
+ if (dm_crtc_state->stream == NULL)
+ goto unlock;
+
+ switch (dm_crtc_state->stream->timing.pixel_encoding) {
+ case PIXEL_ENCODING_RGB:
+ seq_puts(m, "RGB");
+ break;
+ case PIXEL_ENCODING_YCBCR422:
+ seq_puts(m, "YCBCR422");
+ break;
+ case PIXEL_ENCODING_YCBCR444:
+ seq_puts(m, "YCBCR444");
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ seq_puts(m, "YCBCR420");
+ break;
+ default:
+ goto unlock;
+ }
+ res = 0;
+
+unlock:
+ drm_modeset_unlock(>mutex);
+ mutex_unlock(>mode_config.mutex);
+
+ return res;
+}
+DEFINE_SHOW_ATTRIBUTE(amdgpu_current_pixelencoding);

   /*
* Example usage:
@@ -3688,6 +3733,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc)
   crtc, _current_bpc_fops);
   debugfs_create_file("amdgpu_current_colorspace", 0644, 
crtc->debugfs_entry,
   crtc, _current_colorspace_fops);
+ debugfs_create_file("amdgpu_current_pixelencoding", 0644, 
crtc->debugfs_entry,
+ crtc, _current_pixelencoding_fops);
   }

   /*






Re: [PATCH 0/2] Add support for Panel Power Savings property

2024-05-21 Thread Mario Limonciello

On 5/21/2024 12:27, Leo Li wrote:



On 2024-05-21 12:21, Mario Limonciello wrote:

On 5/21/2024 11:14, Xaver Hugl wrote:

Am Di., 21. Mai 2024 um 16:00 Uhr schrieb Mario Limonciello
:


On 5/21/2024 08:43, Simon Ser wrote:
This makes sense to me in general. I like the fact that it's simple 
and

vendor-neutral.

Do we want to hardcode "panel" in the name? Are we sure that this will
ever only apply to panels?

Do we want to use a name which reflects the intent, rather than the
mechanism? In other words, something like "color fidelity" = 
"preferred"

maybe? (I don't know, just throwing ideas around.)


In that vein, how about:

"power saving policy"
--> "power saving"
--> "color fidelity"


It's not just about colors though, is it? The compositor might want to
disable it to increase the backlight brightness in bright
environments, so "color fidelity" doesn't really sound right


Either of these better?

"power saving policy"
--> "power saving"
--> "accuracy"

"power saving policy"
--> "allowed"
--> "forbidden"

Or any other idea?


Another consideration in addition to accuracy is latency.

I suppose a compositor may want to disable features such as PSR for 
use-cases requiring low latency. Touch and stylus input are some examples.


I wonder if flags would work better than enums? A compositor can set 
something like `REQUIRE_ACCURACY & REQUIRE_LOW_LATENCY`, for example.




I thought we had said the PSR latency issue discussed at the hackfest 
was likely just a bug and that nominally it won't matter?


If it really will matter enough then yeah I think you're right that 
flags would be better.  More drivers would probably want to opt into the 
property for the purpose of turning off PSR/PSR2/panel replay as well then.



- Leo







Would be nice to add documentation for the property in the "standard
connector properties" section.


Ack.







Re: [PATCH v1 0/3] Add support for ISP interrupts and disable prefetch

2024-05-21 Thread Mario Limonciello

On 5/21/2024 11:48, Pratap Nirujogi wrote:

Add support for ISP interrupts and disable MMHUB prefetch for ISP v4.1.1

Pratap Nirujogi (3):
   drm/amd/amdgpu: Map ISP interrupts as generic IRQs
   drm/amd/amdgpu: Add ISP4.1.0 and ISP4.1.1 modules
   drm/amd/amdgpu: Disable MMHUB prefetch for ISP v4.1.1

  drivers/gpu/drm/amd/amdgpu/Makefile   |   5 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c   |   3 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c   | 144 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h   |  13 +-
  drivers/gpu/drm/amd/amdgpu/ih_v6_1.c  |   6 +
  drivers/gpu/drm/amd/amdgpu/isp_v4_1_0.c   | 149 ++
  drivers/gpu/drm/amd/amdgpu/isp_v4_1_0.h   |  46 ++
  drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c   | 149 ++
  drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.h   |  46 ++
  .../amd/include/ivsrcid/isp/irqsrcs_isp_4_1.h |  62 
  11 files changed, 517 insertions(+), 110 deletions(-)
  create mode 100644 drivers/gpu/drm/amd/amdgpu/isp_v4_1_0.c
  create mode 100644 drivers/gpu/drm/amd/amdgpu/isp_v4_1_0.h
  create mode 100644 drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
  create mode 100644 drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.h
  create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/isp/irqsrcs_isp_4_1.h


Reviewed-by: Mario Limonciello 


Re: [PATCH 0/2] Add support for Panel Power Savings property

2024-05-21 Thread Mario Limonciello

On 5/21/2024 11:14, Xaver Hugl wrote:

Am Di., 21. Mai 2024 um 16:00 Uhr schrieb Mario Limonciello
:


On 5/21/2024 08:43, Simon Ser wrote:

This makes sense to me in general. I like the fact that it's simple and
vendor-neutral.

Do we want to hardcode "panel" in the name? Are we sure that this will
ever only apply to panels?

Do we want to use a name which reflects the intent, rather than the
mechanism? In other words, something like "color fidelity" = "preferred"
maybe? (I don't know, just throwing ideas around.)


In that vein, how about:

"power saving policy"
--> "power saving"
--> "color fidelity"


It's not just about colors though, is it? The compositor might want to
disable it to increase the backlight brightness in bright
environments, so "color fidelity" doesn't really sound right


Either of these better?

"power saving policy"
--> "power saving"
--> "accuracy"

"power saving policy"
--> "allowed"
--> "forbidden"

Or any other idea?





Would be nice to add documentation for the property in the "standard
connector properties" section.


Ack.





Re: [PATCH 0/2] Add support for Panel Power Savings property

2024-05-21 Thread Mario Limonciello

On 5/21/2024 08:43, Simon Ser wrote:

This makes sense to me in general. I like the fact that it's simple and
vendor-neutral.

Do we want to hardcode "panel" in the name? Are we sure that this will
ever only apply to panels?

Do we want to use a name which reflects the intent, rather than the
mechanism? In other words, something like "color fidelity" = "preferred"
maybe? (I don't know, just throwing ideas around.)


In that vein, how about:

"power saving policy"
--> "power saving"
--> "color fidelity"



Would be nice to add documentation for the property in the "standard
connector properties" section.


Ack.



Re: [PATCH] drm/amd/display: Add pixel encoding info to debugfs

2024-05-20 Thread Mario Limonciello

On 5/20/2024 16:07, Rino Andre Johnsen wrote:

[Why]
For debugging and testing purposes.

[How]
Create amdgpu_current_pixelencoding debugfs entry.
Usage: cat /sys/kernel/debug/dri/1/crtc-0/amdgpu_current_pixelencoding

Signed-off-by: Rino Andre Johnsen 
---
  .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 47 +++
  1 file changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 27d5c6077630..d275e5522335 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -1160,6 +1160,51 @@ static int amdgpu_current_colorspace_show(struct 
seq_file *m, void *data)
  }
  DEFINE_SHOW_ATTRIBUTE(amdgpu_current_colorspace);
  
+/*

+ * Returns the current pixelencoding for the crtc.
+ * Example usage: cat 
/sys/kernel/debug/dri/0/crtc-0/amdgpu_current_pixelencoding
+ */
+static int amdgpu_current_pixelencoding_show(struct seq_file *m, void *data)
+{
+   struct drm_crtc *crtc = m->private;
+   struct drm_device *dev = crtc->dev;
+   struct dm_crtc_state *dm_crtc_state = NULL;


There is no need to initialize dm_crtc_state to NULL.  You set it before 
its first use.



+   int res = -ENODEV;
+
+   mutex_lock(>mode_config.mutex);
+   drm_modeset_lock(>mutex, NULL);
+   if (crtc->state == NULL)
+   goto unlock;
+
+   dm_crtc_state = to_dm_crtc_state(crtc->state);
+   if (dm_crtc_state->stream == NULL)
+   goto unlock;
+
+   switch (dm_crtc_state->stream->timing.pixel_encoding) {
+   case PIXEL_ENCODING_RGB:
+   seq_puts(m, "RGB");
+   break;
+   case PIXEL_ENCODING_YCBCR422:
+   seq_puts(m, "YCBCR422");
+   break;
+   case PIXEL_ENCODING_YCBCR444:
+   seq_puts(m, "YCBCR444");
+   break;
+   case PIXEL_ENCODING_YCBCR420:
+   seq_puts(m, "YCBCR420");
+   break;
+   default:
+   goto unlock;
+   }
+   res = 0;
+
+unlock:
+   drm_modeset_unlock(>mutex);
+   mutex_unlock(>mode_config.mutex);
+
+   return res;
+}
+DEFINE_SHOW_ATTRIBUTE(amdgpu_current_pixelencoding);
  
  /*

   * Example usage:
@@ -3688,6 +3733,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc)
crtc, _current_bpc_fops);
debugfs_create_file("amdgpu_current_colorspace", 0644, 
crtc->debugfs_entry,
crtc, _current_colorspace_fops);
+   debugfs_create_file("amdgpu_current_pixelencoding", 0644, 
crtc->debugfs_entry,
+   crtc, _current_pixelencoding_fops);
  }
  
  /*




[PATCH 2/2] tests/amdgpu/amd_abm: Add support for panel_power_saving property

2024-05-19 Thread Mario Limonciello
From: Mario Limonciello 

When the "panel power saving" property is set to forbidden the
compositor has indicated that userspace prefers to have color
accuracy and fidelity instead of power saving.

Verify that the sysfs file behaves as expected in this situation.

Signed-off-by: Mario Limonciello 
---
 tests/amdgpu/amd_abm.c | 65 ++
 1 file changed, 65 insertions(+)

diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
index f74c3012c..971cda153 100644
--- a/tests/amdgpu/amd_abm.c
+++ b/tests/amdgpu/amd_abm.c
@@ -104,6 +104,32 @@ static int backlight_write_brightness(int value)
return 0;
 }
 
+static int toggle_panel_power_saving_prop(data_t *data, igt_output_t *output, 
bool forbid)
+{
+   uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
+   bool prop_exists;
+   uint32_t prop_id;
+
+   prop_exists = kmstest_get_property(
+   data->drm_fd, output->id, type, "panel power saving",
+   _id, NULL, NULL);
+
+   if (!prop_exists)
+   return -ENODEV;
+
+   return drmModeObjectSetProperty(data->drm_fd, output->id, type, 
prop_id, forbid);
+}
+
+static int allow_panel_power_saving(data_t *data, igt_output_t *output)
+{
+   return toggle_panel_power_saving_prop(data, output, false);
+}
+
+static int forbid_panel_power_saving(data_t *data, igt_output_t *output)
+{
+   return toggle_panel_power_saving_prop(data, output, true);
+}
+
 static int set_abm_level(data_t *data, igt_output_t *output, int level)
 {
char buf[PATH_MAX];
@@ -365,6 +391,43 @@ static void abm_gradual(data_t *data)
}
 }
 
+
+static void abm_forbidden(data_t *data)
+{
+   igt_output_t *output;
+   enum pipe pipe;
+   int target, r;
+
+   for_each_pipe_with_valid_output(>display, pipe, output) {
+   if (output->config.connector->connector_type != 
DRM_MODE_CONNECTOR_eDP)
+   continue;
+
+   r = allow_panel_power_saving(data, output);
+   if (r == -ENODEV) {
+   igt_skip("No panel power saving prop\n");
+   return;
+   }
+   igt_assert_eq(r, 0);
+
+   target = 3;
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, 0);
+
+   r = forbid_panel_power_saving(data, output);
+   igt_assert_eq(r, 0);
+
+   target = 0;
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, -1);
+
+   r = allow_panel_power_saving(data, output);
+   igt_assert_eq(r, 0);
+
+   r = set_abm_level(data, output, target);
+   igt_assert_eq(r, 0);
+   }
+}
+
 igt_main
 {
data_t data = {};
@@ -393,6 +456,8 @@ igt_main
abm_enabled();
igt_subtest("abm_gradual")
abm_gradual();
+   igt_subtest("abm_forbidden")
+   abm_forbidden();
 
igt_fixture {
igt_display_fini();
-- 
2.45.0



[PATCH 0/2] Add support for testing panel power saving DRM property

2024-05-19 Thread Mario Limonciello
During the Display Next hackfest 2024 one of the topics discussed
was the need for compositor to be able to relay intention to drivers
that color fidelity is preferred over power savings.

To accomplish this a new optional DRM property is being introduced called
"panel power saving".  This property is an enum that can be configured
by the compositor to "Allowed" or "Forbidden".

When a driver advertises support for this property and the compositor
sets it to "Forbidden" then the driver will disable any power saving
features that can compromise color fidelity.

This set of IGT changes introduces a new subtest that will cover the
expected kernel behavior when switching between Allowed and Forbidden.

Mario Limonciello (2):
  tests/amdgpu/amd_abm: Make set_abm_level return type int
  tests/amdgpu/amd_abm: Add support for panel_power_saving property

 tests/amdgpu/amd_abm.c | 98 +-
 1 file changed, 88 insertions(+), 10 deletions(-)

-- 
2.45.0



[PATCH 1/2] tests/amdgpu/amd_abm: Make set_abm_level return type int

2024-05-19 Thread Mario Limonciello
From: Mario Limonciello 

In order to bubble of cases of expeted errors on set_abm_level()
change the return type to int.

Signed-off-by: Mario Limonciello 
---
 tests/amdgpu/amd_abm.c | 33 +++--
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
index 2882c2c18..f74c3012c 100644
--- a/tests/amdgpu/amd_abm.c
+++ b/tests/amdgpu/amd_abm.c
@@ -104,10 +104,11 @@ static int backlight_write_brightness(int value)
return 0;
 }
 
-static void set_abm_level(data_t *data, igt_output_t *output, int level)
+static int set_abm_level(data_t *data, igt_output_t *output, int level)
 {
char buf[PATH_MAX];
int fd;
+   int ret;
 
igt_assert(snprintf(buf, PATH_MAX, PANEL_POWER_SAVINGS_PATH,
output->name) < PATH_MAX);
@@ -116,8 +117,12 @@ static void set_abm_level(data_t *data, igt_output_t 
*output, int level)
 
igt_assert(fd != -1);
 
-   igt_assert_eq(snprintf(buf, sizeof(buf), "%d", level),
- write(fd, buf, 1));
+   snprintf(buf, sizeof(buf), "%d", level);
+   ret = write(fd, buf, 1);
+   if (ret < 0) {
+   close(fd);
+   return ret;
+   }
 
igt_assert_eq(close(fd), 0);
 
@@ -129,6 +134,7 @@ static void set_abm_level(data_t *data, igt_output_t 
*output, int level)
 DRM_MODE_DPMS_OFF);
kmstest_set_connector_dpms(data->drm_fd, output->config.connector,
 DRM_MODE_DPMS_ON);
+   return 0;
 }
 
 static int backlight_read_max_brightness(int *result)
@@ -192,7 +198,8 @@ static void backlight_dpms_cycle(data_t *data)
ret = backlight_read_max_brightness(_brightness);
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness / 2);
usleep(10);
pwm_1 = read_target_backlight_pwm(data->drm_fd, output->name);
@@ -223,7 +230,8 @@ static void backlight_monotonic_basic(data_t *data)
 
brightness_step = max_brightness / 10;
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
@@ -257,7 +265,8 @@ static void backlight_monotonic_abm(data_t *data)
 
brightness_step = max_brightness / 10;
for (i = 1; i < 5; i++) {
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
@@ -289,14 +298,16 @@ static void abm_enabled(data_t *data)
ret = backlight_read_max_brightness(_brightness);
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
usleep(10);
prev_pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
pwm_without_abm = prev_pwm;
 
for (i = 1; i < 5; i++) {
-   set_abm_level(data, output, i);
+   ret = set_abm_level(data, output, i);
+   igt_assert_eq(ret, 0);
usleep(10);
pwm = read_target_backlight_pwm(data->drm_fd, 
output->name);
igt_assert(pwm <= prev_pwm);
@@ -323,7 +334,8 @@ static void abm_gradual(data_t *data)
 
igt_assert_eq(ret, 0);
 
-   set_abm_level(data, output, 0);
+   ret = set_abm_level(data, output, 0);
+   igt_assert_eq(ret, 0);
backlight_write_brightness(max_brightness);
 
sleep(convergence_delay);
@@ -331,7 +343,8 @@ static void abm_gradual(data_t *data)
curr = read_current_backlight_pwm(data->drm_fd, output->name);
 
igt_assert_eq(prev_pwm, curr);
-   set_abm_level(data, output, 4);
+   ret = set_abm_level(data, output, 4);
+   igt_assert_eq(ret, 0);
for (i = 0; i < 10; i++) {
usleep(10);
pwm = read_current_backlight_pwm(data->drm_fd, 
output->name);
-- 
2.45.0



[PATCH 1/2] drm: Introduce panel_power_saving drm property

2024-05-19 Thread Mario Limonciello
The `panel_power_saving` DRM property is an optional property that
can be added to a connector by a driver.

This property is for compositors to indicate intent of allowing
policy for the driver to use power saving features that may
compromise color fidelity.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/drm_connector.c | 36 +
 include/drm/drm_connector.h |  1 +
 include/drm/drm_mode_config.h   |  6 ++
 include/uapi/drm/drm_mode.h |  4 
 4 files changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4d2df7f64dc5..ccf672c55e0c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -961,6 +961,11 @@ static const struct drm_prop_enum_list 
drm_scaling_mode_enum_list[] = {
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
 };
 
+static const struct drm_prop_enum_list drm_panel_power_saving_enum_list[] = {
+   { DRM_MODE_PANEL_POWER_SAVING_ALLOWED, "Allowed" },
+   { DRM_MODE_PANEL_POWER_SAVING_FORBIDDEN, "Forbidden" },
+};
+
 static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
{ DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
{ DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
@@ -1963,6 +1968,37 @@ int drm_mode_create_scaling_mode_property(struct 
drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
+/**
+ * drm_mode_create_panel_power_saving_property - create panel power saving 
property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ *
+ * Atomic drivers should use drm_mode_create_panel_power_saving_property()
+ * instead to correctly assign _connector_state.panel_power_saving
+ * in the atomic state.
+ *
+ * Returns: %0
+ */
+int drm_mode_create_panel_power_saving_property(struct drm_device *dev)
+{
+   struct drm_property *panel_power_saving;
+
+   if (dev->mode_config.panel_power_saving)
+   return 0;
+
+   panel_power_saving =
+   drm_property_create_enum(dev, 0, "panel power saving",
+   drm_panel_power_saving_enum_list,
+   
ARRAY_SIZE(drm_panel_power_saving_enum_list));
+
+   dev->mode_config.panel_power_saving = panel_power_saving;
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_panel_power_saving_property);
+
 /**
  * DOC: Variable refresh properties
  *
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index fe88d7fc6b8f..4ea3f912c641 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2025,6 +2025,7 @@ int drm_mode_create_dp_colorspace_property(struct 
drm_connector *connector,
   u32 supported_colorspaces);
 int drm_mode_create_content_type_property(struct drm_device *dev);
 int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
+int drm_mode_create_panel_power_saving_property(struct drm_device *dev);
 
 int drm_connector_set_path_property(struct drm_connector *connector,
const char *path);
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 973119a9176b..099ad2d8c5c1 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -954,6 +954,12 @@ struct drm_mode_config {
 */
struct drm_atomic_state *suspend_state;
 
+   /**
+* @panel_power_saving: DRM ENUM property for type of
+* Panel Power Saving.
+*/
+   struct drm_property *panel_power_saving;
+
const struct drm_mode_config_helper_funcs *helper_private;
 };
 
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 7040e7ea80c7..82e565cc76fb 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -152,6 +152,10 @@ extern "C" {
 #define DRM_MODE_SCALE_CENTER  2 /* Centered, no scaling */
 #define DRM_MODE_SCALE_ASPECT  3 /* Full screen, preserve aspect */
 
+/* Panel power saving options */
+#define DRM_MODE_PANEL_POWER_SAVING_ALLOWED0 /* Panel power savings 
features allowed */
+#define DRM_MODE_PANEL_POWER_SAVING_FORBIDDEN  1 /* Panel power savings 
features not allowed */
+
 /* Dithering mode options */
 #define DRM_MODE_DITHERING_OFF 0
 #define DRM_MODE_DITHERING_ON  1
-- 
2.45.0



[PATCH 2/2] drm/amd: Add panel_power_saving drm property to eDP connectors

2024-05-19 Thread Mario Limonciello
When the `panel_power_saving` property is set to "Forbidden" ABM
should be disabled immediately and any requests by sysfs to update
will return an -EBUSY error.

When the property is restored to "Allowed" the previous value of
ABM will be restored.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  3 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 36 ---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  1 +
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 3ecc7ef95172..6e6531c93d81 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -1350,6 +1350,9 @@ int amdgpu_display_modeset_create_props(struct 
amdgpu_device *adev)
 "dither",
 amdgpu_dither_enum_list, sz);
 
+   if (adev->dc_enabled)
+   drm_mode_create_panel_power_saving_property(adev_to_drm(adev));
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 01b0a331e4a6..f6b80018b136 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6421,6 +6421,12 @@ int amdgpu_dm_connector_atomic_set_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
dm_new_state->underscan_enable = val;
ret = 0;
+   } else if (property == dev->mode_config.panel_power_saving) {
+   dm_new_state->abm_forbidden = val;
+   dm_new_state->abm_level = (val || !amdgpu_dm_abm_level) ?
+   ABM_LEVEL_IMMEDIATE_DISABLE :
+   amdgpu_dm_abm_level;
+   ret = 0;
}
 
return ret;
@@ -6463,6 +6469,9 @@ int amdgpu_dm_connector_atomic_get_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
*val = dm_state->underscan_enable;
ret = 0;
+   } else if (property == dev->mode_config.panel_power_saving) {
+   *val = dm_state->abm_forbidden;
+   ret = 0;
}
 
return ret;
@@ -6489,9 +6498,12 @@ static ssize_t panel_power_savings_show(struct device 
*device,
u8 val;
 
drm_modeset_lock(>mode_config.connection_mutex, NULL);
-   val = to_dm_connector_state(connector->state)->abm_level ==
-   ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
-   to_dm_connector_state(connector->state)->abm_level;
+   if (to_dm_connector_state(connector->state)->abm_forbidden)
+   val = 0;
+   else
+   val = to_dm_connector_state(connector->state)->abm_level ==
+   ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
+   to_dm_connector_state(connector->state)->abm_level;
drm_modeset_unlock(>mode_config.connection_mutex);
 
return sysfs_emit(buf, "%u\n", val);
@@ -6515,10 +6527,16 @@ static ssize_t panel_power_savings_store(struct device 
*device,
return -EINVAL;
 
drm_modeset_lock(>mode_config.connection_mutex, NULL);
-   to_dm_connector_state(connector->state)->abm_level = val ?:
-   ABM_LEVEL_IMMEDIATE_DISABLE;
+   if (to_dm_connector_state(connector->state)->abm_forbidden)
+   ret = -EBUSY;
+   else
+   to_dm_connector_state(connector->state)->abm_level = val ?:
+   ABM_LEVEL_IMMEDIATE_DISABLE;
drm_modeset_unlock(>mode_config.connection_mutex);
 
+   if (ret)
+   return ret;
+
drm_kms_helper_hotplug_event(dev);
 
return count;
@@ -7689,6 +7707,14 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_requested_bpc = 
aconnector->base.state->max_bpc;
 
+   if (connector_type == DRM_MODE_CONNECTOR_eDP &&
+   (dc_is_dmcu_initialized(adev->dm.dc) ||
+adev->dm.dc->ctx->dmub_srv) && amdgpu_dm_abm_level < 0) {
+   drm_object_attach_property(>base.base,
+   dm->ddev->mode_config.panel_power_saving,
+   DRM_MODE_PANEL_POWER_SAVING_ALLOWED);
+   }
+
if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
/* Content Type is currently only implemented for HDMI. */
drm_connector_attach_content_type_property(>base);
diff --git a/drivers/gpu/drm/amd/display/amdgp

[PATCH 0/2] Add support for Panel Power Savings property

2024-05-19 Thread Mario Limonciello
During the Display Next hackfest 2024 one of the topics discussed
was the need for compositor to be able to relay intention to drivers
that color fidelity is preferred over power savings.

To accomplish this a new optional DRM property is being introduced called
"panel power saving".  This property is an enum that can be configured
by the compositor to "Allowed" or "Forbidden".

When a driver advertises support for this property and the compositor
sets it to "Forbidden" then the driver will disable any power saving
features that can compromise color fidelity.

In practice the main feature this currently applies to is the
"Adaptive Backlight Modulation" feature within AMD DCN on eDP panels.

When the compositor has marked the property  "Forbidden" then this
feature will be disabled and any userspace that tries to turn it on
will get an -EBUSY return code.

When the compositor has restored the value back to "Allowed" then the
previous value that would have been programmed will be restored.

Mario Limonciello (2):
  drm: Introduce panel_power_saving drm property
  drm/amd: Add panel_power_saving drm property to eDP connectors

 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  3 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 34 ++---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  1 +
 drivers/gpu/drm/drm_connector.c   | 37 +++
 include/drm/drm_connector.h   |  1 +
 include/drm/drm_mode_config.h |  6 +++
 include/uapi/drm/drm_mode.h   |  4 ++
 7 files changed, 81 insertions(+), 5 deletions(-)

-- 
2.45.0



[PATCH] drm/amd/display: Pass errors from amdgpu_dm_init() up

2024-05-19 Thread Mario Limonciello
Errors in amdgpu_dm_init() are silently ignored and dm_hw_init()
will succeed. However often these are fatal errors and it would
be better to pass them up.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index d6e71aa808d8..01b0a331e4a6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2556,8 +2556,12 @@ static int amdgpu_dm_smu_write_watermarks_table(struct 
amdgpu_device *adev)
 static int dm_hw_init(void *handle)
 {
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+   int r;
+
/* Create DAL display manager */
-   amdgpu_dm_init(adev);
+   r = amdgpu_dm_init(adev);
+   if (r)
+   return r;
amdgpu_dm_hpd_init(adev);
 
return 0;
-- 
2.43.0



Re: [PATCH v3 2/3] drm/amd/amdgpu: Add ISP driver support

2024-05-09 Thread Mario Limonciello

On 5/9/2024 16:50, Pratap Nirujogi wrote:

Add the isp driver in amdgpu to support ISP device on the APUs that
supports ISP IP block. ISP hw block is used for camera front-end, pre
and post processing operations.

Signed-off-by: Pratap Nirujogi 

Reviewed-by: Mario Limonciello 

---
Changes made in v3:

   - Remove unwanted header files
   - Remove suprious lines, duplicate error prints
   - Fix multi-line comment style

  drivers/gpu/drm/amd/amdgpu/Makefile   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   |   4 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c   | 278 ++
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h   |  51 
  drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c |   5 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h |   1 +
  7 files changed, 345 insertions(+)
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h

diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile 
b/drivers/gpu/drm/amd/amdgpu/Makefile
index de7b76327f5b..12ba76025cb7 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -324,4 +324,7 @@ amdgpu-y += $(AMD_DISPLAY_FILES)
  
  endif
  
+# add isp block

+amdgpu-y += amdgpu_isp.o
+
  obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index eb60d28a3a13..6d7f9ef53269 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -112,6 +112,7 @@
  #include "amdgpu_xcp.h"
  #include "amdgpu_seq64.h"
  #include "amdgpu_reg_state.h"
+#include "amdgpu_isp.h"
  
  #define MAX_GPU_INSTANCE		64
  
@@ -1045,6 +1046,9 @@ struct amdgpu_device {

/* display related functionality */
struct amdgpu_display_manager dm;
  
+	/* isp */

+   struct amdgpu_isp   isp;
+
/* mes */
boolenable_mes;
boolenable_mes_kiq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
new file mode 100644
index ..25e88661ac60
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+
+#include 
+#include 
+
+#include "amdgpu.h"
+#include "amdgpu_isp.h"
+
+#define mmDAGB0_WRCLI5_V4_10x6811C
+#define mmDAGB0_WRCLI9_V4_10x6812C
+#define mmDAGB0_WRCLI10_V4_1   0x68130
+#define mmDAGB0_WRCLI14_V4_1   0x68140
+#define mmDAGB0_WRCLI19_V4_1   0x68154
+#define mmDAGB0_WRCLI20_V4_1   0x68158
+
+static int isp_sw_init(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   adev->isp.parent = adev->dev;
+
+   adev->isp.cgs_device = amdgpu_cgs_create_device(adev);
+   if (!adev->isp.cgs_device)
+   return -EINVAL;
+
+   return 0;
+}
+
+static int isp_sw_fini(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   if (adev->isp.cgs_device)
+   amdgpu_cgs_destroy_device(adev->isp.cgs_device);
+
+   return 0;
+}
+
+/**
+ * isp_hw_init - start and test isp block
+ *
+ * @handle: handle for amdgpu_device pointer
+ *
+ */
+static int isp_hw_init(void *handle)
+{
+   int r;
+   u64 isp_base;
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+   const struct amdgpu_ip_block *ip_block =
+   amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ISP);
+
+   if (!ip_block)
+   return -EINVAL;
+
+   if (adev->rmmio_size == 

Re: [PATCH v2 3/3] drm/amd/amdgpu: Enable ISP in amdgpu_discovery

2024-05-09 Thread Mario Limonciello

On 5/9/2024 14:35, Pratap Nirujogi wrote:

Enable ISP for ISP V4.1.0 and V4.1.1 in amdgpu_discovery.

Signed-off-by: Pratap Nirujogi 

Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 22 +++
  1 file changed, 22 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 6586feab8c2c..82d064adaa49 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -107,6 +107,7 @@
  #include "jpeg_v5_0_0.h"
  
  #include "amdgpu_vpe.h"

+#include "amdgpu_isp.h"
  
  #define FIRMWARE_IP_DISCOVERY "amdgpu/ip_discovery.bin"

  MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY);
@@ -682,6 +683,10 @@ static void 
amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
adev->sdma.sdma_mask &=
~(1U << harvest_info->list[i].number_instance);
break;
+   case ISP_HWID:
+   adev->isp.harvest_config |=
+   ~(1U << harvest_info->list[i].number_instance);
+   break;
default:
break;
}
@@ -2303,6 +2308,20 @@ static int 
amdgpu_discovery_set_umsch_mm_ip_blocks(struct amdgpu_device *adev)
return 0;
  }
  
+static int amdgpu_discovery_set_isp_ip_blocks(struct amdgpu_device *adev)

+{
+   switch (amdgpu_ip_version(adev, ISP_HWIP, 0)) {
+   case IP_VERSION(4, 1, 0):
+   case IP_VERSION(4, 1, 1):
+   amdgpu_device_ip_block_add(adev, _ip_block);
+   break;
+   default:
+   break;
+   }
+
+   return 0;
+}
+
  int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
  {
int r;
@@ -2829,6 +2848,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device 
*adev)
if (r)
return r;
  
+	r = amdgpu_discovery_set_isp_ip_blocks(adev);

+   if (r)
+   return r;
return 0;
  }
  




Re: [PATCH v2 1/3] drm/amd/amdgpu: Add ISP support to amdgpu_discovery

2024-05-09 Thread Mario Limonciello

On 5/9/2024 14:35, Pratap Nirujogi wrote:

ISP hw block is supported in some of the AMD GPU versions, add support
to discover ISP IP in amdgpu_discovery.

Signed-off-by: Pratap Nirujogi 

Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   | 1 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 1 +
  drivers/gpu/drm/amd/include/amd_shared.h  | 1 +
  3 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 8bb8b414d511..eb60d28a3a13 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -718,6 +718,7 @@ enum amd_hw_ip_block_type {
XGMI_HWIP,
DCI_HWIP,
PCIE_HWIP,
+   ISP_HWIP,
MAX_HWIP
  };
  
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c

index ece462f8a324..6586feab8c2c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -226,6 +226,7 @@ static int hw_id_map[MAX_HWIP] = {
[DCI_HWIP]  = DCI_HWID,
[PCIE_HWIP] = PCIE_HWID,
[VPE_HWIP]  = VPE_HWID,
+   [ISP_HWIP]  = ISP_HWID,
  };
  
  static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, uint8_t *binary)

diff --git a/drivers/gpu/drm/amd/include/amd_shared.h 
b/drivers/gpu/drm/amd/include/amd_shared.h
index 36ee9d3d6d9c..8bc2134cdd6b 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -105,6 +105,7 @@ enum amd_ip_block_type {
AMD_IP_BLOCK_TYPE_JPEG,
AMD_IP_BLOCK_TYPE_VPE,
AMD_IP_BLOCK_TYPE_UMSCH_MM,
+   AMD_IP_BLOCK_TYPE_ISP,
AMD_IP_BLOCK_TYPE_NUM,
  };
  




Re: [PATCH v2 2/3] drm/amd/amdgpu: Add ISP driver support

2024-05-09 Thread Mario Limonciello

On 5/9/2024 14:35, Pratap Nirujogi wrote:

Add the isp driver in amdgpu to support ISP device on the APUs that
supports ISP IP block. ISP hw block is used for camera front-end, pre
and post processing operations.

Signed-off-by: Pratap Nirujogi 
Change-Id: I67ef206e5eca1fe74e495c3262746be495e17d09


Ttypically we strip the Change-Id for things that were in Gerrit originally.


---
Changes in v2:
  - Remove adding IORESOURCE_IRQ
  - Remove noisy info prints
  - Avoid isp version numbers while naming
  - Fix incorrect argument description
  - Replace // with /* */ for comemnts

  drivers/gpu/drm/amd/amdgpu/Makefile   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   |   4 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c   | 287 ++
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h   |  54 
  drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c |   5 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h |   1 +
  7 files changed, 357 insertions(+)
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h

diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile 
b/drivers/gpu/drm/amd/amdgpu/Makefile
index de7b76327f5b..12ba76025cb7 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -324,4 +324,7 @@ amdgpu-y += $(AMD_DISPLAY_FILES)
  
  endif
  
+# add isp block

+amdgpu-y += amdgpu_isp.o
+
  obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index eb60d28a3a13..6d7f9ef53269 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -112,6 +112,7 @@
  #include "amdgpu_xcp.h"
  #include "amdgpu_seq64.h"
  #include "amdgpu_reg_state.h"
+#include "amdgpu_isp.h"
  
  #define MAX_GPU_INSTANCE		64
  
@@ -1045,6 +1046,9 @@ struct amdgpu_device {

/* display related functionality */
struct amdgpu_display_manager dm;
  
+	/* isp */

+   struct amdgpu_isp   isp;
+
/* mes */
boolenable_mes;
boolenable_mes_kiq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
new file mode 100644
index ..c28d90c25b10
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -0,0 +1,287 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 


This list of headers should be sorted alphabetically.


+
+#include "amdgpu_smu.h"
+#include "atom.h"
+#include "amdgpu_isp.h"
+#include "smu_internal.h"
+#include "smu_v11_5_ppsmc.h"
+#include "smu_v11_5_pmfw.h"
+
+#define mmDAGB0_WRCLI5_V4_10x6811C
+#define mmDAGB0_WRCLI9_V4_10x6812C
+#define mmDAGB0_WRCLI10_V4_1   0x68130
+#define mmDAGB0_WRCLI14_V4_1   0x68140
+#define mmDAGB0_WRCLI19_V4_1   0x68154
+#define mmDAGB0_WRCLI20_V4_1   0x68158
+
+static int isp_sw_init(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   adev->isp.parent = adev->dev;
+
+   adev->isp.cgs_device = amdgpu_cgs_create_device(adev);
+   if (!adev->isp.cgs_device)
+   return -EINVAL;
+
+   return 0;
+}
+
+static int isp_sw_fini(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   if (adev->isp.cgs_device)
+   amdgpu_cgs_destroy_device(adev->isp.cgs_device);
+
+   return 0;
+}
+
+/**
+ * isp_hw_init - start and test isp block
+ *
+ * @handle: handle for amdgpu_device pointer
+ *
+ */
+static int isp_hw_init(void *handle)
+{
+   int r;
+   u64 isp_base;
+   

Re: [PATCH] drm/mst: Fix NULL pointer dereference at drm_dp_add_payload_part2

2024-05-09 Thread Mario Limonciello

On 5/9/2024 07:43, Linux regression tracking (Thorsten Leemhuis) wrote:

On 18.04.24 21:43, Harry Wentland wrote:

On 2024-03-07 01:29, Wayne Lin wrote:

[Why]
Commit:
- commit 5aa1dfcdf0a4 ("drm/mst: Refactor the flow for payload 
allocation/removement")
accidently overwrite the commit
- commit 54d217406afe ("drm: use mgr->dev in drm_dbg_kms in 
drm_dp_add_payload_part2")
which cause regression.

[How]
Recover the original NULL fix and remove the unnecessary input parameter 
'state' for
drm_dp_add_payload_part2().

Fixes: 5aa1dfcdf0a4 ("drm/mst: Refactor the flow for payload 
allocation/removement")
Reported-by: Leon Weiß 
Link: 
https://lore.kernel.org/r/38c253ea42072cc825dc969ac4e6b9b600371cc8.ca...@ruhr-uni-bochum.de/
Cc: ly...@redhat.com
Cc: imre.d...@intel.com
Cc: sta...@vger.kernel.org
Cc: regressi...@lists.linux.dev
Signed-off-by: Wayne Lin 


I haven't been deep in MST code in a while but this all looks
pretty straightforward and good.

Reviewed-by: Harry Wentland 


Hmmm, that was three weeks ago, but it seems since then nothing happened
to fix the linked regression through this or some other patch. Is there
a reason? The build failure report from the CI maybe?


It touches files outside of amd but only has an ack from AMD.  I think 
we /probably/ want an ack from i915 and nouveau to take it through.




Wayne Lin, do you know what's up?

Ciao, Thorsten


---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 +-
  drivers/gpu/drm/display/drm_dp_mst_topology.c | 4 +---
  drivers/gpu/drm/i915/display/intel_dp_mst.c   | 2 +-
  drivers/gpu/drm/nouveau/dispnv50/disp.c   | 2 +-
  include/drm/display/drm_dp_mst_helper.h   | 1 -
  5 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index c27063305a13..2c36f3d00ca2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -363,7 +363,7 @@ void dm_helpers_dp_mst_send_payload_allocation(
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
new_payload = drm_atomic_get_mst_payload_state(mst_state, 
aconnector->mst_output_port);
  
-	ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload);

+   ret = drm_dp_add_payload_part2(mst_mgr, new_payload);
  
  	if (ret) {

amdgpu_dm_set_mst_status(>mst_status,
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c 
b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 03d528209426..95fd18f24e94 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -3421,7 +3421,6 @@ EXPORT_SYMBOL(drm_dp_remove_payload_part2);
  /**
   * drm_dp_add_payload_part2() - Execute payload update part 2
   * @mgr: Manager to use.
- * @state: The global atomic state
   * @payload: The payload to update
   *
   * If @payload was successfully assigned a starting time slot by 
drm_dp_add_payload_part1(), this
@@ -3430,14 +3429,13 @@ EXPORT_SYMBOL(drm_dp_remove_payload_part2);
   * Returns: 0 on success, negative error code on failure.
   */
  int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr,
-struct drm_atomic_state *state,
 struct drm_dp_mst_atomic_payload *payload)
  {
int ret = 0;
  
  	/* Skip failed payloads */

if (payload->payload_allocation_status != 
DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) {
-   drm_dbg_kms(state->dev, "Part 1 of payload creation for %s failed, 
skipping part 2\n",
+   drm_dbg_kms(mgr->dev, "Part 1 of payload creation for %s failed, 
skipping part 2\n",
payload->port->connector->name);
return -EIO;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c 
b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 53aec023ce92..2fba66aec038 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1160,7 +1160,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state 
*state,
if (first_mst_stream)
intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
  
-	drm_dp_add_payload_part2(_dp->mst_mgr, >base,

+   drm_dp_add_payload_part2(_dp->mst_mgr,
 drm_atomic_get_mst_payload_state(mst_state, 
connector->port));
  
  	if (DISPLAY_VER(dev_priv) >= 12)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 0c3d88ad0b0e..88728a0b2c25 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -915,7 +915,7 @@ nv50_msto_cleanup(struct drm_atomic_state *state,
msto->disabled = false;
drm_dp_remove_payload_part2(mgr, new_mst_state, 

[PATCH] drm/amd/display: Don't register panel_power_savings on OLED panels

2024-05-09 Thread Mario Limonciello
OLED panels don't support the ABM, they shouldn't offer the
panel_power_savings attribute to the user. Check whether aux BL
control support was enabled to decide whether to offer it.

Reported-by: Gergo Koteles 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3359
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 29 ---
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 3054bf79fc99..ce2ec857b8a6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6532,12 +6532,34 @@ static const struct attribute_group amdgpu_group = {
.attrs = amdgpu_attrs
 };
 
+static bool
+amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector)
+{
+   if (amdgpu_dm_abm_level >= 0)
+   return false;
+
+   if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
+   return false;
+
+   /* check for OLED panels */
+   if (amdgpu_dm_connector->bl_idx >= 0) {
+   struct drm_device *drm = amdgpu_dm_connector->base.dev;
+   struct amdgpu_display_manager *dm = _to_adev(drm)->dm;
+   struct amdgpu_dm_backlight_caps *caps;
+
+   caps = >backlight_caps[amdgpu_dm_connector->bl_idx];
+   if (caps->aux_support)
+   return false;
+   }
+
+   return true;
+}
+
 static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
 {
struct amdgpu_dm_connector *amdgpu_dm_connector = 
to_amdgpu_dm_connector(connector);
 
-   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
-   amdgpu_dm_abm_level < 0)
+   if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector))
sysfs_remove_group(>kdev->kobj, _group);
 
drm_dp_aux_unregister(_dm_connector->dm_dp_aux.aux);
@@ -6644,8 +,7 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
to_amdgpu_dm_connector(connector);
int r;
 
-   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
-   amdgpu_dm_abm_level < 0) {
+   if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) {
r = sysfs_create_group(>kdev->kobj,
   _group);
if (r)
-- 
2.43.0



Re: [PATCH 2/3] drm/amd/amdgpu: Add ISP driver support

2024-05-09 Thread Mario Limonciello

On 5/8/2024 09:50, Pratap Nirujogi wrote:

Add the isp driver in amdgpu to support ISP device on the APUs that
supports ISP IP block. ISP hw block is used for camera front-end, pre
and post processing operations.

Signed-off-by: Pratap Nirujogi 
---
  drivers/gpu/drm/amd/amdgpu/Makefile   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   |   4 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c   | 298 ++
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h   |  54 
  drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c   |   3 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c |   5 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h |   1 +
  7 files changed, 368 insertions(+)
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h

diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile 
b/drivers/gpu/drm/amd/amdgpu/Makefile
index de7b76327f5b..12ba76025cb7 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -324,4 +324,7 @@ amdgpu-y += $(AMD_DISPLAY_FILES)
  
  endif
  
+# add isp block

+amdgpu-y += amdgpu_isp.o
+
  obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index eb60d28a3a13..6d7f9ef53269 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -112,6 +112,7 @@
  #include "amdgpu_xcp.h"
  #include "amdgpu_seq64.h"
  #include "amdgpu_reg_state.h"
+#include "amdgpu_isp.h"
  
  #define MAX_GPU_INSTANCE		64
  
@@ -1045,6 +1046,9 @@ struct amdgpu_device {

/* display related functionality */
struct amdgpu_display_manager dm;
  
+	/* isp */

+   struct amdgpu_isp   isp;
+
/* mes */
boolenable_mes;
boolenable_mes_kiq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
new file mode 100644
index ..dcc01a339a43
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "amdgpu_smu.h"
+#include "atom.h"
+#include "amdgpu_isp.h"
+#include "smu_internal.h"
+#include "smu_v11_5_ppsmc.h"
+#include "smu_v11_5_pmfw.h"
+
+#define mmDAGB0_WRCLI5_V4_10x6811C
+#define mmDAGB0_WRCLI9_V4_10x6812C
+#define mmDAGB0_WRCLI10_V4_1   0x68130
+#define mmDAGB0_WRCLI14_V4_1   0x68140
+#define mmDAGB0_WRCLI19_V4_1   0x68154
+#define mmDAGB0_WRCLI20_V4_1   0x68158
+
+static int isp_sw_init(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   pr_info("%s called adev %p\n", __func__, adev);


This and other pr_info() statements are too noisy.  I guess they were 
bringup code that should be torn out now.



+
+   adev->isp.parent = adev->dev;
+
+   adev->isp.cgs_device = amdgpu_cgs_create_device(adev);
+   if (!adev->isp.cgs_device)
+   return -EINVAL;
+
+   return 0;
+}
+
+static int isp_sw_fini(void *handle)
+{
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   pr_info("%s called adev %p\n", __func__, adev);
+
+   if (adev->isp.cgs_device)
+   amdgpu_cgs_destroy_device(adev->isp.cgs_device);
+
+   return 0;
+}
+
+/**
+ * isp_hw_init - start and test isp block
+ *
+ * @adev: amdgpu_device pointer


Wrong argument for the function.


+ *
+ */
+static int isp_hw_init(void *handle)
+{
+   int r;
+   u64 isp_base;
+   struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+   const struct amdgpu_ip_block *ip_block =
+   

[PATCH] drm/amd/display: Drop pixel_clock_mhz

2024-05-08 Thread Mario Limonciello
The pixel_clock_mhz property is populated in amdgpu_dm when Freesync is setup,
but it is not used anywhere in amdgpu_dm. Remove the dead code.

Cc: chiahsuan.ch...@amd.com
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 -
 2 files changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index f80213b7e9f7..3054bf79fc99 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11274,7 +11274,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   amdgpu_dm_connector->pixel_clock_mhz = 0;
connector->display_info.monitor_range.min_vfreq = 0;
connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
@@ -11338,8 +11337,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,

connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq =

connector->display_info.monitor_range.max_vfreq;
-   amdgpu_dm_connector->pixel_clock_mhz =
-   range->pixel_clock_mhz * 10;
 
break;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 09519b7abf67..67647bb5999b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -678,7 +678,6 @@ struct amdgpu_dm_connector {
 * value is set to zero when there is no FreeSync support.
 */
int max_vfreq ;
-   int pixel_clock_mhz;
 
/* Audio instance - protected by audio_lock. */
int audio_inst;
-- 
2.43.0



[PATCH v2] drm/amd/display: Enable colorspace property for MST connectors

2024-05-08 Thread Mario Limonciello
MST colorspace property support was disabled due to a series of warnings
that came up when the device was plugged in since the properties weren't
made at device creation. Create the properties in advance instead.

Suggested-by: Ville Syrjälä 
Fixes: 69a959610229 ("drm/amd/display: Temporary Disable MST DP Colorspace 
Property").
Reported-and-tested-by: Tyler Schneider 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3353
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 941e96f100f4..12b036d511d0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -613,6 +613,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
>base,
dev->mode_config.tile_property,
0);
+   connector->colorspace_property = master->base.colorspace_property;
+   if (connector->colorspace_property)
+   drm_connector_attach_colorspace_property(connector);
 
drm_connector_set_path_property(connector, pathprop);
 
-- 
2.43.0



[PATCH 2/2] Revert "drm/amd/display: Temporary Disable MST DP Colorspace Property"

2024-05-08 Thread Mario Limonciello
MST colorspace property support was disabled due to a series of warnings
that came up when the device was plugged in.  As those warnings are fixed,
revert commit 69a959610229 ("drm/amd/display: Temporary Disable MST DP
Colorspace Property").

Reported-and-tested-by: Tyler Schneider 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3353
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 3054bf79fc99..93e2030f4c17 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7695,7 +7695,7 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
if 
(!drm_mode_create_hdmi_colorspace_property(>base, 
supported_colorspaces))

drm_connector_attach_colorspace_property(>base);
-   } else if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && 
!aconnector->mst_root) ||
+   } else if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
   connector_type == DRM_MODE_CONNECTOR_eDP) {
if (!drm_mode_create_dp_colorspace_property(>base, 
supported_colorspaces))

drm_connector_attach_colorspace_property(>base);
-- 
2.43.0



[PATCH 1/2] drm: Allow mode object properties to be added after a device is registered

2024-05-08 Thread Mario Limonciello
When the colorspace property is registered on MST devices there is
no `obj_free_cb` callback for it in drm_mode_object_add().

Don't show a warning trace for __drm_mode_object_add() calls for
DRM_MODE_OBJECT_PROPERTY.

Reported-and-tested-by: Tyler Schneider 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3353
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/drm_mode_object.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_mode_object.c 
b/drivers/gpu/drm/drm_mode_object.c
index 0e8355063eee..b077547a2db4 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -42,7 +42,7 @@ int __drm_mode_object_add(struct drm_device *dev, struct 
drm_mode_object *obj,
 {
int ret;
 
-   WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
+   WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb && 
obj_type != DRM_MODE_OBJECT_PROPERTY);
 
mutex_lock(>mode_config.idr_mutex);
ret = idr_alloc(>mode_config.object_idr, register_obj ? obj : NULL,
-- 
2.43.0



Re: Allow setting a power cap that's lower than recommended

2024-05-03 Thread Mario Limonciello

On 5/3/2024 07:05, fililip wrote:

This patch allows setting a low power cap if |ignore_min_pcap|​ is set to 1.

Signed-off-by: fililip 


Rather than an attachment you should send the patch inline.  That would 
mean that your commit message and SoB should be at the top of the patch 
itself.


If you're not aware of it, you should read through:

https://www.kernel.org/doc/html/latest/process/submitting-patches.html

Basically a maintainer should be able to run:

'b4 shazam $URL'

And it would download the patch and apply it.

That being said my comments on the patch content:

As Alex mentioned a concern about the the maintenance of more 
parameters, maybe it's worth making the sysfs file of the limit 
"writable" instead.


Then when it's written the kernel driver can add_taint() for 
TAINT_FIRMWARE_WORKAROUND when in use so we can see it clearly in logs.






[PATCH] dm/amd/pm: Fix problems with reboot/shutdown for some SMU 13.0.4/13.0.11 users

2024-05-02 Thread Mario Limonciello
Limit the workaround introduced by commit 31729e8c21ec ("drm/amd/pm: fixes
a random hang in S4 for SMU v13.0.4/11") to only run in the s4 path.

Cc: Tim Huang 
Fixes: 31729e8c21ec ("drm/amd/pm: fixes a random hang in S4 for SMU v13.0.4/11")
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3351
Signed-off-by: Mario Limonciello 
---
I tested this on SMU 13.0.4 for ~85 cycles with this script, BIOS 1.1.0.2a and
didn't observe any hangs.

```
#!/bin/sh
echo test_resume > /sys/power/disk
i=1
while [ : ]; do

  echo "Starting cycle $i"
  echo disk > /sys/power/state
  echo "Ending cycle $i"
  i=$((i+1))
  sleep 5
done
```

 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c 
b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index 949131bd1ecb..4abfcd32747d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -226,7 +226,7 @@ static int smu_v13_0_4_system_features_control(struct 
smu_context *smu, bool en)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
 
-   if (!en && !adev->in_s0ix) {
+   if (!en && adev->in_s4) {
/* Adds a GFX reset as workaround just before sending the
 * MP1_UNLOAD message to prevent GC/RLC/PMFW from entering
 * an invalid state.
-- 
2.43.0



[PATCH] drm/amd/display: Disable panel replay by default for now

2024-04-30 Thread Mario Limonciello
Panel replay was enabled by default in commit 5950efe25ee0
("drm/amd/display: Enable Panel Replay for static screen use case"), but
it isn't working properly at least on some BOE and AUO panels.  Instead
of being static the screen is solid black when active.  As it's a new
feature that was just introduced that regressed VRR disable it for now
so that problem can be properly root caused.

Cc: Tom Chung 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3344
Fixes: 5950efe25ee0 ("drm/amd/display: Enable Panel Replay for static screen 
use case")
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 21 +++
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 8245cc63712f..b5e5cbbe5e49 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4581,15 +4581,18 @@ static int amdgpu_dm_initialize_drm_device(struct 
amdgpu_device *adev)
/* Determine whether to enable Replay support by default. */
if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) {
switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
-   case IP_VERSION(3, 1, 4):
-   case IP_VERSION(3, 1, 5):
-   case IP_VERSION(3, 1, 6):
-   case IP_VERSION(3, 2, 0):
-   case IP_VERSION(3, 2, 1):
-   case IP_VERSION(3, 5, 0):
-   case IP_VERSION(3, 5, 1):
-   replay_feature_enabled = true;
-   break;
+/*
+ * Disabled by default due to 
https://gitlab.freedesktop.org/drm/amd/-/issues/3344
+ * case IP_VERSION(3, 1, 4):
+ * case IP_VERSION(3, 1, 5):
+ * case IP_VERSION(3, 1, 6):
+ * case IP_VERSION(3, 2, 0):
+ * case IP_VERSION(3, 2, 1):
+ * case IP_VERSION(3, 5, 0):
+ * case IP_VERSION(3, 5, 1):
+ * replay_feature_enabled = true;
+ * break;
+ */
default:
replay_feature_enabled = amdgpu_dc_feature_mask & 
DC_REPLAY_MASK;
break;
-- 
2.34.1



Re: [PATCH] Revert "drm/amd/pm: fixes a random hang in S4 for SMU v13.0.4/11"

2024-04-29 Thread Mario Limonciello

On 4/29/2024 08:38, Alex Deucher wrote:

This reverts commit 31729e8c21ecfd671458e02b6511eb68c2225113.

This causes problems with reboots/shutdowns for some users.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3351
Signed-off-by: Alex Deucher 
Cc: Tim Huang 


It would be unfortunate to drop as it did fix S4 for a number of users 
too.  Rather than dropping could the check be made for adev->in_s4?


In any case; whichever solution happens should also CC stable because 
the problematic commit did go to stable eventually.



---
  drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 12 +---
  1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c 
b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index 88f1a0d878f33..e8119918ef6b1 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -226,18 +226,8 @@ static int smu_v13_0_4_system_features_control(struct 
smu_context *smu, bool en)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
  
-	if (!en && !adev->in_s0ix) {

-   /* Adds a GFX reset as workaround just before sending the
-* MP1_UNLOAD message to prevent GC/RLC/PMFW from entering
-* an invalid state.
-*/
-   ret = smu_cmn_send_smc_msg_with_param(smu, 
SMU_MSG_GfxDeviceDriverReset,
- SMU_RESET_MODE_2, NULL);
-   if (ret)
-   return ret;
-
+   if (!en && !adev->in_s0ix)
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, 
NULL);
-   }
  
  	return ret;

  }




Re: [PATCH] drm/amd: Only allow one entity to control ABM

2024-04-26 Thread Mario Limonciello

On 4/13/2024 03:51, Gergo Koteles wrote:

Hi>


ABM will reduce the backlight and compensate by adjusting brightness and 
contrast of the image. It has 5 levels: 0, 1, 2, 3, 4. 0 means off. 4 means 
maximum backlight reduction. IMO, 1 and 2 look okay. 3 and 4 can be quite 
impactful, both to power and visual fidelity.


I tried this with 6.9 and it looks weird with an OLED panel used with
dark UI settings.
The dark is no longer dark, everything is brighter.
I turned this feature off with amdgpu.abmlevel=0.

Best regards,
Gergo



Would you mind filing a bug with the details please?  This was something 
that was actually explicitly checked against an OLED panel.  ABM 
shouldn't be applying to OLED today so this very likely points at a bug 
somewhere in the stack.


[PATCH] drm/amd: Flush GFXOFF requests in prepare stage

2024-03-21 Thread Mario Limonciello
From: Mario Limonciello 

If the system hasn't entered GFXOFF when suspend starts it can cause
hangs accessing GC and RLC during the suspend stage.

Cc:  # 6.1.y: 5095d5418193 ("drm/amd: Evict resources 
during PM ops prepare() callback")
Cc:  # 6.1.y: cb11ca3233aa ("drm/amd: Add concept of 
running prepare_suspend() sequence for IP blocks")
Cc:  # 6.1.y: 2ceec37b0e3d ("drm/amd: Add missing 
kernel doc for prepare_suspend()")
Cc:  # 6.1.y: 3a9626c816db ("drm/amd: Stop evicting 
resources on APUs in suspend")
Cc:  # 6.6.y: 5095d5418193 ("drm/amd: Evict resources 
during PM ops prepare() callback")
Cc:  # 6.6.y: cb11ca3233aa ("drm/amd: Add concept of 
running prepare_suspend() sequence for IP blocks")
Cc:  # 6.6.y: 2ceec37b0e3d ("drm/amd: Add missing 
kernel doc for prepare_suspend()")
Cc:  # 6.6.y: 3a9626c816db ("drm/amd: Stop evicting 
resources on APUs in suspend")
Cc:  # 6.1+
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3132
Fixes: ab4750332dbe ("drm/amdgpu/sdma5.2: add begin/end_use ring callbacks")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 94bdb5fa6ebc..1fbaf7b81d69 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4524,6 +4524,8 @@ int amdgpu_device_prepare(struct drm_device *dev)
if (r)
goto unprepare;
 
+   flush_delayed_work(>gfx.gfx_off_delay_work);
+
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
-- 
2.34.1



[PATCH v2] drm/amd/display: Use freesync when `DRM_EDID_FEATURE_CONTINUOUS_FREQ` found

2024-03-08 Thread Mario Limonciello
The monitor shipped with the Framework 16 supports VRR [1], but it's not
being advertised.

This is because the detailed timing block doesn't contain
`EDID_DETAIL_MONITOR_RANGE` which amdgpu looks for to find min and max
frequencies.  This check however is superfluous for this case because
update_display_info() calls drm_get_monitor_range() to get these ranges
already.

So if the `DRM_EDID_FEATURE_CONTINUOUS_FREQ` EDID feature is found then
turn on freesync without extra checks.

Closes: 
https://www.reddit.com/r/framework/comments/1b4y2i5/no_variable_refresh_rate_on_the_framework_16_on/
Closes: 
https://www.reddit.com/r/framework/comments/1b6vzcy/framework_16_variable_refresh_rate/
Closes: 
https://community.frame.work/t/resolved-no-vrr-freesync-with-amd-version/42338
Link: https://gist.github.com/superm1/e8fbacfa4d0f53150231d3a3e0a13faf
Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Use is_dp_capable_without_timing_msa() as well for new case
 * Move edid checks up a level
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 5b7293da5453..4e1633a18f2c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11233,18 +11233,21 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
if (!adev->dm.freesync_module)
goto update;
 
-   if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT
-   || sink->sink_signal == SIGNAL_TYPE_EDP) {
+   if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
+sink->sink_signal == SIGNAL_TYPE_EDP)) {
bool edid_check_required = false;
 
-   if (edid) {
-   edid_check_required = is_dp_capable_without_timing_msa(
-   adev->dm.dc,
-   amdgpu_dm_connector);
+   if (is_dp_capable_without_timing_msa(adev->dm.dc,
+amdgpu_dm_connector)) {
+   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
+   freesync_capable = true;
+   else
+   edid_check_required = edid->version > 1 ||
+ (edid->version == 1 &&
+  edid->revision > 1);
}
 
-   if (edid_check_required == true && (edid->version > 1 ||
-  (edid->version == 1 && edid->revision > 1))) {
+   if (edid_check_required) {
for (i = 0; i < 4; i++) {
 
timing  = >detailed_timings[i];
-- 
2.34.1



Re: [PATCH] drm/amd: Drop abm_level property

2024-03-06 Thread Mario Limonciello

On 3/6/2024 12:59, Harry Wentland wrote:



On 2024-03-06 13:02, Mario Limonciello wrote:

On 3/6/2024 12:00, Xaver Hugl wrote:

Am Mi., 6. März 2024 um 18:19 Uhr schrieb Mario Limonciello
:

So the idea being if the compositor isn't using it we let
power-profiles-daemon (or any other software) take control via sysfs and
if the compositor does want to control it then it then it writes a DRM
cap and we destroy the sysfs file?


Yes. That way still only one party controls it at a given time, and we
can get both good default behavior for display servers that don't care
(like Xorg or compositors without color management support), and
compositors that want to put in the effort can do more specific things
with it.


I think that's a very good solution.

Harry, Hamza, what do you guys think?


In theory I like it. But how will this look in practice? Is PPD or compositor
on the scene first? Would it be possible to yank the sysfs away from PPD?



I double checked the existing PPD code to see how well this case maps out.

* If the compositor shows up first then PPD just wouldn't find amdgpu 
support when it probed.
* If PPD goes first and then the compositor I expect right now that PPD 
wouldn't explode.  All the cases that would update it check that the 
file exists before trying to write it.


I think the only risk is TOCTOU for that check relative to when it would 
write the file, but the worst case is you have an error in the journal 
log that it tried to write the file but it's not present (there is 
already error handling everywhere for this).


What we can do to smooth it out even more is export a CHANGE uevent from 
amdgpu when this happens.  PPD can react to the change event and totally 
stop the amdgpu plugin.



DRM client caps are set by the client when the client interacts with DRM.
At driver creation there is no client. How will the driver set things up?



You jog my mind for another idea.

1) We could reintroduce abm_level property.
2) If client connects with the cap set, we make any reads or writes to 
the sysfs return -EBUSY and we make amdgpu issue a CHANGE uevent.


* Unchanged PPD will likely log a message to the journal that writes 
fail, but won't explode.
* A changed PPD could react to the uevent and look for -EBUSY to not 
bother even logging a message to the journal.



A user might switch between DRM clients (login manager, to desktop compositor,
maybe to another VT with a different compositor). I know everything but the
login manager to desktop compositor hand-off is today considered exotic, but
what if someone starts building a use-case for it? I've done a bunch of 
gamescope
or IGT work in a different VT while I've had Plasma running on its default
VT.



If going off the cap of the client to decide whether or not to report 
-EBUSY to sysfs I think it handles the handoff cleanly.



If someone can sketch this out, with answers to all the questions above and
any other questions you can come up (be creative), I'd be happy to review.
Alternatively we can discuss this at the hackfest and maybe arrive at a
solution.


Yes; I think we should use this thread as a basis for that discussion.



Re: [PATCH] drm/amd: Drop abm_level property

2024-03-06 Thread Mario Limonciello

On 3/6/2024 12:00, Xaver Hugl wrote:

Am Mi., 6. März 2024 um 18:19 Uhr schrieb Mario Limonciello
:

So the idea being if the compositor isn't using it we let
power-profiles-daemon (or any other software) take control via sysfs and
if the compositor does want to control it then it then it writes a DRM
cap and we destroy the sysfs file?


Yes. That way still only one party controls it at a given time, and we
can get both good default behavior for display servers that don't care
(like Xorg or compositors without color management support), and
compositors that want to put in the effort can do more specific things
with it.


I think that's a very good solution.

Harry, Hamza, what do you guys think?


Re: [PATCH] drm/amd: Drop abm_level property

2024-03-06 Thread Mario Limonciello

On 3/6/2024 11:08, Xaver Hugl wrote:

Like already mentioned in the power profiles daemon repository, I don't think
this makes sense. This is a display setting, which compositors have interest
in controlling, for example to:
- disable it in a bright environment, because afaiu it reduces the maximum
screen brightness
- disable it when it shows color critical content
- disable it while profiling the display
- enable it when it shows content that's definitely not color critical (based
on the content-type property of Wayland surfaces)
- enable it as a first step before properly dimming the screen on idle



This specific topic is on the agenda to discuss at 2024 Display Next 
Hackfest.



If the primary concern here is that this hasn't been used by compositors and
potential power savings aren't being realized, that could be solved by
providing documentation about what the feature does in the kernel, and by
sending a mail to wayland-devel describing why it should be used.

If the goal is to implement it in power profiles daemon and not get conflicts, I
think disabling the property by default and instead enable it + disable the
sysfs file when a CAP for it is set would make more sense than making the
listed features impossible.




So the idea being if the compositor isn't using it we let 
power-profiles-daemon (or any other software) take control via sysfs and 
if the compositor does want to control it then it then it writes a DRM 
cap and we destroy the sysfs file?




[PATCH] drm/amd/display: Use freesync when `DRM_EDID_FEATURE_CONTINUOUS_FREQ` found

2024-03-05 Thread Mario Limonciello
The monitor shipped with the Framework 16 supports VRR [1], but it's not
being advertised.

This is because the detailed timing block doesn't contain
`EDID_DETAIL_MONITOR_RANGE` which amdgpu looks for to find min and max
frequencies.  This check however is superfluous for this case because
update_display_info() calls drm_get_monitor_range() to get these ranges
already.

So if the `DRM_EDID_FEATURE_CONTINUOUS_FREQ` EDID feature is found then
turn on freesync without extra checks.

Closes: 
https://www.reddit.com/r/framework/comments/1b4y2i5/no_variable_refresh_rate_on_the_framework_16_on/
Closes: 
https://www.reddit.com/r/framework/comments/1b6vzcy/framework_16_variable_refresh_rate/
Closes: 
https://community.frame.work/t/resolved-no-vrr-freesync-with-amd-version/42338
Link: https://gist.github.com/superm1/e8fbacfa4d0f53150231d3a3e0a13faf [1]
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 5b7293da5453..38186d669a85 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11238,9 +11238,12 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
bool edid_check_required = false;
 
if (edid) {
-   edid_check_required = is_dp_capable_without_timing_msa(
-   adev->dm.dc,
-   amdgpu_dm_connector);
+   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
+   freesync_capable = true;
+   else
+   edid_check_required = 
is_dp_capable_without_timing_msa(
+   adev->dm.dc,
+   amdgpu_dm_connector);
}
 
if (edid_check_required == true && (edid->version > 1 ||
-- 
2.34.1



Re: [PATCH 25/34] drm/amd/display: Set the power_down_on_boot function pointer to null

2024-02-28 Thread Mario Limonciello

On 2/28/2024 12:39, Alex Hung wrote:

From: Muhammad Ahmed 

[WHY]
Blackscreen hang @ PC EF25 when trying to wake up from S0i3. DCN
gets powered off due to dc_power_down_on_boot() being called after
timeout.

[HOW]
Setting the power_down_on_boot function pointer to null since we don't
expect the function to be called for APU.


Perhaps, should we be making the same change for other APUs?

It seems a few others call dcn10_power_down_on_boot() for the callback.



Cc: Mario Limonciello 
Cc: Alex Deucher 
Cc: sta...@vger.kernel.org
Reviewed-by: Nicholas Kazlauskas 
Acked-by: Alex Hung 
Signed-off-by: Muhammad Ahmed 
---
  drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index dce620d359a6..d4e0abbef28e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -39,7 +39,7 @@
  static const struct hw_sequencer_funcs dcn35_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn35_init_hw,
-   .power_down_on_boot = dcn35_power_down_on_boot,
+   .power_down_on_boot = NULL,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,




Re: [PATCH] drm/amdgpu: Fix the runtime resume failure issue

2024-02-21 Thread Mario Limonciello

On 2/21/2024 03:35, Ma Jun wrote:

Don't set power state flag when system enter runtime suspend,
or it may cause runtime resume failure issue.

Signed-off-by: Ma Jun 


Reviewed-by: Mario Limonciello 

Please add a fixes tag for 3a9626c816db901def438dc2513622e281186d39 when 
committing.



---
  drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index f754e50e7b43..4f1a4435cee4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1531,6 +1531,9 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device 
*adev)
   */
  void amdgpu_choose_low_power_state(struct amdgpu_device *adev)
  {
+   if (adev->in_runpm)
+   return;
+
if (amdgpu_acpi_is_s0ix_active(adev))
adev->in_s0ix = true;
else if (amdgpu_acpi_is_s3_active(adev))




Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-16 Thread Mario Limonciello

On 2/16/2024 10:13, Harry Wentland wrote:



On 2024-02-16 11:11, Harry Wentland wrote:



On 2024-02-16 10:42, Pekka Paalanen wrote:

On Fri, 16 Feb 2024 09:33:47 -0500
Harry Wentland  wrote:


On 2024-02-16 03:19, Pekka Paalanen wrote:

On Fri, 2 Feb 2024 10:28:35 -0500
Hamza Mahfooz  wrote:
   

We want programs besides the compositor to be able to enable or disable
panel power saving features.


Could you also explain why, in the commit message, please?

It is unexpected for arbitrary programs to be able to override the KMS
client, and certainly new ways to do so should not be added without an
excellent justification.

Maybe debugfs would be more appropriate if the purpose is only testing
rather than production environments?
   

However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.


When the DRM property was added, what was used as the userspace to
prove its workings?
   


I don't think there ever was a userspace implementation and doubt any
exists today. Part of that is on me. In hindsight, the KMS prop should
have never gone upstream.

I suggest we drop the KMS prop entirely.


Sounds good. What about the sysfs thing? Should it be a debugfs thing
instead, assuming the below question will be resolved?




It's intended to be used by the power profiles daemon (PPD). I don't think
debugfs is the right choice. See
https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/commit/41ed5d33a82b0ceb7b6d473551eb2aa62cade6bc


As for the color accuracy topic, I think it is important that compositors
can have full control over that if needed, while it's also important
for HW vendors to optimize for power when absolute color accuracy is not
needed. An average end-user writing code or working on their slides
would rather have a longer battery life than a perfectly color-accurate
display. We should probably think of a solution that can support both
use-cases.


I agree. Maybe this pondering should start from "how would it work from
end user perspective"?

"Automatically" is probably be most desirable answer. Some kind of


I agree


desktop settings with options like "save power at the expense of image
quality":
- always
- not if watching movies/gaming
- on battery
- on battery, unless I'm watching movies/gaming
- never



It's interesting that you split out movies/gaming, specifically. AMD's
ABM algorithm seems to have considered movies in particular when
evaluating the power/fidelity trade-off.

I wouldn't think consumer media is very particular about a specific
color fidelity (despite what HDR specs try to make you believe). Where
color fidelity would matter to me is when I'd want to edit pictures or
video.

The "abm_level" property that we expose is really just that, a setting
for the strength of the power-savings effect, with 0 being off and 4 being
maximum strength and power saving, at the expense of fidelity.

Mario's work is to let the PPD control it and set the ABM levels based on
the selected power profile:
0 - Performance
1 - Balance
3 - Power

And I believe we've looked at disabling ABM (setting it to 0) automatically
if we know we're on AC power.


Or maybe there already is something like that, and it only needs to be
plumbed through?

Which would point towards KMS clients needing to control it, which
means a generic KMS prop rather than vendor specific?

Or should the desktop compositor be talking to some daemon instead of
KMS for this? Maybe they already are?



I think the intention is for the PPD to be that daemon. Mario can elaborate.



Some more details and screenshots on how the PPD is expected to work and look:
https://linuxconfig.org/how-to-manage-power-profiles-over-d-bus-with-power-profiles-daemon-on-linux


Right, thanks!

The most important point is that the user indicates intent from the GUI.
The daemon orchestrates the various knobs to get that intent.

It's intentionally very coarse - 3 power states.  The policy of what to 
do for those states is managed by the daemon.


In the case of ABM it will only apply the policy if the daemon detects 
the system is on battery.




[PATCH] drm/amd: Drop abm_level property

2024-02-16 Thread Mario Limonciello
This vendor specific property has never been used by userspace
software and conflicts with the panel_power_savings sysfs file.
That is a compositor and user could fight over the same data.

Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs entry to 
eDP connectors")
Suggested-by: Harry Wentland 
Signed-off-by: Mario Limonciello 
--
Cc: Hamza Mahfooz 
Cc: Sun peng (Leo) Li 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  8 
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  2 --
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 --
 3 files changed, 24 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index b8fbe97efe1d..3ecc7ef95172 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -1350,14 +1350,6 @@ int amdgpu_display_modeset_create_props(struct 
amdgpu_device *adev)
 "dither",
 amdgpu_dither_enum_list, sz);
 
-   if (adev->dc_enabled) {
-   adev->mode_info.abm_level_property =
-   drm_property_create_range(adev_to_drm(adev), 0,
- "abm level", 0, 4);
-   if (!adev->mode_info.abm_level_property)
-   return -ENOMEM;
-   }
-
return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 2e4911050cc5..1fe21a70ddd0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -324,8 +324,6 @@ struct amdgpu_mode_info {
struct drm_property *audio_property;
/* FMT dithering */
struct drm_property *dither_property;
-   /* Adaptive Backlight Modulation (power feature) */
-   struct drm_property *abm_level_property;
/* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid;
int bios_hardcoded_edid_size;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b9ac3d2f8029..e3b32ffba85a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6388,9 +6388,6 @@ int amdgpu_dm_connector_atomic_set_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
dm_new_state->underscan_enable = val;
ret = 0;
-   } else if (property == adev->mode_info.abm_level_property) {
-   dm_new_state->abm_level = val ?: ABM_LEVEL_IMMEDIATE_DISABLE;
-   ret = 0;
}
 
return ret;
@@ -6433,10 +6430,6 @@ int amdgpu_dm_connector_atomic_get_property(struct 
drm_connector *connector,
} else if (property == adev->mode_info.underscan_property) {
*val = dm_state->underscan_enable;
ret = 0;
-   } else if (property == adev->mode_info.abm_level_property) {
-   *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
-   dm_state->abm_level : 0;
-   ret = 0;
}
 
return ret;
@@ -7652,13 +7645,6 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_requested_bpc = 
aconnector->base.state->max_bpc;
 
-   if (connector_type == DRM_MODE_CONNECTOR_eDP &&
-   (dc_is_dmcu_initialized(adev->dm.dc) ||
-adev->dm.dc->ctx->dmub_srv) && amdgpu_dm_abm_level < 0) {
-   drm_object_attach_property(>base.base,
-   adev->mode_info.abm_level_property, 0);
-   }
-
if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
/* Content Type is currently only implemented for HDMI. */
drm_connector_attach_content_type_property(>base);
-- 
2.34.1



Re: [PATCH] drm/amd: Only allow one entity to control ABM

2024-02-16 Thread Mario Limonciello

On 2/16/2024 09:41, Christian König wrote:

Am 16.02.24 um 16:12 schrieb Mario Limonciello:

On 2/16/2024 09:05, Harry Wentland wrote:



On 2024-02-16 09:47, Christian König wrote:

Am 16.02.24 um 15:42 schrieb Mario Limonciello:

On 2/16/2024 08:38, Christian König wrote:

Am 16.02.24 um 15:07 schrieb Mario Limonciello:

By exporting ABM to sysfs it's possible that DRM master and software
controlling the sysfs file fight over the value programmed for ABM.

Adjust the module parameter behavior to control who control ABM:
-2: DRM
-1: sysfs (IE via software like power-profiles-daemon)


Well that sounds extremely awkward. Why should a 
power-profiles-deamon has control over the panel power saving 
features?


I mean we are talking about things like reducing backlight level 
when the is inactivity, don't we?


We're talking about activating the ABM algorithm when the system is 
in power saving mode; not from inactivity.  This allows the user to 
squeeze out some extra power "just" in that situation.


But given the comments on the other patch, I tend to agree with 
Harry's proposal instead that we just drop the DRM property 
entirely as there are no consumers of it.


Yeah, but even then the design to let this be controlled by an 
userspace deamon is questionable. Stuff like that is handled inside 
the kernel and not exposed to userspace usually.




Regarding the "how" and "why" of PPD; besides this panel power savings 
sysfs file there are two other things that are nominally changed.


ACPI platform profile: 
https://www.kernel.org/doc/html/latest/userspace-api/sysfs-platform_profile.html


AMD-Pstate EPP value: 
https://www.kernel.org/doc/html//latest/admin-guide/pm/amd-pstate.html


When a user goes into "power saving" mode both of those are tweaked. 
Before we introduced the EPP tweaking in PPD we did discuss a callback 
within the kernel so that userspace could change "just" the ACPI 
platform profile and everything else would react.  There was pushback 
on this, and so instead knobs are offered for things that should be 
tweaked and the userspace daemon can set up policy for what to do when 
a a user uses a userspace client (such as GNOME or KDE) to change the 
desired system profile.


Ok, well who came up with the idea of the userspace deamon? Cause I 
think there will be even more push back on this approach.


Basically when we go from AC to battery (or whatever) the drivers 
usually handle that all inside the kernel today. Involving userspace is 
only done when there is a need for that, e.g. inactivity detection or 
similar.




It's more than AC vs battery.  It's user preference of how they want to 
use the system.


Here's some screenshots of how it all works:

https://linuxconfig.org/how-to-manage-power-profiles-over-d-bus-with-power-profiles-daemon-on-linux



I think we'll need a bit in our kernel docs describing ABM. 
Assumptions around what it is and does seem to lead to confusion.


The thing is that ABM has a visual impact that not all users like. It 
would make sense for users to be able to change the ABM level as 
desired, and/or configure their power profiles to select a certain 
ABM level.


ABM will reduce the backlight and compensate by adjusting brightness 
and contrast of the image. It has 5 levels: 0, 1, 2, 3, 4. 0 means 
off. 4 means maximum backlight reduction. IMO, 1 and 2 look okay. 3 
and 4 can be quite impactful, both to power and visual fidelity.




Aside from this patch Hamza did make some improvements to the kdoc in 
the recent patches, can you read through again and see if you think it 
still needs improvements?


Well what exactly is the requirement? That we have different ABM 
settings for AC and battery? If yes providing different DRM properties 
would sound like the right approach to me.




It's user wants system in "power-saving" state or they want it in 
"balanced" state or they want it in "performance" state.


User picks that state in a client and there is a designated ABM policy 
value that goes with it.  Daemon programs the ABM value.


Re: [PATCH] drm/amd: Only allow one entity to control ABM

2024-02-16 Thread Mario Limonciello

On 2/16/2024 09:05, Harry Wentland wrote:



On 2024-02-16 09:47, Christian König wrote:

Am 16.02.24 um 15:42 schrieb Mario Limonciello:

On 2/16/2024 08:38, Christian König wrote:

Am 16.02.24 um 15:07 schrieb Mario Limonciello:

By exporting ABM to sysfs it's possible that DRM master and software
controlling the sysfs file fight over the value programmed for ABM.

Adjust the module parameter behavior to control who control ABM:
-2: DRM
-1: sysfs (IE via software like power-profiles-daemon)


Well that sounds extremely awkward. Why should a power-profiles-deamon has 
control over the panel power saving features?

I mean we are talking about things like reducing backlight level when the is 
inactivity, don't we?


We're talking about activating the ABM algorithm when the system is in power saving mode; 
not from inactivity.  This allows the user to squeeze out some extra power 
"just" in that situation.

But given the comments on the other patch, I tend to agree with Harry's 
proposal instead that we just drop the DRM property entirely as there are no 
consumers of it.


Yeah, but even then the design to let this be controlled by an userspace deamon 
is questionable. Stuff like that is handled inside the kernel and not exposed 
to userspace usually.



Regarding the "how" and "why" of PPD; besides this panel power savings 
sysfs file there are two other things that are nominally changed.


ACPI platform profile: 
https://www.kernel.org/doc/html/latest/userspace-api/sysfs-platform_profile.html


AMD-Pstate EPP value: 
https://www.kernel.org/doc/html//latest/admin-guide/pm/amd-pstate.html


When a user goes into "power saving" mode both of those are tweaked. 
Before we introduced the EPP tweaking in PPD we did discuss a callback 
within the kernel so that userspace could change "just" the ACPI 
platform profile and everything else would react.  There was pushback on 
this, and so instead knobs are offered for things that should be tweaked 
and the userspace daemon can set up policy for what to do when a a user 
uses a userspace client (such as GNOME or KDE) to change the desired 
system profile.




I think we'll need a bit in our kernel docs describing ABM. Assumptions around 
what it is and does seem to lead to confusion.

The thing is that ABM has a visual impact that not all users like. It would 
make sense for users to be able to change the ABM level as desired, and/or 
configure their power profiles to select a certain ABM level.

ABM will reduce the backlight and compensate by adjusting brightness and 
contrast of the image. It has 5 levels: 0, 1, 2, 3, 4. 0 means off. 4 means 
maximum backlight reduction. IMO, 1 and 2 look okay. 3 and 4 can be quite 
impactful, both to power and visual fidelity.



Aside from this patch Hamza did make some improvements to the kdoc in 
the recent patches, can you read through again and see if you think it 
still needs improvements?



Harry


Regards,
Christian.





Regards,
Christian.


0-4: User via command line

Also introduce a Kconfig option that allows distributions to choose
the default policy that is appropriate for them.

Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs entry to eDP 
connectors")
Signed-off-by: Mario Limonciello 
---
Cc: Hamza Mahfooz 
Cc: Harry Wentland 
Cc: Sun peng (Leo) Li 
   drivers/gpu/drm/amd/amdgpu/Kconfig    | 72 +++
   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 23 +++---
   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  6 +-
   3 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 22d88f8ef527..2ab57ccf6f21 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -80,6 +80,78 @@ config DRM_AMDGPU_WERROR
     Add -Werror to the build flags for amdgpu.ko.
     Only enable this if you are warning code for amdgpu.ko.
+choice
+    prompt "Amdgpu panel power Savings"
+    default AMDGPU_SYSFS_ABM
+    help
+    Control the default behavior for adaptive panel power savings.
+
+    Panel power savings features will sacrifice color accuracy
+    in exchange for power savings.
+
+    This can be configured for:
+    - dynamic control by the DRM master
+    - dynamic control by sysfs nodes
+    - statically by the user at kernel compile time
+
+    This value can also be overridden by the amdgpu.abmlevel
+    module parameter.
+
+config AMDGPU_DRM_ABM
+    bool "DRM Master control"
+    help
+    Export a property called 'abm_level' that can be
+    manipulated by the DRM master for supported hardware.
+
+config AMDGPU_SYSFS_ABM
+    bool "sysfs control"
+    help
+    Export a sysfs file 'panel_power_savings' that can be
+    manipulated by userspace for supported hardware.
+
+config AMDGPU_HARDCODE_ABM0
+    bool &qu

Re: [PATCH] drm/amd: Only allow one entity to control ABM

2024-02-16 Thread Mario Limonciello

On 2/16/2024 08:38, Christian König wrote:

Am 16.02.24 um 15:07 schrieb Mario Limonciello:

By exporting ABM to sysfs it's possible that DRM master and software
controlling the sysfs file fight over the value programmed for ABM.

Adjust the module parameter behavior to control who control ABM:
-2: DRM
-1: sysfs (IE via software like power-profiles-daemon)


Well that sounds extremely awkward. Why should a power-profiles-deamon 
has control over the panel power saving features?


I mean we are talking about things like reducing backlight level when 
the is inactivity, don't we?


We're talking about activating the ABM algorithm when the system is in 
power saving mode; not from inactivity.  This allows the user to squeeze 
out some extra power "just" in that situation.


But given the comments on the other patch, I tend to agree with Harry's 
proposal instead that we just drop the DRM property entirely as there 
are no consumers of it.




Regards,
Christian.


0-4: User via command line

Also introduce a Kconfig option that allows distributions to choose
the default policy that is appropriate for them.

Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs 
entry to eDP connectors")

Signed-off-by: Mario Limonciello 
---
Cc: Hamza Mahfooz 
Cc: Harry Wentland 
Cc: Sun peng (Leo) Li 
  drivers/gpu/drm/amd/amdgpu/Kconfig    | 72 +++
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 23 +++---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  6 +-
  3 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig

index 22d88f8ef527..2ab57ccf6f21 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -80,6 +80,78 @@ config DRM_AMDGPU_WERROR
    Add -Werror to the build flags for amdgpu.ko.
    Only enable this if you are warning code for amdgpu.ko.
+choice
+    prompt "Amdgpu panel power Savings"
+    default AMDGPU_SYSFS_ABM
+    help
+    Control the default behavior for adaptive panel power savings.
+
+    Panel power savings features will sacrifice color accuracy
+    in exchange for power savings.
+
+    This can be configured for:
+    - dynamic control by the DRM master
+    - dynamic control by sysfs nodes
+    - statically by the user at kernel compile time
+
+    This value can also be overridden by the amdgpu.abmlevel
+    module parameter.
+
+config AMDGPU_DRM_ABM
+    bool "DRM Master control"
+    help
+    Export a property called 'abm_level' that can be
+    manipulated by the DRM master for supported hardware.
+
+config AMDGPU_SYSFS_ABM
+    bool "sysfs control"
+    help
+    Export a sysfs file 'panel_power_savings' that can be
+    manipulated by userspace for supported hardware.
+
+config AMDGPU_HARDCODE_ABM0
+    bool "No Panel power savings"
+    help
+    Disable panel power savings.
+    It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM1
+    bool "25% Panel power savings"
+    help
+    Set the ABM panel power savings algorithm to 25%.
+    It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM2
+    bool "50% Panel power savings"
+    help
+    Set the ABM panel power savings algorithm to 50%.
+    It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM3
+    bool "75% Panel power savings"
+    help
+    Set the ABM panel power savings algorithm to 75%.
+    It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM4
+    bool "100% Panel power savings"
+    help
+    Set the ABM panel power savings algorithm to 100%.
+    It can only overridden by the kernel command line.
+endchoice
+
+config AMDGPU_ABM_POLICY
+    int
+    default -2 if AMDGPU_DRM_ABM
+    default -1 if AMDGPU_SYSFS_ABM
+    default 0 if AMDGPU_HARDCODE_ABM0
+    default 1 if AMDGPU_HARDCODE_ABM1
+    default 2 if AMDGPU_HARDCODE_ABM2
+    default 3 if AMDGPU_HARDCODE_ABM3
+    default 4 if AMDGPU_HARDCODE_ABM4
+    default -1
+
+
  source "drivers/gpu/drm/amd/acp/Kconfig"
  source "drivers/gpu/drm/amd/display/Kconfig"
  source "drivers/gpu/drm/amd/amdkfd/Kconfig"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

index af7fae7907d7..00d6c8b58716 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -844,17 +844,24 @@ module_param_named(visualconfirm, 
amdgpu_dc_visual_confirm, uint, 0444);

   * DOC: abmlevel (uint)
   * Override the default ABM (Adaptive Backlight Management) level 
used for DC

   * enabled hardware. Requires DMCU to be supported and loaded.
- * Valid levels are 0-4. A value of 0 indicates that ABM should be 
disabled by
- * d

[PATCH] drm/amd: Only allow one entity to control ABM

2024-02-16 Thread Mario Limonciello
By exporting ABM to sysfs it's possible that DRM master and software
controlling the sysfs file fight over the value programmed for ABM.

Adjust the module parameter behavior to control who control ABM:
-2: DRM
-1: sysfs (IE via software like power-profiles-daemon)
0-4: User via command line

Also introduce a Kconfig option that allows distributions to choose
the default policy that is appropriate for them.

Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs entry to 
eDP connectors")
Signed-off-by: Mario Limonciello 
---
Cc: Hamza Mahfooz 
Cc: Harry Wentland 
Cc: Sun peng (Leo) Li 
 drivers/gpu/drm/amd/amdgpu/Kconfig| 72 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 23 +++---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  6 +-
 3 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 22d88f8ef527..2ab57ccf6f21 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -80,6 +80,78 @@ config DRM_AMDGPU_WERROR
  Add -Werror to the build flags for amdgpu.ko.
  Only enable this if you are warning code for amdgpu.ko.
 
+choice
+   prompt "Amdgpu panel power Savings"
+   default AMDGPU_SYSFS_ABM
+   help
+   Control the default behavior for adaptive panel power savings.
+
+   Panel power savings features will sacrifice color accuracy
+   in exchange for power savings.
+
+   This can be configured for:
+   - dynamic control by the DRM master
+   - dynamic control by sysfs nodes
+   - statically by the user at kernel compile time
+
+   This value can also be overridden by the amdgpu.abmlevel
+   module parameter.
+
+config AMDGPU_DRM_ABM
+   bool "DRM Master control"
+   help
+   Export a property called 'abm_level' that can be
+   manipulated by the DRM master for supported hardware.
+
+config AMDGPU_SYSFS_ABM
+   bool "sysfs control"
+   help
+   Export a sysfs file 'panel_power_savings' that can be
+   manipulated by userspace for supported hardware.
+
+config AMDGPU_HARDCODE_ABM0
+   bool "No Panel power savings"
+   help
+   Disable panel power savings.
+   It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM1
+   bool "25% Panel power savings"
+   help
+   Set the ABM panel power savings algorithm to 25%.
+   It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM2
+   bool "50% Panel power savings"
+   help
+   Set the ABM panel power savings algorithm to 50%.
+   It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM3
+   bool "75% Panel power savings"
+   help
+   Set the ABM panel power savings algorithm to 75%.
+   It can only overridden by the kernel command line.
+
+config AMDGPU_HARDCODE_ABM4
+   bool "100% Panel power savings"
+   help
+   Set the ABM panel power savings algorithm to 100%.
+   It can only overridden by the kernel command line.
+endchoice
+
+config AMDGPU_ABM_POLICY
+   int
+   default -2 if AMDGPU_DRM_ABM
+   default -1 if AMDGPU_SYSFS_ABM
+   default 0 if AMDGPU_HARDCODE_ABM0
+   default 1 if AMDGPU_HARDCODE_ABM1
+   default 2 if AMDGPU_HARDCODE_ABM2
+   default 3 if AMDGPU_HARDCODE_ABM3
+   default 4 if AMDGPU_HARDCODE_ABM4
+   default -1
+
+
 source "drivers/gpu/drm/amd/acp/Kconfig"
 source "drivers/gpu/drm/amd/display/Kconfig"
 source "drivers/gpu/drm/amd/amdkfd/Kconfig"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index af7fae7907d7..00d6c8b58716 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -844,17 +844,24 @@ module_param_named(visualconfirm, 
amdgpu_dc_visual_confirm, uint, 0444);
  * DOC: abmlevel (uint)
  * Override the default ABM (Adaptive Backlight Management) level used for DC
  * enabled hardware. Requires DMCU to be supported and loaded.
- * Valid levels are 0-4. A value of 0 indicates that ABM should be disabled by
- * default. Values 1-4 control the maximum allowable brightness reduction via
- * the ABM algorithm, with 1 being the least reduction and 4 being the most
- * reduction.
+ * Valid levels are -2 through 4.
  *
- * Defaults to -1, or disabled. Userspace can only override this level after
- * boot if it's set to auto.
+ *  -2: indicates that ABM should be controlled by DRM property 'abm_level.
+ *  -1: indicates that ABM should be controlled by the sysfs file
+ *  'panel_power_s

[PATCH] drm/amd: Change `jpeg_v4_0_5_start_dpg_mode()` to void

2024-02-15 Thread Mario Limonciello
jpeg_v4_0_5_start_dpg_mode() always returns 0 and the return value
doesn't get used in the caller jpeg_v4_0_5_start(). Modify the
function to be void.

Reported-by: coverity-bot 
Addresses-Coverity-ID: 1583635 ("Code maintainability issues")
Fixes: 0a119d53f74a ("drm/amdgpu/jpeg: add support for jpeg DPG mode")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c 
b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index 3602738874ee..8d1754e35605 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -358,7 +358,7 @@ static int jpeg_v4_0_5_enable_static_power_gating(struct 
amdgpu_device *adev, in
  *
  * Start JPEG block with dpg mode
  */
-static int jpeg_v4_0_5_start_dpg_mode(struct amdgpu_device *adev, int 
inst_idx, bool indirect)
+static void jpeg_v4_0_5_start_dpg_mode(struct amdgpu_device *adev, int 
inst_idx, bool indirect)
 {
struct amdgpu_ring *ring = adev->jpeg.inst[inst_idx].ring_dec;
uint32_t reg_data = 0;
@@ -411,8 +411,6 @@ static int jpeg_v4_0_5_start_dpg_mode(struct amdgpu_device 
*adev, int inst_idx,
WREG32_SOC15(JPEG, inst_idx, regUVD_JRBC_RB_CNTL, 0x0002L);
WREG32_SOC15(JPEG, inst_idx, regUVD_JRBC_RB_SIZE, ring->ring_size / 4);
ring->wptr = RREG32_SOC15(JPEG, inst_idx, regUVD_JRBC_RB_WPTR);
-
-   return 0;
 }
 
 /**
@@ -458,7 +456,7 @@ static int jpeg_v4_0_5_start(struct amdgpu_device *adev)
VCN_JPEG_DB_CTRL__EN_MASK);
 
if (adev->pg_flags & AMD_PG_SUPPORT_JPEG_DPG) {
-   r = jpeg_v4_0_5_start_dpg_mode(adev, i, 
adev->jpeg.indirect_sram);
+   jpeg_v4_0_5_start_dpg_mode(adev, i, 
adev->jpeg.indirect_sram);
continue;
}
 
-- 
2.34.1



Re: [PATCH v6 3/5] drm: Add support to get EDID from ACPI

2024-02-15 Thread Mario Limonciello

On 2/15/2024 12:47, Ville Syrjälä wrote:

On Thu, Feb 15, 2024 at 12:20:56PM -0600, Mario Limonciello wrote:

On 2/14/2024 17:13, Ville Syrjälä wrote:

On Wed, Feb 14, 2024 at 03:57:54PM -0600, Mario Limonciello wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
   drivers/gpu/drm/Kconfig |   1 +
   drivers/gpu/drm/drm_edid.c  | 109 +---
   include/drm/drm_connector.h |   6 ++
   include/drm/drm_edid.h  |   1 +
   4 files changed, 109 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 872edb47bb53..3db89e6af01d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -8,6 +8,7 @@
   menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI 
support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
select DRM_PANEL_ORIENTATION_QUIRKS
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..cdc30c6d05d5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
* DEALINGS IN THE SOFTWARE.
*/
   
+#include 

   #include 
   #include 
   #include 
@@ -2188,6 +2189,58 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
   }
   
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }


We could have other types of connectors that want this too.
I don't see any real benefit in having this check tbh. Drivers
should simply notset the flag on connectors where it won't work,
and only the driver can really know that.


Ack.




+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return r;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
   static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
   {
@@ -2621,7 +2674,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
* @connector: connector we're probing
* @adapter: I2C adapter to use for DDC
*
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
* attach it to the connector.
*
* Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2683,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
   struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
   {
-   struct edid *edid;
+   struct edid *edid = NULL;
   
   	if (connector->force == DRM_FORCE_OFF)

return NULL;
   
-	if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter))

-   return NULL;
+   if (connector->acpi_edid_allowed)
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector, NULL);
+
+   if (!edid) {
+   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+   return NULL;
+   edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, 
adapter, NULL);
+ 

Re: [PATCH v6 3/5] drm: Add support to get EDID from ACPI

2024-02-15 Thread Mario Limonciello

On 2/14/2024 17:13, Ville Syrjälä wrote:

On Wed, Feb 14, 2024 at 03:57:54PM -0600, Mario Limonciello wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/Kconfig |   1 +
  drivers/gpu/drm/drm_edid.c  | 109 +---
  include/drm/drm_connector.h |   6 ++
  include/drm/drm_edid.h  |   1 +
  4 files changed, 109 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 872edb47bb53..3db89e6af01d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -8,6 +8,7 @@
  menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI 
support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
select DRM_PANEL_ORIENTATION_QUIRKS
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..cdc30c6d05d5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,58 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }


We could have other types of connectors that want this too.
I don't see any real benefit in having this check tbh. Drivers
should simply notset the flag on connectors where it won't work,
and only the driver can really know that.


Ack.




+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return r;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2621,7 +2674,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
   * @connector: connector we're probing
   * @adapter: I2C adapter to use for DDC
   *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
   * attach it to the connector.
   *
   * Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2683,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
  struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
  {
-   struct edid *edid;
+   struct edid *edid = NULL;
  
  	if (connector->force == DRM_FORCE_OFF)

return NULL;
  
-	if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter))

-   return NULL;
+   if (connector->acpi_edid_allowed)
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector, NULL);
+
+   if (!edid) {
+   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+   return NULL;
+   edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, 
adapter, NULL);
+   }
  
-	edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter, NULL);

drm_connector_update_

Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-15 Thread Mario Limonciello

On 2/15/2024 11:54, Harry Wentland wrote:

On 2024-02-02 11:20, Mario Limonciello wrote:

On 2/2/2024 09:28, Hamza Mahfooz wrote:

We want programs besides the compositor to be able to enable or disable
panel power saving features. However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.



I've been trying to avoid looking at this too closely, partly because
I want ABM enablement by default, with control for users. But the
more I think about this the more uncomfortable I get. The key for my
discomfort is that we're going around the back of DRM master to set
a DRM property. This is apt to create lots of weird behaviors,
especially if compositors also decide to implement support for the
abm_level property and then potentially fight PPD, or other users
of this sysfs.


I feel the problem is that specifically both DRM master and sysfs can 
simultaneously fight over the value for ABM.


This isn't a totally new problem because previously the user and DRM
master could fight over this (with the user setting it on command line
and DRM master overriding that).  That was fixed in a follow up patch
though in that the DRM property isn't attached if a user sets the value
on the command line.

I feel the solution to these concerns is that we should make a knob that 
controls whether the DRM property is created or the sysfs file is 
created but not let them happen simultaneously.


We already have amdgpu.abmlevel=-1 is the only time sysfs is created. 
I'd say we should drop the drm property in that case and add a case for 
amdgpu.abmlevel=-2 which will only make the drm property and not the 
sysfs value.  With that done it turns into:


-2  : DRM master is in control
-1  : sysfs is in control.  Software like PPD will tune it as needed.
0-4 : User is in control.




Re: [PATCH v5 1/3] drm: Add support to get EDID from ACPI

2024-02-15 Thread Mario Limonciello

On 2/15/2024 08:01, Jani Nikula wrote:

On Sat, 10 Feb 2024, Mario Limonciello  wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
v1->v2:
  * Split code from previous amdgpu specific helper to generic drm helper.
v2->v3:
  * Add an extra select to fix a variety of randconfig errors found from
LKP robot.
v3->v4:
  * Return struct drm_edid
v4->v5:
  * Rename to drm_edid_read_acpi
  * Drop selects
---
  drivers/gpu/drm/Kconfig |   7 +++
  drivers/gpu/drm/drm_edid.c  | 113 +---
  include/drm/drm_connector.h |   6 ++
  include/drm/drm_edid.h  |   1 +
  4 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..a49740c528b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -103,6 +103,13 @@ config DRM_KMS_HELPER
help
  CRTC helpers for KMS drivers.
  
+config DRM_ACPI_HELPER

+   tristate "ACPI support in DRM"
+   depends on DRM
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
+   help
+ ACPI helpers for DRM drivers.
+
  config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
  bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..096c278b6f66 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,62 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* fetch the entire edid from BIOS */
+   if (IS_REACHABLE(CONFIG_DRM_ACPI_HELPER)) {
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, 
);
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   } else {
+   r = -EOPNOTSUPP;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2621,7 +2678,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
   * @connector: connector we're probing
   * @adapter: I2C adapter to use for DDC
   *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
   * attach it to the connector.
   *
   * Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2687,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
  struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
  {
-   struct edid *edid;
+   struct edid *edid = NULL;
  
  	if (connector->force == DRM_FORCE_OFF)

return NULL;
  
-	if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter))

-   return NULL;
+   if (connector->acpi_edid_allowed)
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector, NULL);
+
+   if (!edid) {
+   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+   retu

[PATCH v6 4/5] drm/amd: Fetch the EDID from _DDC if available for eDP

2024-02-14 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.

Attempt to fetch this EDID if it exists and prefer it over the EDID
that is provided by the panel. If a user prefers to use the EDID from
the panel, offer a module parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   | 1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c| 3 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 8 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 ++
 5 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 312dfaec7b4a..fcec39a62a39 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -215,6 +215,7 @@ extern int amdgpu_smartshift_bias;
 extern int amdgpu_use_xgmi_p2p;
 extern int amdgpu_mtype_local;
 extern bool enforce_isolation;
+extern bool acpi_edid;
 #ifdef CONFIG_HSA_AMD
 extern int sched_policy;
 extern bool debug_evictions;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 9caba10315a8..9165a199ac9b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -281,6 +281,9 @@ static void amdgpu_connector_get_edid(struct drm_connector 
*connector)
if (amdgpu_connector->edid)
return;
 
+   /* if the BIOS specifies the EDID via _DDC, prefer this */
+   connector->acpi_edid_allowed = acpi_edid;
+
/* on hw with routers, select right port */
if (amdgpu_connector->router.ddc_valid)
amdgpu_i2c_router_select_ddc_port(amdgpu_connector);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 161ecf9b4174..9676df447a57 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -166,6 +166,7 @@ uint amdgpu_sdma_phase_quantum = 32;
 char *amdgpu_disable_cu;
 char *amdgpu_virtual_display;
 bool enforce_isolation;
+bool acpi_edid = true;
 /*
  * OverDrive(bit 14) disabled by default
  * GFX DCS(bit 19) disabled by default
@@ -990,6 +991,13 @@ MODULE_PARM_DESC(wbrf,
"Enable Wifi RFI interference mitigation (0 = disabled, 1 = enabled, -1 
= auto(default)");
 module_param_named(wbrf, amdgpu_wbrf, int, 0444);
 
+/**
+ * DOC: acpi_edid (bool)
+ * Try to fetch EDID for eDP display from BIOS using ACPI _DDC method.
+ */
+module_param(acpi_edid, bool, 0444);
+MODULE_PARM_DESC(acpi_edid, "Fetch EDID for eDP display from BIOS");
+
 /* These devices are not supported by amdgpu.
  * They are supported by the mach64, r128, radeon drivers
  */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 467796d97313..504577ea36e7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6649,8 +6649,10 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * Note: drm_get_edid gets edid in the following order:
 * 1) override EDID if set via edid_override debugfs,
 * 2) firmware EDID if set via edid_firmware module parameter
-* 3) regular DDC read.
+* 3) ACPI EDID if allowed via module parameter
+* 4) regular DDC read.
 */
+   connector->acpi_edid_allowed = acpi_edid;
edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 85b7f58a7f35..d570a1b6141b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -910,6 +910,8 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
+   /* prefer ACPI over panel for eDP */
+   connector->acpi_edid_allowed = acpi_edid;
 
edid = drm_get_edid(>base, ddc);
 
-- 
2.34.1



[PATCH v6 2/5] drm: Stop using `select BACKLIGHT_CLASS_DEVICE`

2024-02-14 Thread Mario Limonciello
Many drivers ab(use) `select BACKLIGHT_CLASS_DEVICE` to avoid
dependency problems.  This however makes it impossible for DRM
core to be able to add a dependency on ACPI_VIDEO. Switch users
of `select BACKLIGHT_CLASS_DEVICE` to `depends on BACKLIGHT_CLASS_DEVICE`.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/bridge/Kconfig   |  2 +-
 drivers/gpu/drm/fsl-dcu/Kconfig  |  2 +-
 drivers/gpu/drm/gud/Kconfig  |  2 +-
 drivers/gpu/drm/renesas/shmobile/Kconfig |  2 +-
 drivers/gpu/drm/solomon/Kconfig  |  2 +-
 drivers/gpu/drm/tilcdc/Kconfig   |  2 +-
 drivers/gpu/drm/tiny/Kconfig | 14 +++---
 drivers/platform/x86/Kconfig |  4 ++--
 drivers/usb/misc/Kconfig |  2 +-
 9 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index efd996f6c138..c4e0d506a389 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -218,9 +218,9 @@ config DRM_NXP_PTN3460
 config DRM_PARADE_PS8622
tristate "Parade eDP/LVDS bridge"
depends on OF
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_PANEL
select DRM_KMS_HELPER
-   select BACKLIGHT_CLASS_DEVICE
help
  Parade eDP-LVDS bridge chip driver.
 
diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig
index 5ca71ef87325..93202786bec5 100644
--- a/drivers/gpu/drm/fsl-dcu/Kconfig
+++ b/drivers/gpu/drm/fsl-dcu/Kconfig
@@ -2,7 +2,7 @@
 config DRM_FSL_DCU
tristate "DRM Support for Freescale DCU"
depends on DRM && OF && ARM && COMMON_CLK
-   select BACKLIGHT_CLASS_DEVICE
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER
select DRM_PANEL
diff --git a/drivers/gpu/drm/gud/Kconfig b/drivers/gpu/drm/gud/Kconfig
index 9c1e61f9eec3..44553514ad64 100644
--- a/drivers/gpu/drm/gud/Kconfig
+++ b/drivers/gpu/drm/gud/Kconfig
@@ -3,10 +3,10 @@
 config DRM_GUD
tristate "GUD USB Display"
depends on DRM && USB && MMU
+   depends on BACKLIGHT_CLASS_DEVICE
select LZ4_COMPRESS
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
-   select BACKLIGHT_CLASS_DEVICE
help
  This is a DRM display driver for GUD USB Displays or display
  adapters.
diff --git a/drivers/gpu/drm/renesas/shmobile/Kconfig 
b/drivers/gpu/drm/renesas/shmobile/Kconfig
index 027220b8fe1c..6b36dee443eb 100644
--- a/drivers/gpu/drm/renesas/shmobile/Kconfig
+++ b/drivers/gpu/drm/renesas/shmobile/Kconfig
@@ -3,7 +3,7 @@ config DRM_SHMOBILE
tristate "DRM Support for SH Mobile"
depends on DRM && PM
depends on ARCH_RENESAS || ARCH_SHMOBILE || COMPILE_TEST
-   select BACKLIGHT_CLASS_DEVICE
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select VIDEOMODE_HELPERS
diff --git a/drivers/gpu/drm/solomon/Kconfig b/drivers/gpu/drm/solomon/Kconfig
index c3ee956c2bb9..2b36ac8e0913 100644
--- a/drivers/gpu/drm/solomon/Kconfig
+++ b/drivers/gpu/drm/solomon/Kconfig
@@ -1,7 +1,7 @@
 config DRM_SSD130X
tristate "DRM support for Solomon SSD13xx OLED displays"
depends on DRM && MMU
-   select BACKLIGHT_CLASS_DEVICE
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
help
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index d3bd2d7a181e..640adf075bba 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -2,12 +2,12 @@
 config DRM_TILCDC
tristate "DRM Support for TI LCDC Display Controller"
depends on DRM && OF && ARM
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_BRIDGE
select DRM_PANEL_BRIDGE
select VIDEOMODE_HELPERS
-   select BACKLIGHT_CLASS_DEVICE
help
  Choose this option if you have an TI SoC with LCDC display
  controller, for example AM33xx in beagle-bone, DA8xx, or
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index f6889f649bc1..d5160a6b5d72 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -67,10 +67,10 @@ config DRM_OFDRM
 config DRM_PANEL_MIPI_DBI
tristate "DRM support for MIPI DBI compatible panels"
depends on DRM && SPI
+   depends on BACKLIGHT_CLASS_DEVICE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_MIPI_DBI
-   select BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
  Say Y here if you want to enable support for MIPI DBI compatible
@@ -99,10 +99,10 @

[PATCH v6 5/5] drm/nouveau: Use drm_edid_read_acpi() helper

2024-02-14 Thread Mario Limonciello
Rather than inventing a wrapper to acpi_video_get_edid() use the
one provided by drm. This fixes two problems:
1. A memory leak that the memory provided by the ACPI call was
   never freed.
2. Validation of the BIOS provided blob.

Convert the usage in nouveau_connector_detect_lvds() to use
struct drm_edid at the same time.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c  | 27 
 drivers/gpu/drm/nouveau/nouveau_acpi.h  |  2 --
 drivers/gpu/drm/nouveau/nouveau_connector.c | 35 +
 3 files changed, 14 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 8f0c69aad248..de9daafb3fbb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -360,33 +360,6 @@ void nouveau_unregister_dsm_handler(void) {}
 void nouveau_switcheroo_optimus_dsm(void) {}
 #endif
 
-void *
-nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
-{
-   struct acpi_device *acpidev;
-   int type, ret;
-   void *edid;
-
-   switch (connector->connector_type) {
-   case DRM_MODE_CONNECTOR_LVDS:
-   case DRM_MODE_CONNECTOR_eDP:
-   type = ACPI_VIDEO_DISPLAY_LCD;
-   break;
-   default:
-   return NULL;
-   }
-
-   acpidev = ACPI_COMPANION(dev->dev);
-   if (!acpidev)
-   return NULL;
-
-   ret = acpi_video_get_edid(acpidev, type, -1, );
-   if (ret < 0)
-   return NULL;
-
-   return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-}
-
 bool nouveau_acpi_video_backlight_use_native(void)
 {
return acpi_video_backlight_use_native();
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h 
b/drivers/gpu/drm/nouveau/nouveau_acpi.h
index e39dd8b94b8b..6a3def8e6cca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.h
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h
@@ -10,7 +10,6 @@ bool nouveau_is_v1_dsm(void);
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
 void nouveau_switcheroo_optimus_dsm(void);
-void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 bool nouveau_acpi_video_backlight_use_native(void);
 void nouveau_acpi_video_register_backlight(void);
 #else
@@ -19,7 +18,6 @@ static inline bool nouveau_is_v1_dsm(void) { return false; };
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
 static inline void nouveau_switcheroo_optimus_dsm(void) {}
-static inline void *nouveau_acpi_edid(struct drm_device *dev, struct 
drm_connector *connector) { return NULL; }
 static inline bool nouveau_acpi_video_backlight_use_native(void) { return 
true; }
 static inline void nouveau_acpi_video_register_backlight(void) {}
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 856b3ef5edb8..492035dc8453 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -687,22 +687,13 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
-   struct edid *edid = NULL;
+   const struct drm_edid *drm_edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
 
nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
if (!nv_encoder)
goto out;
 
-   /* Try retrieving EDID via DDC */
-   if (!drm->vbios.fp_no_ddc) {
-   status = nouveau_connector_detect(connector, force);
-   if (status == connector_status_connected) {
-   edid = nv_connector->edid;
-   goto out;
-   }
-   }
-
/* On some laptops (Sony, i'm looking at you) there appears to
 * be no direct way of accessing the panel's EDID.  The only
 * option available to us appears to be to ask ACPI for help..
@@ -712,10 +703,14 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
 * the nouveau decides an entry in the VBIOS FP mode table is
 * valid - it's not (rh#613284)
 */
-   if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-   edid = nouveau_acpi_edid(dev, connector);
-   if (edid) {
-   status = connector_status_connected;
+   if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid)
+   connector->acpi_edid_allowed = true;
+
+   /* Try retrieving EDID via BIOS or DDC */
+   if (!drm->vbios.fp_no_ddc || 
nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
+   status = nouveau_connector_detect(connector, force);
+   i

[PATCH v6 3/5] drm: Add support to get EDID from ACPI

2024-02-14 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/Kconfig |   1 +
 drivers/gpu/drm/drm_edid.c  | 109 +---
 include/drm/drm_connector.h |   6 ++
 include/drm/drm_edid.h  |   1 +
 4 files changed, 109 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 872edb47bb53..3db89e6af01d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -8,6 +8,7 @@
 menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI 
support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
select DRM_PANEL_ORIENTATION_QUIRKS
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..cdc30c6d05d5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -2188,6 +2189,58 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
 }
 
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return r;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
 static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
 {
@@ -2621,7 +2674,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
  * @connector: connector we're probing
  * @adapter: I2C adapter to use for DDC
  *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
  * attach it to the connector.
  *
  * Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2683,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
 struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
-   struct edid *edid;
+   struct edid *edid = NULL;
 
if (connector->force == DRM_FORCE_OFF)
return NULL;
 
-   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
-   return NULL;
+   if (connector->acpi_edid_allowed)
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector, NULL);
+
+   if (!edid) {
+   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+   return NULL;
+   edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, 
adapter, NULL);
+   }
 
-   edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter, 
NULL);
drm_connector_update_edid_property(connector, edid);
return edid;
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+/**
+ * drm_edid_read_acpi - get EDID data, if available
+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.
+ *
+ * The returned pointer must be freed using drm_edid_free().
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find

[PATCH v6 1/5] drm: Stop using `select ACPI_VIDEO` in all drivers

2024-02-14 Thread Mario Limonciello
Many DRM drivers (ab)use `select ACPI_VIDEO` and to avoid problems
will then select all the dependencies for ACPI_VIDEO.  This creates
a soft dependency, but makes it very hard to use ACPI_VIDEO in DRM
core.  Switch everything else over to use `depends on ACPI_VIDEO`
instead.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/Kconfig | 9 +
 drivers/gpu/drm/gma500/Kconfig | 7 +--
 drivers/gpu/drm/i915/Kconfig   | 9 +
 drivers/gpu/drm/nouveau/Kconfig| 9 +
 drivers/gpu/drm/radeon/Kconfig | 9 +
 drivers/gpu/drm/xe/Kconfig | 8 +---
 drivers/platform/loongarch/Kconfig | 2 +-
 drivers/staging/olpc_dcon/Kconfig  | 2 +-
 drivers/video/fbdev/core/Kconfig   | 2 +-
 9 files changed, 9 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 22d88f8ef527..49c3b6eeef76 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -4,6 +4,7 @@ config DRM_AMDGPU
tristate "AMD GPU"
depends on DRM && PCI && MMU
depends on !UML
+   depends on ACPI_VIDEO || !ACPI
select FW_LOADER
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDMI_HELPER
@@ -17,18 +18,10 @@ config DRM_AMDGPU
select HWMON
select I2C
select I2C_ALGOBIT
-   select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
-   # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
-   # ACPI_VIDEO's dependencies must also be selected.
-   select INPUT if ACPI
-   select ACPI_VIDEO if ACPI
-   # On x86 ACPI_VIDEO also needs ACPI_WMI
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
help
  Choose this option if you have a recent AMD Radeon graphics card.
 
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index efb4a2dd2f80..a974cdde4b9c 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -2,16 +2,11 @@
 config DRM_GMA500
tristate "Intel GMA500/600/3600/3650 KMS Framebuffer"
depends on DRM && PCI && X86 && MMU
+   depends on ACPI_VIDEO || !ACPI
select DRM_KMS_HELPER
select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION
select I2C
select I2C_ALGOBIT
-   # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
-   select ACPI_VIDEO if ACPI
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
help
  Say yes for an experimental 2D KMS framebuffer driver for the
  Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index b5d6e3352071..e99405c18c22 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -4,6 +4,7 @@ config DRM_I915
depends on DRM
depends on X86 && PCI
depends on !PREEMPT_RT
+   depends on ACPI_VIDEO || !ACPI
select INTEL_GTT if X86
select INTERVAL_TREE
# we need shmfs for the swappable backing store, and in particular
@@ -22,14 +23,6 @@ config DRM_I915
select I2C
select I2C_ALGOBIT
select IRQ_WORK
-   # i915 depends on ACPI_VIDEO when ACPI is enabled
-   # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
-   select ACPI_VIDEO if ACPI
-   select ACPI_BUTTON if ACPI
select SYNC_FILE
select IOSF_MBI if X86
select CRC32
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 1e6aaf95ff7c..a3768484cbf5 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -2,6 +2,7 @@
 config DRM_NOUVEAU
tristate "Nouveau (NVIDIA) cards"
depends on DRM && PCI && MMU
+   depends on ACPI_VIDEO || !ACPI
select IOMMU_API
select FW_LOADER
select DRM_DISPLAY_DP_HELPER
@@ -15,16 +16,8 @@ config DRM_NOUVEAU
select DRM_SCHED
select I2C
select I2C_ALGOBIT
-   select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
-   select MXM_WMI if ACPI && X86
select POWER_SUPPLY
-   # Similar to i915, we need to select ACPI_VIDEO and it's dependencies
-   select BACKLIGHT_CLASS_DEVICE if ACPI && X86
-   select INPUT if ACPI && X86
select THERMAL if AC

[PATCH v6 0/5] Add support for getting EDID over ACPI to DRM

2024-02-14 Thread Mario Limonciello
This series adds the ability to fetch the EDID through ACPI for laptop
panels. Drivers need to opt into the behavior.

In this series it's enabled by default for all eDP or LVDS panels with
AMDGPU and certain panels for Nouveau.

Mario Limonciello (5):
  drm: Stop using `select ACPI_VIDEO` in all drivers
  drm: Stop using `select BACKLIGHT_CLASS_DEVICE`
  drm: Add support to get EDID from ACPI
  drm/amd: Fetch the EDID from _DDC if available for eDP
  drm/nouveau: Use drm_edid_read_acpi() helper

 drivers/gpu/drm/Kconfig   |   1 +
 drivers/gpu/drm/amd/amdgpu/Kconfig|   9 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |   1 +
 .../gpu/drm/amd/amdgpu/amdgpu_connectors.c|   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   |   8 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   2 +
 drivers/gpu/drm/bridge/Kconfig|   2 +-
 drivers/gpu/drm/drm_edid.c| 109 --
 drivers/gpu/drm/fsl-dcu/Kconfig   |   2 +-
 drivers/gpu/drm/gma500/Kconfig|   7 +-
 drivers/gpu/drm/gud/Kconfig   |   2 +-
 drivers/gpu/drm/i915/Kconfig  |   9 +-
 drivers/gpu/drm/nouveau/Kconfig   |   9 +-
 drivers/gpu/drm/nouveau/nouveau_acpi.c|  27 -
 drivers/gpu/drm/nouveau/nouveau_acpi.h|   2 -
 drivers/gpu/drm/nouveau/nouveau_connector.c   |  35 +++---
 drivers/gpu/drm/radeon/Kconfig|   9 +-
 drivers/gpu/drm/renesas/shmobile/Kconfig  |   2 +-
 drivers/gpu/drm/solomon/Kconfig   |   2 +-
 drivers/gpu/drm/tilcdc/Kconfig|   2 +-
 drivers/gpu/drm/tiny/Kconfig  |  14 +--
 drivers/gpu/drm/xe/Kconfig|   8 +-
 drivers/platform/loongarch/Kconfig|   2 +-
 drivers/platform/x86/Kconfig  |   4 +-
 drivers/staging/olpc_dcon/Kconfig |   2 +-
 drivers/usb/misc/Kconfig  |   2 +-
 drivers/video/fbdev/core/Kconfig  |   2 +-
 include/drm/drm_connector.h   |   6 +
 include/drm/drm_edid.h|   1 +
 30 files changed, 165 insertions(+), 123 deletions(-)

-- 
2.34.1



Re: [PATCH v5 1/3] drm: Add support to get EDID from ACPI

2024-02-12 Thread Mario Limonciello

On 2/12/2024 10:31, Mario Limonciello wrote:

On 2/10/2024 23:50, Mario Limonciello wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
v1->v2:
  * Split code from previous amdgpu specific helper to generic drm 
helper.

v2->v3:
  * Add an extra select to fix a variety of randconfig errors found from
    LKP robot.
v3->v4:
  * Return struct drm_edid
v4->v5:
  * Rename to drm_edid_read_acpi
  * Drop selects
---
  drivers/gpu/drm/Kconfig |   7 +++
  drivers/gpu/drm/drm_edid.c  | 113 +---
  include/drm/drm_connector.h |   6 ++
  include/drm/drm_edid.h  |   1 +
  4 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..a49740c528b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -103,6 +103,13 @@ config DRM_KMS_HELPER
  help
    CRTC helpers for KMS drivers.
+config DRM_ACPI_HELPER
+    tristate "ACPI support in DRM"
+    depends on DRM
+    depends on (ACPI_VIDEO || ACPI_VIDEO=n)
+    help
+  ACPI helpers for DRM drivers.
+


Unfortunately in my wider testing this still fails with a few combinations.

This combination fails to link:

CONFIG_ACPI_VIDEO=m
CONFIG_DRM_ACPI_HELPER=y
CONFIG_DRM=y

This combination links but doesn't work because the IS_REACHABLE() fails 
(-EOPNOTSUPP):


CONFIG_ACPI_VIDEO=m
CONFIG_DRM_ACPI_HELPER=M
CONFIG_DRM=y

I'm tempted to split off all of drm_edid to it's own module instead  of 
CONFIG_DRM_ACPI_HELPER which has a depends on (ACPI_VIDEO || 
ACPI_VIDEIO=n).


Or Daniel, any better ideas?


I've come up with a solution that undoes all the select mess in 
preceding patches.


This patch will be swapped around to

--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -8,6 +8,7 @@
 menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher 
DRI support)"

depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
select DRM_PANEL_ORIENTATION_QUIRKS
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION

I'll wait a little for any other feedback and then post the updated 
series.  None of the other patches change in any material way.





  config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
  bool "Enable refcount backtrace history in the DP MST helpers"
  depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..096c278b6f66 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
+#include 
  #include 
  #include 
  #include 
@@ -2188,6 +2189,62 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, 
unsigned int block, size_t len)

  return ret == xfers ? 0 : -1;
  }
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() 
function.

+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, 
size_t len)

+{
+    struct drm_connector *connector = data;
+    struct drm_device *ddev = connector->dev;
+    struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+    unsigned char start = block * EDID_LENGTH;
+    void *edid;
+    int r;
+
+    if (!acpidev)
+    return -ENODEV;
+
+    switch (connector->connector_type) {
+    case DRM_MODE_CONNECTOR_LVDS:
+    case DRM_MODE_CONNECTOR_eDP:
+    break;
+    default:
+    return -EINVAL;
+    }
+
+    /* fetch the entire edid from BIOS */
+    if (IS_REACHABLE(CONFIG_DRM_ACPI_HELPER)) {
+    r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, 
);

+    if (r < 0) {
+    DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+    return -EINVAL;
+    }
+    } else {
+    r = -EOPNOTSUPP;
+    }
+    if (len > r || start > r || start + len > r) {
+    r = -EINVAL;
+    goto cleanup;
+    }
+
+    memcpy(buf, edid + start, len);
+    r = 0;
+
+cleanup:
+    kfree(edid);
+
+    return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
 const struct edid *edid, int num_blocks)
  {
@@ -2621,7 +2678,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
   * @connector: connector we're probing
   * @adapter: I2C adapter to use for DDC
   *
- * Poke the given 

Re: [PATCH v5 1/3] drm: Add support to get EDID from ACPI

2024-02-12 Thread Mario Limonciello

On 2/10/2024 23:50, Mario Limonciello wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
v1->v2:
  * Split code from previous amdgpu specific helper to generic drm helper.
v2->v3:
  * Add an extra select to fix a variety of randconfig errors found from
LKP robot.
v3->v4:
  * Return struct drm_edid
v4->v5:
  * Rename to drm_edid_read_acpi
  * Drop selects
---
  drivers/gpu/drm/Kconfig |   7 +++
  drivers/gpu/drm/drm_edid.c  | 113 +---
  include/drm/drm_connector.h |   6 ++
  include/drm/drm_edid.h  |   1 +
  4 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..a49740c528b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -103,6 +103,13 @@ config DRM_KMS_HELPER
help
  CRTC helpers for KMS drivers.
  
+config DRM_ACPI_HELPER

+   tristate "ACPI support in DRM"
+   depends on DRM
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
+   help
+ ACPI helpers for DRM drivers.
+


Unfortunately in my wider testing this still fails with a few combinations.

This combination fails to link:

CONFIG_ACPI_VIDEO=m
CONFIG_DRM_ACPI_HELPER=y
CONFIG_DRM=y

This combination links but doesn't work because the IS_REACHABLE() fails 
(-EOPNOTSUPP):


CONFIG_ACPI_VIDEO=m
CONFIG_DRM_ACPI_HELPER=M
CONFIG_DRM=y

I'm tempted to split off all of drm_edid to it's own module instead  of 
CONFIG_DRM_ACPI_HELPER which has a depends on (ACPI_VIDEO || ACPI_VIDEIO=n).


Or Daniel, any better ideas?


  config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
  bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..096c278b6f66 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,62 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* fetch the entire edid from BIOS */
+   if (IS_REACHABLE(CONFIG_DRM_ACPI_HELPER)) {
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, 
);
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   } else {
+   r = -EOPNOTSUPP;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2621,7 +2678,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
   * @connector: connector we're probing
   * @adapter: I2C adapter to use for DDC
   *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
   * attach it to the connector.
   *
   * Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2687,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
  struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
  {
-   struct edid *edid;
+   struct edid *edid = NULL;
  
  	if (connector->force 

[PATCH v5 3/3] drm/nouveau: Use drm_edid_read_acpi() helper

2024-02-11 Thread Mario Limonciello
Rather than inventing a wrapper to acpi_video_get_edid() use the
one provided by drm. This fixes two problems:
1. A memory leak that the memory provided by the ACPI call was
   never freed.
2. Validation of the BIOS provided blob.

Convert the usage in nouveau_connector_detect_lvds() to use
struct drm_edid at the same time.

Signed-off-by: Mario Limonciello 
---
v1->v2:
 * New patch
v3->v4:
 * Rebase on v4 changes
v4->v5:
 * Rebase on v5 changes
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c  | 27 
 drivers/gpu/drm/nouveau/nouveau_acpi.h  |  2 --
 drivers/gpu/drm/nouveau/nouveau_connector.c | 35 +
 3 files changed, 14 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 8f0c69aad248..de9daafb3fbb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -360,33 +360,6 @@ void nouveau_unregister_dsm_handler(void) {}
 void nouveau_switcheroo_optimus_dsm(void) {}
 #endif
 
-void *
-nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
-{
-   struct acpi_device *acpidev;
-   int type, ret;
-   void *edid;
-
-   switch (connector->connector_type) {
-   case DRM_MODE_CONNECTOR_LVDS:
-   case DRM_MODE_CONNECTOR_eDP:
-   type = ACPI_VIDEO_DISPLAY_LCD;
-   break;
-   default:
-   return NULL;
-   }
-
-   acpidev = ACPI_COMPANION(dev->dev);
-   if (!acpidev)
-   return NULL;
-
-   ret = acpi_video_get_edid(acpidev, type, -1, );
-   if (ret < 0)
-   return NULL;
-
-   return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-}
-
 bool nouveau_acpi_video_backlight_use_native(void)
 {
return acpi_video_backlight_use_native();
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h 
b/drivers/gpu/drm/nouveau/nouveau_acpi.h
index e39dd8b94b8b..6a3def8e6cca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.h
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h
@@ -10,7 +10,6 @@ bool nouveau_is_v1_dsm(void);
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
 void nouveau_switcheroo_optimus_dsm(void);
-void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 bool nouveau_acpi_video_backlight_use_native(void);
 void nouveau_acpi_video_register_backlight(void);
 #else
@@ -19,7 +18,6 @@ static inline bool nouveau_is_v1_dsm(void) { return false; };
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
 static inline void nouveau_switcheroo_optimus_dsm(void) {}
-static inline void *nouveau_acpi_edid(struct drm_device *dev, struct 
drm_connector *connector) { return NULL; }
 static inline bool nouveau_acpi_video_backlight_use_native(void) { return 
true; }
 static inline void nouveau_acpi_video_register_backlight(void) {}
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 856b3ef5edb8..492035dc8453 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -687,22 +687,13 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
-   struct edid *edid = NULL;
+   const struct drm_edid *drm_edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
 
nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
if (!nv_encoder)
goto out;
 
-   /* Try retrieving EDID via DDC */
-   if (!drm->vbios.fp_no_ddc) {
-   status = nouveau_connector_detect(connector, force);
-   if (status == connector_status_connected) {
-   edid = nv_connector->edid;
-   goto out;
-   }
-   }
-
/* On some laptops (Sony, i'm looking at you) there appears to
 * be no direct way of accessing the panel's EDID.  The only
 * option available to us appears to be to ask ACPI for help..
@@ -712,10 +703,14 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
 * the nouveau decides an entry in the VBIOS FP mode table is
 * valid - it's not (rh#613284)
 */
-   if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-   edid = nouveau_acpi_edid(dev, connector);
-   if (edid) {
-   status = connector_status_connected;
+   if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid)
+   connector->acpi_edid_allowed = true;
+
+   /* Try retrieving EDID via BIOS or DDC */
+   if (!drm->vbios.fp_no_ddc || 
nv_encoder->dcb->lvds

[PATCH v5 1/3] drm: Add support to get EDID from ACPI

2024-02-11 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers that prefer to
fetch this EDID can set a bit on the drm_connector to indicate that
the DRM EDID helpers should try to fetch it and it is preferred if
it's present.

Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Split code from previous amdgpu specific helper to generic drm helper.
v2->v3:
 * Add an extra select to fix a variety of randconfig errors found from
   LKP robot.
v3->v4:
 * Return struct drm_edid
v4->v5:
 * Rename to drm_edid_read_acpi
 * Drop selects
---
 drivers/gpu/drm/Kconfig |   7 +++
 drivers/gpu/drm/drm_edid.c  | 113 +---
 include/drm/drm_connector.h |   6 ++
 include/drm/drm_edid.h  |   1 +
 4 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..a49740c528b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -103,6 +103,13 @@ config DRM_KMS_HELPER
help
  CRTC helpers for KMS drivers.
 
+config DRM_ACPI_HELPER
+   tristate "ACPI support in DRM"
+   depends on DRM
+   depends on (ACPI_VIDEO || ACPI_VIDEO=n)
+   help
+ ACPI helpers for DRM drivers.
+
 config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
 bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..096c278b6f66 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -2188,6 +2189,62 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
 }
 
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_connector
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct drm_device *ddev = connector->dev;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* fetch the entire edid from BIOS */
+   if (IS_REACHABLE(CONFIG_DRM_ACPI_HELPER)) {
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, 
);
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   } else {
+   r = -EOPNOTSUPP;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
 static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
 {
@@ -2621,7 +2678,8 @@ EXPORT_SYMBOL(drm_probe_ddc);
  * @connector: connector we're probing
  * @adapter: I2C adapter to use for DDC
  *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * If the connector allows it, try to fetch EDID data using ACPI. If not found
+ * poke the given I2C channel to grab EDID data if possible.  If found,
  * attach it to the connector.
  *
  * Return: Pointer to valid EDID or NULL if we couldn't find any.
@@ -2629,20 +2687,50 @@ EXPORT_SYMBOL(drm_probe_ddc);
 struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter)
 {
-   struct edid *edid;
+   struct edid *edid = NULL;
 
if (connector->force == DRM_FORCE_OFF)
return NULL;
 
-   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
-   return NULL;
+   if (connector->acpi_edid_allowed)
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector, NULL);
+
+   if (!edid) {
+   if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+   return NULL;
+   edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, 
adapter, NULL);
+

[PATCH v5 0/3] Add support for getting EDID over ACPI to DRM

2024-02-11 Thread Mario Limonciello
This series adds the ability to fetch the EDID through ACPI for laptop
panels. Drivers need to opt into the behavior.

In this series it's enabled by default for all eDP or LVDS panels with
AMDGPU and certain panels for Nouveau.

Mario Limonciello (3):
  drm: Add support to get EDID from ACPI
  drm/amd: Fetch the EDID from _DDC if available for eDP
  drm/nouveau: Use drm_edid_read_acpi() helper

 drivers/gpu/drm/Kconfig   |   7 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |   1 +
 .../gpu/drm/amd/amdgpu/amdgpu_connectors.c|   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   |   8 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   2 +
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   2 +
 drivers/gpu/drm/drm_edid.c| 113 --
 drivers/gpu/drm/nouveau/nouveau_acpi.c|  27 -
 drivers/gpu/drm/nouveau/nouveau_acpi.h|   2 -
 drivers/gpu/drm/nouveau/nouveau_connector.c   |  35 +++---
 include/drm/drm_connector.h   |   6 +
 include/drm/drm_edid.h|   1 +
 12 files changed, 149 insertions(+), 58 deletions(-)

-- 
2.34.1



[PATCH v5 2/3] drm/amd: Fetch the EDID from _DDC if available for eDP

2024-02-11 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.

Attempt to fetch this EDID if it exists and prefer it over the EDID
that is provided by the panel. If a user prefers to use the EDID from
the panel, offer a module parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
v4->v5:
 * rebase on v5 changes
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   | 1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c| 3 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 8 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 ++
 5 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 543ed9de5a6d..399885251714 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -217,6 +217,7 @@ extern int amdgpu_smartshift_bias;
 extern int amdgpu_use_xgmi_p2p;
 extern int amdgpu_mtype_local;
 extern bool enforce_isolation;
+extern bool acpi_edid;
 #ifdef CONFIG_HSA_AMD
 extern int sched_policy;
 extern bool debug_evictions;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 9caba10315a8..9165a199ac9b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -281,6 +281,9 @@ static void amdgpu_connector_get_edid(struct drm_connector 
*connector)
if (amdgpu_connector->edid)
return;
 
+   /* if the BIOS specifies the EDID via _DDC, prefer this */
+   connector->acpi_edid_allowed = acpi_edid;
+
/* on hw with routers, select right port */
if (amdgpu_connector->router.ddc_valid)
amdgpu_i2c_router_select_ddc_port(amdgpu_connector);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index edc042db4ea8..123f1128d14e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -166,6 +166,7 @@ uint amdgpu_sdma_phase_quantum = 32;
 char *amdgpu_disable_cu;
 char *amdgpu_virtual_display;
 bool enforce_isolation;
+bool acpi_edid = true;
 /*
  * OverDrive(bit 14) disabled by default
  * GFX DCS(bit 19) disabled by default
@@ -991,6 +992,13 @@ MODULE_PARM_DESC(wbrf,
"Enable Wifi RFI interference mitigation (0 = disabled, 1 = enabled, -1 
= auto(default)");
 module_param_named(wbrf, amdgpu_wbrf, int, 0444);
 
+/**
+ * DOC: acpi_edid (bool)
+ * Try to fetch EDID for eDP display from BIOS using ACPI _DDC method.
+ */
+module_param(acpi_edid, bool, 0444);
+MODULE_PARM_DESC(acpi_edid, "Fetch EDID for eDP display from BIOS");
+
 /* These devices are not supported by amdgpu.
  * They are supported by the mach64, r128, radeon drivers
  */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ed90fc8fee9f..0b3a19d3d43a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6619,8 +6619,10 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * Note: drm_get_edid gets edid in the following order:
 * 1) override EDID if set via edid_override debugfs,
 * 2) firmware EDID if set via edid_firmware module parameter
-* 3) regular DDC read.
+* 3) ACPI EDID if allowed via module parameter
+* 4) regular DDC read.
 */
+   connector->acpi_edid_allowed = acpi_edid;
edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 85b7f58a7f35..d570a1b6141b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -910,6 +910,8 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
+   /* prefer ACPI over panel for eDP */
+   connector->acpi_edid_allowed = acpi_edid;
 
edid = drm_get_edid(>base, ddc);
 
-- 
2.34.1



Re: [PATCH v4 1/3] drm: Add drm_get_acpi_edid() helper

2024-02-10 Thread Mario Limonciello

On 2/9/2024 12:57, Daniel Vetter wrote:

On Fri, Feb 09, 2024 at 09:34:13AM -0600, Mario Limonciello wrote:

On 2/9/2024 05:07, Daniel Vetter wrote:

On Thu, Feb 08, 2024 at 11:57:11AM +0200, Jani Nikula wrote:

On Wed, 07 Feb 2024, Mario Limonciello  wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.

Signed-off-by: Mario Limonciello 
---
   drivers/gpu/drm/Kconfig|  5 +++
   drivers/gpu/drm/drm_edid.c | 77 ++
   include/drm/drm_edid.h |  1 +
   3 files changed, 83 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6ec33d36f3a4..ec2bb71e8b36 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86


I think I'll defer to drm maintainers on whether this is okay or
something to be avoided.


Uh yeah this is a bit much, and select just messes with everything. Just
#ifdef this in the code with a dummy alternative, if users configure their
kernel without acpi but need it, they get to keep all the pieces.

Alternatively make a DRM_ACPI_HELPERS symbol, but imo a Kconfig for every
function is also not great. And just using #ifdef in the code also works
for CONFIG_OF, which is exactly the same thing for platforms using dt to
describe hw.

Also I'd expect ACPI code to already provide dummy functions if ACPI is
provided, so you probably dont even need all that much #ifdef in the code.

What we defo cant do is select platform/hw stuff just because you enable
CONFIG_DRM.
-Sima


The problem was with linking.  I'll experiment with #ifdef for the next
version.


Ah yes, if e.g. acpi is a module but drm is built-in then it will compile,
but not link.

You need

depends on (ACPI || ACPI=n)

for this. Looks a bit funny but works for all combinations.


Nope; this fails at link time with this combination:

CONFIG_ACPI=y
CONFIG_ACPI_VIDEO=m
CONFIG_DRM=y

ld: drivers/gpu/drm/drm_edid.o: in function `drm_do_probe_acpi_edid':
drm_edid.c:(.text+0xd34): undefined reference to `acpi_video_get_edid'
make[5]: *** [scripts/Makefile.vmlinux:37: vmlinux] Error 1

So the logical solution is to try
depends on (ACPI_VIDEO || ACPI_VIDEO=n)

But that leads me back to the rabbit hole of why I had the selects moved 
to drm instead of drivers in the first place:


drivers/gpu/drm/Kconfig:8:error: recursive dependency detected!
drivers/gpu/drm/Kconfig:8:  symbol DRM depends on ACPI_VIDEO
drivers/acpi/Kconfig:213:   symbol ACPI_VIDEO depends on 
BACKLIGHT_CLASS_DEVICE
drivers/video/backlight/Kconfig:136:symbol BACKLIGHT_CLASS_DEVICE is 
selected by DRM_RADEON

drivers/gpu/drm/radeon/Kconfig:3:   symbol DRM_RADEON depends on DRM




Since this gets mess it might be useful to have a DRM_ACPI_HELPERS Kconfig
that controls all this.


How about all those selects that I had in this patch moved to 
DRM_ACPI_HELPERS and keep the patch that drops from all the drivers then?



-Sima









help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..c649b4f9fd8e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include 
   #include 
   #include 
   #include 
@@ -2188,6 +2189,49 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
   }
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len

Re: [PATCH] drm/amdgpu: respect the abmlevel module parameter value if it is set

2024-02-10 Thread Mario Limonciello

On 2/9/2024 15:46, Hamza Mahfooz wrote:

Currently, if the abmlevel module parameter is set, it is possible for
user space to override the ABM level at some point after boot. However,
that is undesirable because it means that we aren't respecting the
user's wishes with regard to the level that they want to use. So,
prevent user space from changing the ABM level if the module parameter
is set to a non-auto value.

Signed-off-by: Hamza Mahfooz 


Reviewed-by: Mario Limonciello 
Tested-by: Mario Limonciello 


---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  2 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 11 ++-
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++-
  3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 1291b8eb9dff..f5c8187e0d58 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -196,7 +196,7 @@ extern int amdgpu_smu_pptable_id;
  extern uint amdgpu_dc_feature_mask;
  extern uint amdgpu_dc_debug_mask;
  extern uint amdgpu_dc_visual_confirm;
-extern uint amdgpu_dm_abm_level;
+extern int amdgpu_dm_abm_level;
  extern int amdgpu_backlight;
  extern int amdgpu_damage_clips;
  extern struct amdgpu_mgpu_info mgpu_info;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 6ef7f22c1152..af7fae7907d7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -849,12 +849,13 @@ module_param_named(visualconfirm, 
amdgpu_dc_visual_confirm, uint, 0444);
   * the ABM algorithm, with 1 being the least reduction and 4 being the most
   * reduction.
   *
- * Defaults to 0, or disabled. Userspace can still override this level later
- * after boot.
+ * Defaults to -1, or disabled. Userspace can only override this level after
+ * boot if it's set to auto.
   */
-uint amdgpu_dm_abm_level;
-MODULE_PARM_DESC(abmlevel, "ABM level (0 = off (default), 1-4 = backlight reduction 
level) ");
-module_param_named(abmlevel, amdgpu_dm_abm_level, uint, 0444);
+int amdgpu_dm_abm_level = -1;
+MODULE_PARM_DESC(abmlevel,
+"ABM level (0 = off, 1-4 = backlight reduction level, -1 auto 
(default))");
+module_param_named(abmlevel, amdgpu_dm_abm_level, int, 0444);
  
  int amdgpu_backlight = -1;

  MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto 
(default))");
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index fbe2aa40c21a..a5b3330879f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6513,7 +6513,8 @@ static void amdgpu_dm_connector_unregister(struct 
drm_connector *connector)
  {
struct amdgpu_dm_connector *amdgpu_dm_connector = 
to_amdgpu_dm_connector(connector);
  
-	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)

+   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
+   amdgpu_dm_abm_level < 0)
sysfs_remove_group(>kdev->kobj, _group);
  
  	drm_dp_aux_unregister(_dm_connector->dm_dp_aux.aux);

@@ -6577,9 +6578,12 @@ void amdgpu_dm_connector_funcs_reset(struct 
drm_connector *connector)
state->vcpi_slots = 0;
state->pbn = 0;
  
-		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)

-   state->abm_level = amdgpu_dm_abm_level ?:
-   ABM_LEVEL_IMMEDIATE_DISABLE;
+   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+   if (amdgpu_dm_abm_level <= 0)
+   state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
+   else
+   state->abm_level = amdgpu_dm_abm_level;
+   }
  
  		__drm_atomic_helper_connector_reset(connector, >base);

}
@@ -6617,7 +6621,8 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
to_amdgpu_dm_connector(connector);
int r;
  
-	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {

+   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
+   amdgpu_dm_abm_level < 0) {
r = sysfs_create_group(>kdev->kobj,
   _group);
if (r)




Re: [PATCH v4 1/3] drm: Add drm_get_acpi_edid() helper

2024-02-09 Thread Mario Limonciello

On 2/9/2024 05:07, Daniel Vetter wrote:

On Thu, Feb 08, 2024 at 11:57:11AM +0200, Jani Nikula wrote:

On Wed, 07 Feb 2024, Mario Limonciello  wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.

Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/Kconfig|  5 +++
  drivers/gpu/drm/drm_edid.c | 77 ++
  include/drm/drm_edid.h |  1 +
  3 files changed, 83 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6ec33d36f3a4..ec2bb71e8b36 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86


I think I'll defer to drm maintainers on whether this is okay or
something to be avoided.


Uh yeah this is a bit much, and select just messes with everything. Just
#ifdef this in the code with a dummy alternative, if users configure their
kernel without acpi but need it, they get to keep all the pieces.

Alternatively make a DRM_ACPI_HELPERS symbol, but imo a Kconfig for every
function is also not great. And just using #ifdef in the code also works
for CONFIG_OF, which is exactly the same thing for platforms using dt to
describe hw.

Also I'd expect ACPI code to already provide dummy functions if ACPI is
provided, so you probably dont even need all that much #ifdef in the code.

What we defo cant do is select platform/hw stuff just because you enable
CONFIG_DRM.
-Sima


The problem was with linking.  I'll experiment with #ifdef for the next 
version.








help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..c649b4f9fd8e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,49 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2643,6 +2687,39 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
  }
  EXPORT_SYMBOL(drm_get_edid);
  
+/**

+ * drm_get_acpi_edid - get EDID data, if available


I'd prefer all the new EDID API to be named drm_edid_*. Makes a clean
break from the old API, and is more consistent.

So perhaps drm_edid_read_acpi() to be in line with all the other struct
drm_edid based EDID reading functions.


+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.
+ *
+ * The returned pointer must be freed using drm_edid_free().
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+const struct drm_edid *drm_get_acpi_edid(struct drm_connector *connector)
+{
+   const struct drm_edid *drm_edid;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return NULL;
+   }
+
+   if (connector->force == DRM_FORCE_OFF)
+   return NULL;
+
+ 

Re: [PATCH] drm/amdgpu: make damage clips support configurable

2024-02-08 Thread Mario Limonciello

On 2/8/2024 16:11, Hamza Mahfooz wrote:

We have observed that there are quite a number of PSR-SU panels on the
market that are unable to keep up with what user space throws at them,
resulting in hangs and random black screens. So, make damage clips
support configurable and disable it by default for PSR-SU displays.

Cc: Mario Limonciello 
Signed-off-by: Hamza Mahfooz 


I think this with this patch in place you could also revert

571c2fa26aa6 ("drm/amd/display: Disable PSR-SU on Parade 0803 TCON again")

One minor nit below otherwise LGTM.

Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  1 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 13 +
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  7 +++
  3 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 312dfaec7b4a..1291b8eb9dff 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -198,6 +198,7 @@ extern uint amdgpu_dc_debug_mask;
  extern uint amdgpu_dc_visual_confirm;
  extern uint amdgpu_dm_abm_level;
  extern int amdgpu_backlight;
+extern int amdgpu_damage_clips;
  extern struct amdgpu_mgpu_info mgpu_info;
  extern int amdgpu_ras_enable;
  extern uint amdgpu_ras_mask;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 161ecf9b4174..2b75aeb8280f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -211,6 +211,7 @@ int amdgpu_seamless = -1; /* auto */
  uint amdgpu_debug_mask;
  int amdgpu_agp = -1; /* auto */
  int amdgpu_wbrf = -1;
+int amdgpu_damage_clips = -1; /* auto */
  
  static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
  
@@ -859,6 +860,18 @@ int amdgpu_backlight = -1;

  MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto 
(default))");
  module_param_named(backlight, amdgpu_backlight, bint, 0444);
  
+/**

+ * DOC: damageclips (int)
+ * Enable or disable damage clips support. If damage clips support is disabled,
+ * we will force full frame updates, irrespective of what user space sends to
+ * us.
+ *
+ * Defaults to -1.


I think it would be better if this documentation explained what the 
values are (IE what -1 really means).



+ */
+MODULE_PARM_DESC(damageclips,
+"Damage clips support (0 = disable, 1 = enable, -1 auto 
(default))");
+module_param_named(damageclips, amdgpu_damage_clips, int, 0444);
+
  /**
   * DOC: tmz (int)
   * Trusted Memory Zone (TMZ) is a method to protect data being written
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b3a5e730be24..fbe2aa40c21a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5253,6 +5253,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
struct drm_plane_state *new_plane_state,
struct drm_crtc_state *crtc_state,
struct dc_flip_addrs *flip_addrs,
+   bool is_psr_su,
bool *dirty_regions_changed)
  {
struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
@@ -5277,6 +5278,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
num_clips = drm_plane_get_damage_clips_count(new_plane_state);
clips = drm_plane_get_damage_clips(new_plane_state);
  
+	if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 &&

+  is_psr_su)))
+   goto ffu;
+
if (!dm_crtc_state->mpo_requested) {
if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS)
goto ffu;
@@ -8411,6 +8416,8 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
fill_dc_dirty_rects(plane, old_plane_state,
new_plane_state, new_crtc_state,
>flip_addrs[planes_count],
+   
acrtc_state->stream->link->psr_settings.psr_version ==
+   DC_PSR_VERSION_SU_1,
_rects_changed);
  
  			/*




Re: [PATCH v4 1/3] drm: Add drm_get_acpi_edid() helper

2024-02-08 Thread Mario Limonciello

On 2/8/2024 08:31, Jani Nikula wrote:

On Thu, 08 Feb 2024, Maxime Ripard  wrote:

On Thu, Feb 08, 2024 at 11:57:11AM +0200, Jani Nikula wrote:

On Wed, 07 Feb 2024, Mario Limonciello  wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.

Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/Kconfig|  5 +++
  drivers/gpu/drm/drm_edid.c | 77 ++
  include/drm/drm_edid.h |  1 +
  3 files changed, 83 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6ec33d36f3a4..ec2bb71e8b36 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86


I think I'll defer to drm maintainers on whether this is okay or
something to be avoided.


It's pretty much the same thing that all the other drivers do right now.
Because the symbol is now used by DRM it needs to do this.

Patch 3 in this version of the series tears it out from all the drivers.





help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..c649b4f9fd8e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,49 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2643,6 +2687,39 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
  }
  EXPORT_SYMBOL(drm_get_edid);
  
+/**

+ * drm_get_acpi_edid - get EDID data, if available


I'd prefer all the new EDID API to be named drm_edid_*. Makes a clean
break from the old API, and is more consistent.

So perhaps drm_edid_read_acpi() to be in line with all the other struct
drm_edid based EDID reading functions.



Roger that.  Even if it ends up not being exported out will rename as such.


+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.
+ *
+ * The returned pointer must be freed using drm_edid_free().
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+const struct drm_edid *drm_get_acpi_edid(struct drm_connector *connector)
+{
+   const struct drm_edid *drm_edid;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return NULL;
+   }
+
+   if (connector->force == DRM_FORCE_OFF)
+   return NULL;
+
+   drm_edid = drm_edid_read_custom(connector, drm_do_probe_acpi_edid, 
connector->dev);
+
+   /* Note: Do *not* call connector updates here. */
+
+   return drm_edid;
+}
+EXPORT_SYMBOL(drm_get_acpi_edid);


Why shouldn't we use the BIOS/UEFI to retrieve them if it's available?

I guess what I'm asking is why should we make this an exported function
that drivers would have to call explicitly, instead of just making it
part of the usual EDI

Re: [PATCH v4 3/3] drm/amd: Drop unneeded functions to check if s3/s0ix active

2024-02-08 Thread Mario Limonciello

On 2/8/2024 00:54, Christian König wrote:

Am 08.02.24 um 06:52 schrieb Mario Limonciello:

amdgpu_acpi_is_s0ix_active() and amdgpu_acpi_is_s0ix_active() aren't
needed to be checked multiple times in a suspend cycle.  Checking and
setting up policy one time in the prepare() callback is sufficient.


Mhm, looking at amdgpu_acpi_is_s3_active() I think we should not cache 
that in a variable in the first place.


Just calling the function all the time to check the state should be 
sufficient, or do we then run into any state transition problems?


I think calling to check it each time is perfectly fine, it should never 
change once the sequence starts until it's over.


If the first 2 patches look OK, I'd like to get those merged so we can 
fix the regressions.  I'll do another series that can drop the cached 
parameters.




Regards,
Christian.



Signed-off-by: Mario Limonciello 
---
v4: New patch
---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h  |  4 
  drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c |  7 +++
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c  | 17 ++---
  3 files changed, 5 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h

index f6c38a974bae..53823539eba5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1545,12 +1545,8 @@ static inline int 
amdgpu_acpi_smart_shift_update(struct drm_device *dev,

  #endif
  #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
-bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
  void amdgpu_choose_low_power_state(struct amdgpu_device *adev);
  #else
-static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device 
*adev) { return false; }
-static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device 
*adev) { return false; }
  static void amdgpu_choose_low_power_state(struct amdgpu_device 
*adev) { }

  #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c

index cc21ed67a330..1d58728f8c3f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1366,8 +1366,7 @@ bool amdgpu_acpi_should_gpu_reset(struct 
amdgpu_device *adev)
  adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU 
enabled APUs */

  return false;
-    if ((adev->flags & AMD_IS_APU) &&
-    amdgpu_acpi_is_s3_active(adev))
+    if ((adev->flags & AMD_IS_APU) && adev->in_s3)
  return false;
  if (amdgpu_sriov_vf(adev))
@@ -1472,7 +1471,7 @@ void amdgpu_acpi_release(void)
   *
   * returns true if supported, false if not.
   */
-bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
+static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
  {
  return !(adev->flags & AMD_IS_APU) ||
  (pm_suspend_target_state == PM_SUSPEND_MEM);
@@ -1485,7 +1484,7 @@ bool amdgpu_acpi_is_s3_active(struct 
amdgpu_device *adev)

   *
   * returns true if supported, false if not.
   */
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
+static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device 
*adev)

  {
  if (!(adev->flags & AMD_IS_APU) ||
  (pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

index 971acf01bea6..2bc4c5bb9b5a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2456,13 +2456,6 @@ static int amdgpu_pmops_prepare(struct device 
*dev)

  pm_runtime_suspended(dev))
  return 1;
-    /* if we will not support s3 or s2i for the device
- *  then skip suspend
- */
-    if (!amdgpu_acpi_is_s0ix_active(adev) &&
-    !amdgpu_acpi_is_s3_active(adev))
-    return 1;
-
  return amdgpu_device_prepare(drm_dev);
  }
@@ -2476,10 +2469,6 @@ static int amdgpu_pmops_suspend(struct device 
*dev)

  struct drm_device *drm_dev = dev_get_drvdata(dev);
  struct amdgpu_device *adev = drm_to_adev(drm_dev);
-    if (amdgpu_acpi_is_s0ix_active(adev))
-    adev->in_s0ix = true;
-    else if (amdgpu_acpi_is_s3_active(adev))
-    adev->in_s3 = true;
  if (!adev->in_s0ix && !adev->in_s3)
  return 0;
  return amdgpu_device_suspend(drm_dev, true);
@@ -2510,10 +2499,8 @@ static int amdgpu_pmops_resume(struct device *dev)
  adev->no_hw_access = true;
  r = amdgpu_device_resume(drm_dev, true);
-    if (amdgpu_acpi_is_s0ix_active(adev))
-    adev->in_s0ix = false;
-    else
-    adev->in_s3 = false;
+    adev->in_s0ix = adev->in_s3 = false;
+
  return r;
  }






Re: [PATCH] drm/buddy: Fix alloc_range() error handling code

2024-02-08 Thread Mario Limonciello

On 2/8/2024 06:06, Arunpravin Paneer Selvam wrote:

Hi Christian,

On 2/8/2024 12:27 PM, Christian König wrote:

Am 07.02.24 um 18:44 schrieb Arunpravin Paneer Selvam:

Few users have observed display corruption when they boot
the machine to KDE Plasma or playing games. We have root
caused the problem that whenever alloc_range() couldn't
find the required memory blocks the function was returning
SUCCESS in some of the corner cases.

The right approach would be if the total allocated size
is less than the required size, the function should
return -ENOSPC.

Gitlab ticket link - 
https://gitlab.freedesktop.org/drm/amd/-/issues/3097


Syntax should be "Closes: $URL"


Fixes: 0a1844bf0b53 ("drm/buddy: Improve contiguous memory allocation")
Signed-off-by: Arunpravin Paneer Selvam 


Tested-by: Mario Limonciello 


Acked-by: Christian König 

CC: stable.. ?

I will check and add the stable kernel version.


Should be 6.7.



Thanks,
Arun.



---
  drivers/gpu/drm/drm_buddy.c | 6 ++
  1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
index f57e6d74fb0e..c1a99bf4dffd 100644
--- a/drivers/gpu/drm/drm_buddy.c
+++ b/drivers/gpu/drm/drm_buddy.c
@@ -539,6 +539,12 @@ static int __alloc_range(struct drm_buddy *mm,
  } while (1);
    list_splice_tail(, blocks);
+
+    if (total_allocated < size) {
+    err = -ENOSPC;
+    goto err_free;
+    }
+
  return 0;
    err_undo:








[PATCH v4 2/3] drm/amd: Stop evicting resources on APUs in suspend

2024-02-07 Thread Mario Limonciello
commit 5095d5418193 ("drm/amd: Evict resources during PM ops prepare()
callback") intentionally moved the eviction of resources to earlier in
the suspend process, but this introduced a subtle change that it occurs
before adev->in_s0ix or adev->in_s3 are set. This meant that APUs
actually started to evict resources at suspend time as well.

Explicitly set s0ix or s3 in the prepare() stage, and unset them if the
prepare() stage failed.

Reported-by: Jürg Billeter 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3132#note_2271038
Fixes: 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
Signed-off-by: Mario Limonciello 
---
v3->v4:
* New function to set s0ix/s3 and explicitly unset in cleanup
v2->v3:
* Whitespace
v1->v2:
* Add and use new in_prepare member
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h|  2 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c   | 15 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 11 +--
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 3d8a48f46b01..f6c38a974bae 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1547,9 +1547,11 @@ static inline int amdgpu_acpi_smart_shift_update(struct 
drm_device *dev,
 #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
 bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
+void amdgpu_choose_low_power_state(struct amdgpu_device *adev);
 #else
 static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { 
return false; }
 static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { 
return false; }
+static void amdgpu_choose_low_power_state(struct amdgpu_device *adev) { }
 #endif
 
 #if defined(CONFIG_DRM_AMD_DC)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 2deebece810e..cc21ed67a330 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1519,4 +1519,19 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device 
*adev)
 #endif /* CONFIG_AMD_PMC */
 }
 
+/**
+ * amdgpu_choose_low_power_state
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * Choose the target low power state for the GPU
+ */
+void amdgpu_choose_low_power_state(struct amdgpu_device *adev)
+{
+   if (amdgpu_acpi_is_s0ix_active(adev))
+   adev->in_s0ix = true;
+   else if (amdgpu_acpi_is_s3_active(adev))
+   adev->in_s3 = true;
+}
+
 #endif /* CONFIG_SUSPEND */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 2bc460cb993d..dab03865c827 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4518,13 +4518,15 @@ int amdgpu_device_prepare(struct drm_device *dev)
struct amdgpu_device *adev = drm_to_adev(dev);
int i, r;
 
+   amdgpu_choose_low_power_state(adev);
+
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
 
/* Evict the majority of BOs before starting suspend sequence */
r = amdgpu_device_evict_resources(adev);
if (r)
-   return r;
+   goto unprepare;
 
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
@@ -4533,10 +4535,15 @@ int amdgpu_device_prepare(struct drm_device *dev)
continue;
r = adev->ip_blocks[i].version->funcs->prepare_suspend((void 
*)adev);
if (r)
-   return r;
+   goto unprepare;
}
 
return 0;
+
+unprepare:
+   adev->in_s0ix = adev->in_s3 = false;
+
+   return r;
 }
 
 /**
-- 
2.34.1



[PATCH v4 3/3] drm/amd: Drop unneeded functions to check if s3/s0ix active

2024-02-07 Thread Mario Limonciello
amdgpu_acpi_is_s0ix_active() and amdgpu_acpi_is_s0ix_active() aren't
needed to be checked multiple times in a suspend cycle.  Checking and
setting up policy one time in the prepare() callback is sufficient.

Signed-off-by: Mario Limonciello 
---
v4: New patch
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h  |  4 
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c |  7 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c  | 17 ++---
 3 files changed, 5 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index f6c38a974bae..53823539eba5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1545,12 +1545,8 @@ static inline int amdgpu_acpi_smart_shift_update(struct 
drm_device *dev,
 #endif
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
-bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
 void amdgpu_choose_low_power_state(struct amdgpu_device *adev);
 #else
-static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { 
return false; }
-static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { 
return false; }
 static void amdgpu_choose_low_power_state(struct amdgpu_device *adev) { }
 #endif
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index cc21ed67a330..1d58728f8c3f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1366,8 +1366,7 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device 
*adev)
adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU enabled 
APUs */
return false;
 
-   if ((adev->flags & AMD_IS_APU) &&
-   amdgpu_acpi_is_s3_active(adev))
+   if ((adev->flags & AMD_IS_APU) && adev->in_s3)
return false;
 
if (amdgpu_sriov_vf(adev))
@@ -1472,7 +1471,7 @@ void amdgpu_acpi_release(void)
  *
  * returns true if supported, false if not.
  */
-bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
+static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
 {
return !(adev->flags & AMD_IS_APU) ||
(pm_suspend_target_state == PM_SUSPEND_MEM);
@@ -1485,7 +1484,7 @@ bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
  *
  * returns true if supported, false if not.
  */
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
+static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
 {
if (!(adev->flags & AMD_IS_APU) ||
(pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 971acf01bea6..2bc4c5bb9b5a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2456,13 +2456,6 @@ static int amdgpu_pmops_prepare(struct device *dev)
pm_runtime_suspended(dev))
return 1;
 
-   /* if we will not support s3 or s2i for the device
-*  then skip suspend
-*/
-   if (!amdgpu_acpi_is_s0ix_active(adev) &&
-   !amdgpu_acpi_is_s3_active(adev))
-   return 1;
-
return amdgpu_device_prepare(drm_dev);
 }
 
@@ -2476,10 +2469,6 @@ static int amdgpu_pmops_suspend(struct device *dev)
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(drm_dev);
 
-   if (amdgpu_acpi_is_s0ix_active(adev))
-   adev->in_s0ix = true;
-   else if (amdgpu_acpi_is_s3_active(adev))
-   adev->in_s3 = true;
if (!adev->in_s0ix && !adev->in_s3)
return 0;
return amdgpu_device_suspend(drm_dev, true);
@@ -2510,10 +2499,8 @@ static int amdgpu_pmops_resume(struct device *dev)
adev->no_hw_access = true;
 
r = amdgpu_device_resume(drm_dev, true);
-   if (amdgpu_acpi_is_s0ix_active(adev))
-   adev->in_s0ix = false;
-   else
-   adev->in_s3 = false;
+   adev->in_s0ix = adev->in_s3 = false;
+
return r;
 }
 
-- 
2.34.1



[PATCH v4 1/3] Revert "drm/amd: flush any delayed gfxoff on suspend entry"

2024-02-07 Thread Mario Limonciello
commit ab4750332dbe ("drm/amdgpu/sdma5.2: add begin/end_use ring
callbacks") caused GFXOFF control to be used more heavily and the
codepath that was removed from commit 0dee72639533 ("drm/amd: flush any
delayed gfxoff on suspend entry") now can be exercised at suspend again.

Users report that by using GNOME to suspend the lockscreen trigger will
cause SDMA traffic and the system can deadlock.

This reverts commit 0dee726395333fea833eaaf838bc80962df886c8.

Acked-by: Alex Deucher 
Fixes: ab4750332dbe ("drm/amdgpu/sdma5.2: add begin/end_use ring callbacks")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 1 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c| 9 -
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 670ecb789d59..2bc460cb993d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4573,7 +4573,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool 
fbcon)

drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
 
cancel_delayed_work_sync(>delayed_init_work);
-   flush_delayed_work(>gfx.gfx_off_delay_work);
 
amdgpu_ras_suspend(adev);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index aa8e1d29d10a..9831dd854532 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -727,8 +727,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool 
enable)
 
if (adev->gfx.gfx_off_req_count == 0 &&
!adev->gfx.gfx_off_state) {
-   schedule_delayed_work(>gfx.gfx_off_delay_work,
+   /* If going to s2idle, no need to wait */
+   if (adev->in_s0ix) {
+   if (!amdgpu_dpm_set_powergating_by_smu(adev,
+   AMD_IP_BLOCK_TYPE_GFX, true))
+   adev->gfx.gfx_off_state = true;
+   } else {
+   
schedule_delayed_work(>gfx.gfx_off_delay_work,
  delay);
+   }
}
} else {
if (adev->gfx.gfx_off_req_count == 0) {
-- 
2.34.1



[PATCH v4 3/3] drm: Drop unneeded selects in DRM drivers

2024-02-07 Thread Mario Limonciello
All of the selects on ACPI_VIDEO are unnecessary when DRM does the
select for ACPI_VIDEO as it provides a helper for acpi based EDID.

Reviewed-by: Pranjal Ramajor Asha Kanojiya 
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/Kconfig | 7 ---
 drivers/gpu/drm/gma500/Kconfig | 6 --
 drivers/gpu/drm/i915/Kconfig   | 7 ---
 drivers/gpu/drm/nouveau/Kconfig| 4 
 drivers/gpu/drm/radeon/Kconfig | 7 ---
 drivers/gpu/drm/xe/Kconfig | 6 --
 6 files changed, 37 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 22d88f8ef527..b2178a5a947c 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -22,13 +22,6 @@ config DRM_AMDGPU
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
-   # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
-   # ACPI_VIDEO's dependencies must also be selected.
-   select INPUT if ACPI
-   select ACPI_VIDEO if ACPI
-   # On x86 ACPI_VIDEO also needs ACPI_WMI
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
help
  Choose this option if you have a recent AMD Radeon graphics card.
 
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index efb4a2dd2f80..6921ef67b256 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -6,12 +6,6 @@ config DRM_GMA500
select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION
select I2C
select I2C_ALGOBIT
-   # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
-   select ACPI_VIDEO if ACPI
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
help
  Say yes for an experimental 2D KMS framebuffer driver for the
  Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index b5d6e3352071..476da09433bb 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -22,13 +22,6 @@ config DRM_I915
select I2C
select I2C_ALGOBIT
select IRQ_WORK
-   # i915 depends on ACPI_VIDEO when ACPI is enabled
-   # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
-   select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
select SYNC_FILE
select IOSF_MBI if X86
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 1e6aaf95ff7c..61f531abd3e3 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -20,11 +20,7 @@ config DRM_NOUVEAU
select ACPI_WMI if ACPI && X86
select MXM_WMI if ACPI && X86
select POWER_SUPPLY
-   # Similar to i915, we need to select ACPI_VIDEO and it's dependencies
-   select BACKLIGHT_CLASS_DEVICE if ACPI && X86
-   select INPUT if ACPI && X86
select THERMAL if ACPI && X86
-   select ACPI_VIDEO if ACPI && X86
select SND_HDA_COMPONENT if SND_HDA_CORE
help
  Choose this option for open-source NVIDIA support.
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index f98356be0af2..12149d594100 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -19,13 +19,6 @@ config DRM_RADEON
select INTERVAL_TREE
select I2C
select I2C_ALGOBIT
-   # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
-   # ACPI_VIDEO's dependencies must also be selected.
-   select INPUT if ACPI
-   select ACPI_VIDEO if ACPI
-   # On x86 ACPI_VIDEO also needs ACPI_WMI
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
help
  Choose this option if you have an ATI Radeon graphics card.  There
  are both PCI and AGP versions.  You don't need to choose this to
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index e36ae1f0d885..cf60bdcafb0c 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -19,13 +19,7 @@ config DRM_XE
select DRM_MIPI_DSI
select RELAY
select IRQ_WORK
-   # xe depends on ACPI_VIDEO when ACPI is enabled
-   # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select ACPI_VIDEO if X86 && ACPI
select ACPI_BUTTON if ACPI
-   select ACPI_WMI if X86 && ACPI
select SYNC_FILE
select IOSF_MBI
select CRC32
-- 
2.34.1



[PATCH v4 1/3] drm: Add drm_get_acpi_edid() helper

2024-02-07 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/Kconfig|  5 +++
 drivers/gpu/drm/drm_edid.c | 77 ++
 include/drm/drm_edid.h |  1 +
 3 files changed, 83 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6ec33d36f3a4..ec2bb71e8b36 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86
help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..c649b4f9fd8e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -2188,6 +2189,49 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
 }
 
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = -EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+
+cleanup:
+   kfree(edid);
+
+   return r;
+}
+
 static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
 {
@@ -2643,6 +2687,39 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+/**
+ * drm_get_acpi_edid - get EDID data, if available
+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.
+ *
+ * The returned pointer must be freed using drm_edid_free().
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+const struct drm_edid *drm_get_acpi_edid(struct drm_connector *connector)
+{
+   const struct drm_edid *drm_edid;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return NULL;
+   }
+
+   if (connector->force == DRM_FORCE_OFF)
+   return NULL;
+
+   drm_edid = drm_edid_read_custom(connector, drm_do_probe_acpi_edid, 
connector->dev);
+
+   /* Note: Do *not* call connector updates here. */
+
+   return drm_edid;
+}
+EXPORT_SYMBOL(drm_get_acpi_edid);
+
 /**
  * drm_edid_read_custom - Read EDID data using given EDID block read function
  * @connector: Connector to use
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 7923bc00dc7a..ca41be289fc6 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -410,6 +410,7 @@ struct edid *drm_do_get_edid(struct drm_connector 
*connector,
void *data);
 struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
+const struct drm_edid *drm_get_acpi_edid(struct drm_connector *connector);
 u32 drm_edid_get_panel_id(struct i2c_adapter *adapter);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
-- 
2.34.1



[PATCH v4 2/3] drm/nouveau: Use drm_get_acpi_edid() helper

2024-02-07 Thread Mario Limonciello
Rather than inventing a wrapper to acpi_video_get_edid() use the
one provided by drm. This fixes two problems:
1. A memory leak that the memory provided by the ACPI call was
   never freed.
2. Validation of the BIOS provided blob.

Convert the usage in nouveau_connector_detect_lvds() to use
struct drm_edid at the same time.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c  | 27 -
 drivers/gpu/drm/nouveau/nouveau_acpi.h  |  2 --
 drivers/gpu/drm/nouveau/nouveau_connector.c | 20 +++
 3 files changed, 9 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 8f0c69aad248..de9daafb3fbb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -360,33 +360,6 @@ void nouveau_unregister_dsm_handler(void) {}
 void nouveau_switcheroo_optimus_dsm(void) {}
 #endif
 
-void *
-nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
-{
-   struct acpi_device *acpidev;
-   int type, ret;
-   void *edid;
-
-   switch (connector->connector_type) {
-   case DRM_MODE_CONNECTOR_LVDS:
-   case DRM_MODE_CONNECTOR_eDP:
-   type = ACPI_VIDEO_DISPLAY_LCD;
-   break;
-   default:
-   return NULL;
-   }
-
-   acpidev = ACPI_COMPANION(dev->dev);
-   if (!acpidev)
-   return NULL;
-
-   ret = acpi_video_get_edid(acpidev, type, -1, );
-   if (ret < 0)
-   return NULL;
-
-   return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-}
-
 bool nouveau_acpi_video_backlight_use_native(void)
 {
return acpi_video_backlight_use_native();
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h 
b/drivers/gpu/drm/nouveau/nouveau_acpi.h
index e39dd8b94b8b..6a3def8e6cca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.h
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h
@@ -10,7 +10,6 @@ bool nouveau_is_v1_dsm(void);
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
 void nouveau_switcheroo_optimus_dsm(void);
-void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 bool nouveau_acpi_video_backlight_use_native(void);
 void nouveau_acpi_video_register_backlight(void);
 #else
@@ -19,7 +18,6 @@ static inline bool nouveau_is_v1_dsm(void) { return false; };
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
 static inline void nouveau_switcheroo_optimus_dsm(void) {}
-static inline void *nouveau_acpi_edid(struct drm_device *dev, struct 
drm_connector *connector) { return NULL; }
 static inline bool nouveau_acpi_video_backlight_use_native(void) { return 
true; }
 static inline void nouveau_acpi_video_register_backlight(void) {}
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 856b3ef5edb8..4c47d231c65e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -687,7 +687,7 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
-   struct edid *edid = NULL;
+   const struct drm_edid *drm_edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
 
nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
@@ -698,7 +698,7 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
if (!drm->vbios.fp_no_ddc) {
status = nouveau_connector_detect(connector, force);
if (status == connector_status_connected) {
-   edid = nv_connector->edid;
+   drm_edid = drm_edid_alloc(nv_connector->edid, 
EDID_LENGTH);
goto out;
}
}
@@ -713,8 +713,8 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
 * valid - it's not (rh#613284)
 */
if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-   edid = nouveau_acpi_edid(dev, connector);
-   if (edid) {
+   drm_edid = drm_get_acpi_edid(connector);
+   if (drm_edid) {
status = connector_status_connected;
goto out;
}
@@ -734,12 +734,9 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
 * stored for the panel stored in them.
 */
if (!drm->vbios.fp_no_ddc) {
-   edid = (struct edid *)nouveau_bios_embedded_edid(dev);
-   if (edid) {
-   edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-   if (edid)
-  

[PATCH v4 0/3] Add drm_get_acpi_edid() helper

2024-02-07 Thread Mario Limonciello
The drm_get_acpi_edid() helper is for drivers that would prefer
to get the EDID from ACPI instead of from the panel.

Earlier versions of this series were aimed at using this in amdgpu
and nouveau.

This version does NOT update amdgpu as the change will require a
larger overhaul to use struct drm_edid. There will be a follow up
patch to amdgpu after Melissa Wen finishes that effort [2].

https://lore.kernel.org/dri-devel/20240201221119.42564-1-mario.limoncie...@amd.com/
 [1]
https://lore.kernel.org/amd-gfx/20240126163429.56714-1-m...@igalia.com/ [2]
Mario Limonciello (3):
  drm: Add drm_get_acpi_edid() helper
  drm/nouveau: Use drm_get_acpi_edid() helper
  drm: Drop unneeded selects in DRM drivers

 drivers/gpu/drm/Kconfig |  5 ++
 drivers/gpu/drm/amd/amdgpu/Kconfig  |  7 --
 drivers/gpu/drm/drm_edid.c  | 77 +
 drivers/gpu/drm/gma500/Kconfig  |  6 --
 drivers/gpu/drm/i915/Kconfig|  7 --
 drivers/gpu/drm/nouveau/Kconfig |  4 --
 drivers/gpu/drm/nouveau/nouveau_acpi.c  | 27 
 drivers/gpu/drm/nouveau/nouveau_acpi.h  |  2 -
 drivers/gpu/drm/nouveau/nouveau_connector.c | 20 +++---
 drivers/gpu/drm/radeon/Kconfig  |  7 --
 drivers/gpu/drm/xe/Kconfig  |  6 --
 include/drm/drm_edid.h  |  1 +
 12 files changed, 92 insertions(+), 77 deletions(-)

-- 
2.34.1



Re: [PATCH v2 2/2] drm/amd: Stop evicting resources on APUs in suspend

2024-02-07 Thread Mario Limonciello

On 2/7/2024 16:34, Alex Deucher wrote:

On Wed, Feb 7, 2024 at 3:48 PM Mario Limonciello
 wrote:


commit 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
intentionally moved the eviction of resources to earlier in the suspend
process, but this introduced a subtle change that it occurs before adev->in_s0ix
or adev->in_s3 are set. This meant that APUs actually started to evict
resources at suspend time as well.

Add a new `in_prepare` flag that is set for the life of the prepare() callback
to return the old code flow. Drop the existing call to return 1 in this case 
because
the suspend() callback looks for the flags too.

Also, introduce a new amdgpu_device_freeze() function to call at S4 and evict
resources in this callback so that APUs will still get resources evicted.

Reported-by: Jürg Billeter 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3132#note_2271038
Fixes: 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
Signed-off-by: Mario Limonciello 
---
v1->v2:
  * Add and use new in_prepare member
---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 46 --
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c| 21 ++
  3 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 5d5be3e20687..f9db09a9017a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1075,7 +1075,8 @@ struct amdgpu_device {
 u8  reset_magic[AMDGPU_RESET_MAGIC_NUM];

 /* s3/s4 mask */
-   boolin_suspend;
+   boolin_prepare;
+   boolin_suspend;
 boolin_s3;
 boolin_s4;
 boolin_s0ix;
@@ -1462,6 +1463,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev);
  int amdgpu_device_prepare(struct drm_device *dev);
  int amdgpu_device_suspend(struct drm_device *dev, bool fbcon);
  int amdgpu_device_resume(struct drm_device *dev, bool fbcon);
+int amdgpu_device_freeze(struct drm_device *drm_dev);
  u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc);
  int amdgpu_enable_vblank_kms(struct drm_crtc *crtc);
  void amdgpu_disable_vblank_kms(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 2bc460cb993d..0a337fcd89b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4492,7 +4492,7 @@ static int amdgpu_device_evict_resources(struct 
amdgpu_device *adev)
 int ret;

 /* No need to evict vram on APUs for suspend to ram or s2idle */
-   if ((adev->in_s3 || adev->in_s0ix) && (adev->flags & AMD_IS_APU))
+   if ((adev->in_prepare) && (adev->flags & AMD_IS_APU))


Could probably simplify this to:
if ((!adev->in_s4) && (adev->flags & AMD_IS_APU))

Then you could drop the in_prepare variable.


 return 0;

 ret = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM);
@@ -4521,10 +4521,12 @@ int amdgpu_device_prepare(struct drm_device *dev)
 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
 return 0;

+   adev->in_prepare = true;
+
 /* Evict the majority of BOs before starting suspend sequence */
 r = amdgpu_device_evict_resources(adev);
 if (r)
-   return r;
+   goto unprepare;

 for (i = 0; i < adev->num_ip_blocks; i++) {
 if (!adev->ip_blocks[i].status.valid)
@@ -4533,10 +4535,46 @@ int amdgpu_device_prepare(struct drm_device *dev)
 continue;
 r = adev->ip_blocks[i].version->funcs->prepare_suspend((void 
*)adev);
 if (r)
-   return r;
+   goto unprepare;
 }

-   return 0;
+unprepare:
+   adev->in_prepare = FALSE;
+
+   return r;
+}
+
+/**
+ * amdgpu_device_freeze - run S4 sequence
+ *
+ * @dev: drm dev pointer
+ *
+ * Prepare to put the hw in the S4 state (all asics).
+ * Returns 0 for success or an error on failure.
+ * Called at driver freeze.
+ */
+int amdgpu_device_freeze(struct drm_device *drm_dev)
+{
+   struct amdgpu_device *adev = drm_to_adev(drm_dev);
+   int r;
+
+   adev->in_s4 = true;
+
+   r = amdgpu_device_evict_resources(adev);


Won't this be too late to allocate memory?  Doesn't this need to
happen in prepare() even for S4?


Hmm; possibly.  I'll swap it back with your other suggestion.

Thanks


Alex


+   if (r)
+   goto cleanup;
+
+   r = amdgpu_device_suspend(drm_dev, tru

[PATCH v2 2/2] drm/amd: Stop evicting resources on APUs in suspend

2024-02-07 Thread Mario Limonciello
commit 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
intentionally moved the eviction of resources to earlier in the suspend
process, but this introduced a subtle change that it occurs before adev->in_s0ix
or adev->in_s3 are set. This meant that APUs actually started to evict
resources at suspend time as well.

Add a new `in_prepare` flag that is set for the life of the prepare() callback
to return the old code flow. Drop the existing call to return 1 in this case 
because
the suspend() callback looks for the flags too.

Also, introduce a new amdgpu_device_freeze() function to call at S4 and evict
resources in this callback so that APUs will still get resources evicted.

Reported-by: Jürg Billeter 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3132#note_2271038
Fixes: 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Add and use new in_prepare member
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 46 --
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c| 21 ++
 3 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 5d5be3e20687..f9db09a9017a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1075,7 +1075,8 @@ struct amdgpu_device {
u8  reset_magic[AMDGPU_RESET_MAGIC_NUM];
 
/* s3/s4 mask */
-   boolin_suspend;
+   boolin_prepare;
+   boolin_suspend;
boolin_s3;
boolin_s4;
boolin_s0ix;
@@ -1462,6 +1463,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev);
 int amdgpu_device_prepare(struct drm_device *dev);
 int amdgpu_device_suspend(struct drm_device *dev, bool fbcon);
 int amdgpu_device_resume(struct drm_device *dev, bool fbcon);
+int amdgpu_device_freeze(struct drm_device *drm_dev);
 u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc);
 int amdgpu_enable_vblank_kms(struct drm_crtc *crtc);
 void amdgpu_disable_vblank_kms(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 2bc460cb993d..0a337fcd89b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4492,7 +4492,7 @@ static int amdgpu_device_evict_resources(struct 
amdgpu_device *adev)
int ret;
 
/* No need to evict vram on APUs for suspend to ram or s2idle */
-   if ((adev->in_s3 || adev->in_s0ix) && (adev->flags & AMD_IS_APU))
+   if ((adev->in_prepare) && (adev->flags & AMD_IS_APU))
return 0;
 
ret = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM);
@@ -4521,10 +4521,12 @@ int amdgpu_device_prepare(struct drm_device *dev)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
 
+   adev->in_prepare = true;
+
/* Evict the majority of BOs before starting suspend sequence */
r = amdgpu_device_evict_resources(adev);
if (r)
-   return r;
+   goto unprepare;
 
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
@@ -4533,10 +4535,46 @@ int amdgpu_device_prepare(struct drm_device *dev)
continue;
r = adev->ip_blocks[i].version->funcs->prepare_suspend((void 
*)adev);
if (r)
-   return r;
+   goto unprepare;
}
 
-   return 0;
+unprepare:
+   adev->in_prepare = FALSE;
+
+   return r;
+}
+
+/**
+ * amdgpu_device_freeze - run S4 sequence
+ *
+ * @dev: drm dev pointer
+ *
+ * Prepare to put the hw in the S4 state (all asics).
+ * Returns 0 for success or an error on failure.
+ * Called at driver freeze.
+ */
+int amdgpu_device_freeze(struct drm_device *drm_dev)
+{
+   struct amdgpu_device *adev = drm_to_adev(drm_dev);
+   int r;
+
+   adev->in_s4 = true;
+
+   r = amdgpu_device_evict_resources(adev);
+   if (r)
+   goto cleanup;
+
+   r = amdgpu_device_suspend(drm_dev, true);
+   if (r)
+   goto cleanup;
+
+   if (amdgpu_acpi_should_gpu_reset(adev))
+   r = amdgpu_asic_reset(adev);
+
+cleanup:
+   adev->in_s4 = false;
+
+   return r;
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index b74f68a15802..fc9caa14c9d6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2456,6

[PATCH v2 1/2] Revert "drm/amd: flush any delayed gfxoff on suspend entry"

2024-02-07 Thread Mario Limonciello
commit ab4750332dbe ("drm/amdgpu/sdma5.2: add begin/end_use ring callbacks")
caused GFXOFF control to be used more heavily and the codepath that was
removed from commit 0dee72639533 ("drm/amd: flush any delayed gfxoff on
suspend entry") now can be exercised at suspend again.

Users report that by using GNOME to suspend the lockscreen trigger will
cause SDMA traffic and the system can deadlock.

This reverts commit 0dee726395333fea833eaaf838bc80962df886c8.

Fixes: ab4750332dbe ("drm/amdgpu/sdma5.2: add begin/end_use ring callbacks")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 1 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c| 9 -
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 670ecb789d59..2bc460cb993d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4573,7 +4573,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool 
fbcon)

drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
 
cancel_delayed_work_sync(>delayed_init_work);
-   flush_delayed_work(>gfx.gfx_off_delay_work);
 
amdgpu_ras_suspend(adev);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index aa8e1d29d10a..9831dd854532 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -727,8 +727,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool 
enable)
 
if (adev->gfx.gfx_off_req_count == 0 &&
!adev->gfx.gfx_off_state) {
-   schedule_delayed_work(>gfx.gfx_off_delay_work,
+   /* If going to s2idle, no need to wait */
+   if (adev->in_s0ix) {
+   if (!amdgpu_dpm_set_powergating_by_smu(adev,
+   AMD_IP_BLOCK_TYPE_GFX, true))
+   adev->gfx.gfx_off_state = true;
+   } else {
+   
schedule_delayed_work(>gfx.gfx_off_delay_work,
  delay);
+   }
}
} else {
if (adev->gfx.gfx_off_req_count == 0) {
-- 
2.34.1



Re: [PATCH] drm/amd: Set s0i3/s3 in prepare() callback instead of suspend() callback

2024-02-06 Thread Mario Limonciello

On 2/6/2024 16:00, Deucher, Alexander wrote:

[AMD Official Use Only - General]


-Original Message-
From: amd-gfx  On Behalf Of Mario
Limonciello
Sent: Tuesday, February 6, 2024 4:32 PM
To: amd-gfx@lists.freedesktop.org
Cc: Limonciello, Mario ; Jürg Billeter

Subject: [PATCH] drm/amd: Set s0i3/s3 in prepare() callback instead of
suspend() callback

commit 5095d5418193 ("drm/amd: Evict resources during PM ops prepare()
callback") intentionally moved the eviction of resources to earlier in the
suspend process, but this introduced a subtle change that it occurs before
adev->in_s0ix or adev->in_s3 are set. This meant that APUs actually started to
evict resources at suspend time as well.

Move the s0i3/s3 setting flags into prepare() to ensure that they're set during
eviction. Drop the existing call to return 1 in this case because the suspend()
callback looks for the flags too.

Reported-by: Jürg Billeter 
Closes: https://gitlab.freedesktop.org/drm/amd/-
/issues/3132#note_2271038
Fixes: 5095d5418193 ("drm/amd: Evict resources during PM ops prepare()
callback")
Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 14 --
  1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index b74f68a15802..190b2ee9e36b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2464,12 +2464,10 @@ static int amdgpu_pmops_prepare(struct device
*dev)
   pm_runtime_suspended(dev))
   return 1;

- /* if we will not support s3 or s2i for the device
-  *  then skip suspend
-  */
- if (!amdgpu_acpi_is_s0ix_active(adev) &&
- !amdgpu_acpi_is_s3_active(adev))
- return 1;
+ if (amdgpu_acpi_is_s0ix_active(adev))
+ adev->in_s0ix = true;
+ else if (amdgpu_acpi_is_s3_active(adev))
+ adev->in_s3 = true;



Will resume always get called to clear these after after prepare?  Will these 
ever get set and then not unset?


You're right; it doesn't clean up.

This is the call sequence:

suspend_devices_and_enter()
->dpm_suspend_start()
->->device_prepare()
->->->dpm_prepare()

Errors bubble up.  In suspend_devices_and_enter() errors goto 
Recover_platform label.  This calls platform_recover().


platform_recover() is for platform recovery not device recovery.
So this patch is incorrect.

Let me see if I can come up with another way to do this without having 
to revert 5095d5418193.




Alex


   return amdgpu_device_prepare(drm_dev);  } @@ -2484,10 +2482,6
@@ static int amdgpu_pmops_suspend(struct device *dev)
   struct drm_device *drm_dev = dev_get_drvdata(dev);
   struct amdgpu_device *adev = drm_to_adev(drm_dev);

- if (amdgpu_acpi_is_s0ix_active(adev))
- adev->in_s0ix = true;
- else if (amdgpu_acpi_is_s3_active(adev))
- adev->in_s3 = true;
   if (!adev->in_s0ix && !adev->in_s3)
   return 0;
   return amdgpu_device_suspend(drm_dev, true);
--
2.34.1






[PATCH] drm/amd: Set s0i3/s3 in prepare() callback instead of suspend() callback

2024-02-06 Thread Mario Limonciello
commit 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
intentionally moved the eviction of resources to earlier in the suspend
process, but this introduced a subtle change that it occurs before adev->in_s0ix
or adev->in_s3 are set. This meant that APUs actually started to evict
resources at suspend time as well.

Move the s0i3/s3 setting flags into prepare() to ensure that they're set
during eviction. Drop the existing call to return 1 in this case because
the suspend() callback looks for the flags too.

Reported-by: Jürg Billeter 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3132#note_2271038
Fixes: 5095d5418193 ("drm/amd: Evict resources during PM ops prepare() 
callback")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index b74f68a15802..190b2ee9e36b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2464,12 +2464,10 @@ static int amdgpu_pmops_prepare(struct device *dev)
pm_runtime_suspended(dev))
return 1;
 
-   /* if we will not support s3 or s2i for the device
-*  then skip suspend
-*/
-   if (!amdgpu_acpi_is_s0ix_active(adev) &&
-   !amdgpu_acpi_is_s3_active(adev))
-   return 1;
+   if (amdgpu_acpi_is_s0ix_active(adev))
+   adev->in_s0ix = true;
+   else if (amdgpu_acpi_is_s3_active(adev))
+   adev->in_s3 = true;
 
return amdgpu_device_prepare(drm_dev);
 }
@@ -2484,10 +2482,6 @@ static int amdgpu_pmops_suspend(struct device *dev)
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(drm_dev);
 
-   if (amdgpu_acpi_is_s0ix_active(adev))
-   adev->in_s0ix = true;
-   else if (amdgpu_acpi_is_s3_active(adev))
-   adev->in_s3 = true;
if (!adev->in_s0ix && !adev->in_s3)
return 0;
return amdgpu_device_suspend(drm_dev, true);
-- 
2.34.1



[PATCH] drm/amd/display: Disable PSR-SU on Parade 08-01 TCON too

2024-02-05 Thread Mario Limonciello
Stuart Hayhurst has found that both at bootup and fullscreen VA-API video
is leading to black screens for around 1 second and kernel WARNING [1] traces
when calling dmub_psr_enable() with Parade 08-01 TCON.

These symptoms all go away with PSR-SU disabled for this TCON, so disable
it for now while DMUB traces [2] from the failure can be analyzed and the 
failure
state properly root caused.

Cc: sta...@vger.kernel.org
Cc: Marc Rossi 
Cc: Hamza Mahfooz 
Link: 
https://gitlab.freedesktop.org/drm/amd/uploads/a832dd515b571ee171b3e3b566e99a13/dmesg.log
 [1]
Link: 
https://gitlab.freedesktop.org/drm/amd/uploads/8f13ff3b00963c833e23e68aa8116959/output.log
 [2]
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/2645
Signed-off-by: Mario Limonciello 
---
---
 drivers/gpu/drm/amd/display/modules/power/power_helpers.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c 
b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
index e304e8435fb8..477289846a0a 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -841,6 +841,8 @@ bool is_psr_su_specific_panel(struct dc_link *link)
isPSRSUSupported = false;
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && 
dpcd_caps->sink_dev_id_str[0] == 0x03)
isPSRSUSupported = false;
+   else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && 
dpcd_caps->sink_dev_id_str[0] == 0x01)
+   isPSRSUSupported = false;
else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1)
isPSRSUSupported = true;
}
-- 
2.34.1



[PATCH] drm/amd/display: Force full frame updates on DP 38-ec-11

2024-02-03 Thread Mario Limonciello
The 38-ec-11 TCON contained in some AUO panels will hang when used
with PSR-SU and changing the brightness.

Forcing a full frame update works around the issue, so add a quirk
for this panel to do just that.

Reported-by: aaron...@canonical.com
Signed-off-by: Mario Limonciello 
---
Cc: hamza.mahf...@amd.com
Cc: mpearson-len...@squebb.ca

 drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 30 ++-
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c 
b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
index 3e243e407bb8..68c619b43cbf 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
@@ -36,6 +36,7 @@
 static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3};
 static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5};
 static const uint8_t DP_SINK_DEVICE_STR_ID_3[] = {0x42, 0x61, 0x6c, 0x73, 
0x61};
+static const uint8_t DP_SINK_DEVICE_STR_ID_4[] = {0x0, 0x0, 0x0, 0x0, 0x0};
 
 /*
  * Convert dmcub psr state to dmcu psr state.
@@ -284,6 +285,25 @@ static void dmub_psr_set_power_opt(struct dmub_psr *dmub, 
unsigned int power_opt
dc_wake_and_execute_dmub_cmd(dc, , DM_DMUB_WAIT_TYPE_WAIT);
 }
 
+static bool dmub_psr_need_force_ffu(bool dsc_enable_status, struct dc_link 
*link)
+{
+   if (link->dpcd_caps.sink_dev_id != DP_DEVICE_ID_38EC11)
+   return false;
+
+   /**
+* WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as 
ffu mode(full frame update)
+* Note that PSRSU+DSC is still under development.
+*/
+   if (dsc_enable_status &&
+   !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1,
+   sizeof(DP_SINK_DEVICE_STR_ID_1)))
+   return true;
+   if (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_4,
+   sizeof(DP_SINK_DEVICE_STR_ID_4)))
+   return true;
+
+   return false;
+}
 /*
  * Setup PSR by programming phy registers and sending psr hw context values to 
firmware.
  */
@@ -378,14 +398,8 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
copy_settings_data->panel_inst = panel_inst;
copy_settings_data->dsc_enable_status = 
(pipe_ctx->stream->timing.flags.DSC == 1);
 
-   /**
-* WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as 
ffu mode(full frame update)
-* Note that PSRSU+DSC is still under development.
-*/
-   if (copy_settings_data->dsc_enable_status &&
-   link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 &&
-   !memcmp(link->dpcd_caps.sink_dev_id_str, 
DP_SINK_DEVICE_STR_ID_1,
-   sizeof(DP_SINK_DEVICE_STR_ID_1)))
+
+   if (dmub_psr_need_force_ffu(copy_settings_data->dsc_enable_status, 
link))
link->psr_settings.force_ffu_mode = 1;
else
link->psr_settings.force_ffu_mode = 0;
-- 
2.34.1



[PATCH] drm/amd/display: Clear phantom stream count and plane count

2024-02-02 Thread Mario Limonciello
When dc_state_destruct() was refactored the new phantom_stream_count
and phantom_plane_count members weren't cleared.

Fixes: 012a04b1d6af ("drm/amd/display: Refactor phantom resource allocation")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/dc/core/dc_state.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index 88c6436b28b6..180ac47868c2 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -291,11 +291,14 @@ void dc_state_destruct(struct dc_state *state)
dc_stream_release(state->phantom_streams[i]);
state->phantom_streams[i] = NULL;
}
+   state->phantom_stream_count = 0;
 
for (i = 0; i < state->phantom_plane_count; i++) {
dc_plane_state_release(state->phantom_planes[i]);
state->phantom_planes[i] = NULL;
}
+   state->phantom_plane_count = 0;
+
state->stream_mask = 0;
memset(>res_ctx, 0, sizeof(state->res_ctx));
memset(>pp_display_cfg, 0, sizeof(state->pp_display_cfg));
-- 
2.34.1



Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-02 Thread Mario Limonciello

On 2/2/2024 09:28, Hamza Mahfooz wrote:

We want programs besides the compositor to be able to enable or disable
panel power saving features. However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.

Cc: Mario Limonciello 
Signed-off-by: Hamza Mahfooz 


Reviewed-by: Mario Limonciello 
Tested-by: Mario Limonciello 


---
v2: hide ABM_LEVEL_IMMEDIATE_DISABLE in the read case, force an atomic
 commit when setting the value, call sysfs_remove_group() in
 amdgpu_dm_connector_unregister() and add some documentation.
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 76 +++
  1 file changed, 76 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 8590c9f1dda6..3c62489d03dc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6436,10 +6436,79 @@ int amdgpu_dm_connector_atomic_get_property(struct 
drm_connector *connector,
return ret;
  }
  
+/**

+ * DOC: panel power savings
+ *
+ * The display manager allows you to set your desired **panel power savings**
+ * level (between 0-4, with 0 representing off), e.g. using the following::
+ *
+ *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
+ *
+ * Modifying this value can have implications on color accuracy, so tread
+ * carefully.
+ */
+
+static ssize_t panel_power_savings_show(struct device *device,
+   struct device_attribute *attr,
+   char *buf)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   u8 val;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   val = to_dm_connector_state(connector->state)->abm_level ==
+   ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
+   to_dm_connector_state(connector->state)->abm_level;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   return sysfs_emit(buf, "%u\n", val);
+}
+
+static ssize_t panel_power_savings_store(struct device *device,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   long val;
+   int ret;
+
+   ret = kstrtol(buf, 0, );
+
+   if (ret)
+   return ret;
+
+   if (val < 0 || val > 4)
+   return -EINVAL;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   to_dm_connector_state(connector->state)->abm_level = val ?:
+   ABM_LEVEL_IMMEDIATE_DISABLE;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   drm_kms_helper_hotplug_event(dev);
+
+   return count;
+}
+
+static DEVICE_ATTR_RW(panel_power_savings);
+
+static struct attribute *amdgpu_attrs[] = {
+   _attr_panel_power_savings.attr,
+   NULL
+};
+
+static const struct attribute_group amdgpu_group = {
+   .name = "amdgpu",
+   .attrs = amdgpu_attrs
+};
+
  static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
  {
struct amdgpu_dm_connector *amdgpu_dm_connector = 
to_amdgpu_dm_connector(connector);
  
+	sysfs_remove_group(>kdev->kobj, _group);

drm_dp_aux_unregister(_dm_connector->dm_dp_aux.aux);
  }
  
@@ -6541,6 +6610,13 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)

to_amdgpu_dm_connector(connector);
int r;
  
+	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {

+   r = sysfs_create_group(>kdev->kobj,
+  _group);
+   if (r)
+   return r;
+   }
+
amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
  
  	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||




Re: [PATCH v3 1/5] ACPI: video: Handle fetching EDID that is longer than 256 bytes

2024-02-02 Thread Mario Limonciello

On 2/2/2024 10:07, Rafael J. Wysocki wrote:

On Thu, Feb 1, 2024 at 11:11 PM Mario Limonciello
 wrote:


The ACPI specification allows for an EDID to be up to 512 bytes but
the _DDC EDID fetching code will only try up to 256 bytes.

Modify the code to instead start at 512 bytes and work it's way
down instead.

As _DDC is now called up to 4 times on a machine debugging messages
are noisier than necessary.  Decrease from info to debug.

Link: 
https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/Apx_B_Video_Extensions/output-device-specific-methods.html#ddc-return-the-edid-for-this-device
Signed-off-by: Mario Limonciello 


Acked-by: Rafael J. Wysocki 

or I can apply it if that's preferred.


Thanks!

I think go ahead and apply this one to your -next tree.

The rest might take a few weeks to get right and no need to block on this.



Thanks!


---
v1->v2:
  * Use for loop for acpi_video_get_edid()
  * Use one of Rafael's suggestions for acpi_video_device_EDID()
  * Decrease message level too
---
  drivers/acpi/acpi_video.c | 25 +
  1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 4afdda9db019..3bfd013e09d2 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -625,12 +625,9 @@ acpi_video_device_EDID(struct acpi_video_device *device,

 if (!device)
 return -ENODEV;
-   if (length == 128)
-   arg0.integer.value = 1;
-   else if (length == 256)
-   arg0.integer.value = 2;
-   else
+   if (!length || (length % 128))
 return -EINVAL;
+   arg0.integer.value = length / 128;

 status = acpi_evaluate_object(device->dev->handle, "_DDC", , 
);
 if (ACPI_FAILURE(status))
@@ -641,7 +638,8 @@ acpi_video_device_EDID(struct acpi_video_device *device,
 if (obj && obj->type == ACPI_TYPE_BUFFER)
 *edid = obj;
 else {
-   acpi_handle_info(device->dev->handle, "Invalid _DDC data\n");
+   acpi_handle_debug(device->dev->handle,
+"Invalid _DDC data for length %ld\n", length);
 status = -EFAULT;
 kfree(obj);
 }
@@ -1447,7 +1445,6 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,

 for (i = 0; i < video->attached_count; i++) {
 video_device = video->attached_array[i].bind_info;
-   length = 256;

 if (!video_device)
 continue;
@@ -1478,18 +1475,14 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,
 continue;
 }

-   status = acpi_video_device_EDID(video_device, , length);
-
-   if (ACPI_FAILURE(status) || !buffer ||
-   buffer->type != ACPI_TYPE_BUFFER) {
-   length = 128;
+   for (length = 512; length > 0; length -= 128) {
 status = acpi_video_device_EDID(video_device, ,
 length);
-   if (ACPI_FAILURE(status) || !buffer ||
-   buffer->type != ACPI_TYPE_BUFFER) {
-   continue;
-   }
+   if (ACPI_SUCCESS(status))
+   break;
 }
+   if (!length)
+   continue;

 *edid = buffer->buffer.pointer;
 return length;
--
2.34.1





Re: [PATCH v3 2/5] drm: Add drm_get_acpi_edid() helper

2024-02-02 Thread Mario Limonciello

On 2/2/2024 04:29, Jani Nikula wrote:

On Thu, 01 Feb 2024, Mario Limonciello  wrote:

Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.


I'm really not happy about adding new struct edid based APIs to
drm_edid.[ch]. Everything new should be struct drm_edid based. All
drivers should be converting towards struct drm_edid, instead of adding
more legacy to rip out later.


OK; I'll redo it with struct drm_edid.

The changeover for amdgpu to use drm_edid is going to be a pretty 
involved effort so I'm going to use a get_raw in amdgpu for now so we 
can unblock the issue this is fixing and let that part get removed when 
the rest of the overhaul gets done there.




BR,
Jani.



Signed-off-by: Mario Limonciello 
---
v1->v2:
  * Split code from previous amdgpu specific helper to generic drm helper.
v2->v3:
  * Add an extra select to fix a variety of randconfig errors found from
LKP robot.
---
  drivers/gpu/drm/Kconfig|  5 +++
  drivers/gpu/drm/drm_edid.c | 73 ++
  include/drm/drm_edid.h |  1 +
  3 files changed, 79 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..14df907c96c8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86
help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..1fbbeaa664b2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
   * DEALINGS IN THE SOFTWARE.
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -2188,6 +2189,47 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
  }
  
+/**

+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+cleanup:
+   kfree(edid);
+   return r;
+}
+
  static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
  {
@@ -2643,6 +2685,37 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
  }
  EXPORT_SYMBOL(drm_get_edid);
  
+/**

+ * drm_get_acpi_edid - get EDID data, if available
+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.  If found,
+ * attach it to the connector.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_get_acpi_edid(struct drm_connector *connector)
+{
+   struct edid *edid = NULL;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return NULL;
+   }
+
+   if (connector->force == DRM_FORCE_OFF)
+   return NULL;
+
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector->dev, NULL);
+
+   drm_connector_update_edid_property(connector, edid);
+   return edid;
+}
+EXPORT_SYMBOL(drm_get_acpi_edid);
+
  /**
   * drm_edid_read_custom - Read EDID data using given EDID block read function
   * @connector: Connector to use
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 518d1b8106c7..60fbdc06badc 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h

[PATCH v3 0/5] Add support for fetching EDID from ACPI _DDC

2024-02-01 Thread Mario Limonciello
Some laptops ship an EDID in the BIOS encoded in the _DDC method that
differs than the EDID directly on the laptop panel for $REASONS.

This is the EDID that is used by the AMD Windows driver, and so sometimes
different results are found in different operating systems.

This series adds a new DRM helper that will use acpi_video to fetch the
EDID.

On amdgpu when an eDP panel is found the BIOS
is checked first for an EDID and that used as a preference if found.

On nouveau it replaces the previous local function doing a similar role.

This does *not* use struct drm_edid as this will require more involved
amdgpu display driver work that will come separately as part of follow-ups
to: https://lore.kernel.org/amd-gfx/20240126163429.56714-1-m...@igalia.com/

v2-v3:
 * Clean up some of the 'select ACPI_VIDEO' kconfig spaghetti reported by LKP
 * Drop the 'select ACPI_VIDEO' from the DRM drivers

Mario Limonciello (5):
  ACPI: video: Handle fetching EDID that is longer than 256 bytes
  drm: Add drm_get_acpi_edid() helper
  drm/amd: Fetch the EDID from _DDC if available for eDP
  drm/nouveau: Use drm_get_acpi_edid() helper
  drm: Drop unneeded selects in DRM drivers

 drivers/acpi/acpi_video.c | 25 +++
 drivers/gpu/drm/Kconfig   |  5 ++
 drivers/gpu/drm/amd/amdgpu/Kconfig|  7 --
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  1 +
 .../gpu/drm/amd/amdgpu/amdgpu_connectors.c|  4 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   |  8 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 ++-
 drivers/gpu/drm/drm_edid.c| 73 +++
 drivers/gpu/drm/gma500/Kconfig|  6 --
 drivers/gpu/drm/i915/Kconfig  |  7 --
 drivers/gpu/drm/nouveau/nouveau_acpi.c| 27 ---
 drivers/gpu/drm/nouveau/nouveau_acpi.h|  2 -
 drivers/gpu/drm/nouveau/nouveau_connector.c   |  2 +-
 drivers/gpu/drm/radeon/Kconfig|  7 --
 drivers/gpu/drm/xe/Kconfig|  6 --
 include/drm/drm_edid.h|  1 +
 17 files changed, 116 insertions(+), 84 deletions(-)

-- 
2.34.1



[PATCH v3 2/5] drm: Add drm_get_acpi_edid() helper

2024-02-01 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.  Drivers can call this
helper to attempt to fetch the EDID from the BIOS's ACPI _DDC method.

Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Split code from previous amdgpu specific helper to generic drm helper.
v2->v3:
 * Add an extra select to fix a variety of randconfig errors found from
   LKP robot.
---
 drivers/gpu/drm/Kconfig|  5 +++
 drivers/gpu/drm/drm_edid.c | 73 ++
 include/drm/drm_edid.h |  1 +
 3 files changed, 79 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..14df907c96c8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -21,6 +21,11 @@ menuconfig DRM
select KCMP
select VIDEO_CMDLINE
select VIDEO_NOMODESET
+   select ACPI_VIDEO if ACPI
+   select BACKLIGHT_CLASS_DEVICE if ACPI
+   select INPUT if ACPI
+   select X86_PLATFORM_DEVICES if ACPI && X86
+   select ACPI_WMI if ACPI && X86
help
  Kernel-level support for the Direct Rendering Infrastructure (DRI)
  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 69c68804023f..1fbbeaa664b2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -28,6 +28,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -2188,6 +2189,47 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
return ret == xfers ? 0 : -1;
 }
 
+/**
+ * drm_do_probe_acpi_edid() - get EDID information via ACPI _DDC
+ * @data: struct drm_device
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling acpi_video_get_edid() function.
+ *
+ * Return: 0 on success or error code on failure.
+ */
+static int
+drm_do_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_device *ddev = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   unsigned char start = block * EDID_LENGTH;
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return -ENODEV;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_KMS("Failed to get EDID from ACPI: %d\n", r);
+   return -EINVAL;
+   }
+   if (len > r || start > r || start + len > r) {
+   r = EINVAL;
+   goto cleanup;
+   }
+
+   memcpy(buf, edid + start, len);
+   r = 0;
+cleanup:
+   kfree(edid);
+   return r;
+}
+
 static void connector_bad_edid(struct drm_connector *connector,
   const struct edid *edid, int num_blocks)
 {
@@ -2643,6 +2685,37 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+/**
+ * drm_get_acpi_edid - get EDID data, if available
+ * @connector: connector we're probing
+ *
+ * Use the BIOS to attempt to grab EDID data if possible.  If found,
+ * attach it to the connector.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_get_acpi_edid(struct drm_connector *connector)
+{
+   struct edid *edid = NULL;
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   break;
+   default:
+   return NULL;
+   }
+
+   if (connector->force == DRM_FORCE_OFF)
+   return NULL;
+
+   edid = _drm_do_get_edid(connector, drm_do_probe_acpi_edid, 
connector->dev, NULL);
+
+   drm_connector_update_edid_property(connector, edid);
+   return edid;
+}
+EXPORT_SYMBOL(drm_get_acpi_edid);
+
 /**
  * drm_edid_read_custom - Read EDID data using given EDID block read function
  * @connector: Connector to use
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 518d1b8106c7..60fbdc06badc 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -412,6 +412,7 @@ struct edid *drm_do_get_edid(struct drm_connector 
*connector,
void *data);
 struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
+struct edid *drm_get_acpi_edid(struct drm_connector *connector);
 u32 drm_edid_get_panel_id(struct i2c_adapter *adapter);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
-- 
2.34.1



[PATCH v3 5/5] drm: Drop unneeded selects in DRM drivers

2024-02-01 Thread Mario Limonciello
All of the selects on ACPI_VIDEO are unnecessary when DRM does the
select for ACPI_VIDEO as it provides a helper for acpi based EDID.

Signed-off-by: Mario Limonciello 
---
v2->v3:
 * new patch
---
 drivers/gpu/drm/amd/amdgpu/Kconfig | 7 ---
 drivers/gpu/drm/gma500/Kconfig | 6 --
 drivers/gpu/drm/i915/Kconfig   | 7 ---
 drivers/gpu/drm/radeon/Kconfig | 7 ---
 drivers/gpu/drm/xe/Kconfig | 6 --
 5 files changed, 33 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 22d88f8ef527..b2178a5a947c 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -22,13 +22,6 @@ config DRM_AMDGPU
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
-   # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
-   # ACPI_VIDEO's dependencies must also be selected.
-   select INPUT if ACPI
-   select ACPI_VIDEO if ACPI
-   # On x86 ACPI_VIDEO also needs ACPI_WMI
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
help
  Choose this option if you have a recent AMD Radeon graphics card.
 
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index efb4a2dd2f80..6921ef67b256 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -6,12 +6,6 @@ config DRM_GMA500
select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION
select I2C
select I2C_ALGOBIT
-   # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
-   select ACPI_VIDEO if ACPI
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
help
  Say yes for an experimental 2D KMS framebuffer driver for the
  Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index b5d6e3352071..476da09433bb 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -22,13 +22,6 @@ config DRM_I915
select I2C
select I2C_ALGOBIT
select IRQ_WORK
-   # i915 depends on ACPI_VIDEO when ACPI is enabled
-   # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select X86_PLATFORM_DEVICES if ACPI
-   select ACPI_WMI if ACPI
-   select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
select SYNC_FILE
select IOSF_MBI if X86
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index f98356be0af2..12149d594100 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -19,13 +19,6 @@ config DRM_RADEON
select INTERVAL_TREE
select I2C
select I2C_ALGOBIT
-   # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
-   # ACPI_VIDEO's dependencies must also be selected.
-   select INPUT if ACPI
-   select ACPI_VIDEO if ACPI
-   # On x86 ACPI_VIDEO also needs ACPI_WMI
-   select X86_PLATFORM_DEVICES if ACPI && X86
-   select ACPI_WMI if ACPI && X86
help
  Choose this option if you have an ATI Radeon graphics card.  There
  are both PCI and AGP versions.  You don't need to choose this to
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index e36ae1f0d885..cf60bdcafb0c 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -19,13 +19,7 @@ config DRM_XE
select DRM_MIPI_DSI
select RELAY
select IRQ_WORK
-   # xe depends on ACPI_VIDEO when ACPI is enabled
-   # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-   select BACKLIGHT_CLASS_DEVICE if ACPI
-   select INPUT if ACPI
-   select ACPI_VIDEO if X86 && ACPI
select ACPI_BUTTON if ACPI
-   select ACPI_WMI if X86 && ACPI
select SYNC_FILE
select IOSF_MBI
select CRC32
-- 
2.34.1



[PATCH v3 4/5] drm/nouveau: Use drm_get_acpi_edid() helper

2024-02-01 Thread Mario Limonciello
Rather than inventing a wrapper to acpi_video_get_edid() use the
one provided by drm. This fixes two problems:
1. A memory leak that the memory provided by the ACPI call was
   never freed.
2. Validation of the BIOS provided blob.

Signed-off-by: Mario Limonciello 
---
v1->v2:
 * New patch
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c  | 27 -
 drivers/gpu/drm/nouveau/nouveau_acpi.h  |  2 --
 drivers/gpu/drm/nouveau/nouveau_connector.c |  2 +-
 3 files changed, 1 insertion(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c 
b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 8f0c69aad248..de9daafb3fbb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -360,33 +360,6 @@ void nouveau_unregister_dsm_handler(void) {}
 void nouveau_switcheroo_optimus_dsm(void) {}
 #endif
 
-void *
-nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
-{
-   struct acpi_device *acpidev;
-   int type, ret;
-   void *edid;
-
-   switch (connector->connector_type) {
-   case DRM_MODE_CONNECTOR_LVDS:
-   case DRM_MODE_CONNECTOR_eDP:
-   type = ACPI_VIDEO_DISPLAY_LCD;
-   break;
-   default:
-   return NULL;
-   }
-
-   acpidev = ACPI_COMPANION(dev->dev);
-   if (!acpidev)
-   return NULL;
-
-   ret = acpi_video_get_edid(acpidev, type, -1, );
-   if (ret < 0)
-   return NULL;
-
-   return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-}
-
 bool nouveau_acpi_video_backlight_use_native(void)
 {
return acpi_video_backlight_use_native();
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h 
b/drivers/gpu/drm/nouveau/nouveau_acpi.h
index e39dd8b94b8b..6a3def8e6cca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.h
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h
@@ -10,7 +10,6 @@ bool nouveau_is_v1_dsm(void);
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
 void nouveau_switcheroo_optimus_dsm(void);
-void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 bool nouveau_acpi_video_backlight_use_native(void);
 void nouveau_acpi_video_register_backlight(void);
 #else
@@ -19,7 +18,6 @@ static inline bool nouveau_is_v1_dsm(void) { return false; };
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
 static inline void nouveau_switcheroo_optimus_dsm(void) {}
-static inline void *nouveau_acpi_edid(struct drm_device *dev, struct 
drm_connector *connector) { return NULL; }
 static inline bool nouveau_acpi_video_backlight_use_native(void) { return 
true; }
 static inline void nouveau_acpi_video_register_backlight(void) {}
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 856b3ef5edb8..746571d4cac0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -713,7 +713,7 @@ nouveau_connector_detect_lvds(struct drm_connector 
*connector, bool force)
 * valid - it's not (rh#613284)
 */
if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-   edid = nouveau_acpi_edid(dev, connector);
+   edid = drm_get_acpi_edid(connector);
if (edid) {
status = connector_status_connected;
goto out;
-- 
2.34.1



[PATCH v3 1/5] ACPI: video: Handle fetching EDID that is longer than 256 bytes

2024-02-01 Thread Mario Limonciello
The ACPI specification allows for an EDID to be up to 512 bytes but
the _DDC EDID fetching code will only try up to 256 bytes.

Modify the code to instead start at 512 bytes and work it's way
down instead.

As _DDC is now called up to 4 times on a machine debugging messages
are noisier than necessary.  Decrease from info to debug.

Link: 
https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/Apx_B_Video_Extensions/output-device-specific-methods.html#ddc-return-the-edid-for-this-device
Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Use for loop for acpi_video_get_edid()
 * Use one of Rafael's suggestions for acpi_video_device_EDID()
 * Decrease message level too
---
 drivers/acpi/acpi_video.c | 25 +
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 4afdda9db019..3bfd013e09d2 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -625,12 +625,9 @@ acpi_video_device_EDID(struct acpi_video_device *device,
 
if (!device)
return -ENODEV;
-   if (length == 128)
-   arg0.integer.value = 1;
-   else if (length == 256)
-   arg0.integer.value = 2;
-   else
+   if (!length || (length % 128))
return -EINVAL;
+   arg0.integer.value = length / 128;
 
status = acpi_evaluate_object(device->dev->handle, "_DDC", , 
);
if (ACPI_FAILURE(status))
@@ -641,7 +638,8 @@ acpi_video_device_EDID(struct acpi_video_device *device,
if (obj && obj->type == ACPI_TYPE_BUFFER)
*edid = obj;
else {
-   acpi_handle_info(device->dev->handle, "Invalid _DDC data\n");
+   acpi_handle_debug(device->dev->handle,
+"Invalid _DDC data for length %ld\n", length);
status = -EFAULT;
kfree(obj);
}
@@ -1447,7 +1445,6 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,
 
for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info;
-   length = 256;
 
if (!video_device)
continue;
@@ -1478,18 +1475,14 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,
continue;
}
 
-   status = acpi_video_device_EDID(video_device, , length);
-
-   if (ACPI_FAILURE(status) || !buffer ||
-   buffer->type != ACPI_TYPE_BUFFER) {
-   length = 128;
+   for (length = 512; length > 0; length -= 128) {
status = acpi_video_device_EDID(video_device, ,
length);
-   if (ACPI_FAILURE(status) || !buffer ||
-   buffer->type != ACPI_TYPE_BUFFER) {
-   continue;
-   }
+   if (ACPI_SUCCESS(status))
+   break;
}
+   if (!length)
+   continue;
 
*edid = buffer->buffer.pointer;
return length;
-- 
2.34.1



  1   2   3   4   5   6   7   8   9   >