Re: [PATCH] drm/amd: Taint the kernel when enabling overdrive

2024-09-25 Thread Mario Limonciello

On 9/25/2024 15:09, Alex Deucher wrote:

On Wed, Sep 25, 2024 at 4:05 PM Mario Limonciello
 wrote:


Some distributions have been patching amdgpu to enable overdrive by
default which may compromise stability.  Furthermore when bug reports
are brought upstream it's not obvious that the system has been tampered
with.

When overdrive is enabled taint the kernel and leave a critical message
in the logs for users so that it's obvious in a bug report it's been
tampered with.

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

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index f57411ed2dc2..99717a1d7f61 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -3067,6 +3067,11 @@ static int __init amdgpu_init(void)
 /* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */
 amdgpu_amdkfd_init();

+   if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) {
+   add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+   pr_crit("Overdrive is enabled, please disable it before reporting 
any bugs.\n");


Might want to reword this to something like:
"Overdrive is enabled, please disable it before reporting any bugs
unrelated to overdrive.\n"

Thanks, good suggestion; I'll reword.  Are you in agreement with the 
selected taint code and location in the driver?



Alex


+   }
+
 /* let modprobe override vga console setting */
 return pci_register_driver(&amdgpu_kms_pci_driver);

--
2.43.0





[PATCH] drm/amd: Taint the kernel when enabling overdrive

2024-09-25 Thread Mario Limonciello
Some distributions have been patching amdgpu to enable overdrive by
default which may compromise stability.  Furthermore when bug reports
are brought upstream it's not obvious that the system has been tampered
with.

When overdrive is enabled taint the kernel and leave a critical message
in the logs for users so that it's obvious in a bug report it's been
tampered with.

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

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index f57411ed2dc2..99717a1d7f61 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -3067,6 +3067,11 @@ static int __init amdgpu_init(void)
/* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */
amdgpu_amdkfd_init();
 
+   if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) {
+   add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+   pr_crit("Overdrive is enabled, please disable it before 
reporting any bugs.\n");
+   }
+
/* let modprobe override vga console setting */
return pci_register_driver(&amdgpu_kms_pci_driver);
 
-- 
2.43.0



Re: [PATCH v7 09/10] drm/amd/display: remove dc_edid handler from dm_helpers_parse_edid_caps

2024-09-25 Thread Mario Limonciello

Alex,

Unfortunately I can't reproduce the regression on the APU I tried. 
However I do have a suspicion on a fix.


Can you see if this helps?  If it does, we can squash it in.

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 bf847ac55475..e75cd527d753 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7008,6 +7008,7 @@ static void amdgpu_dm_connector_destroy(struct 
drm_connector *connector)

kfree(aconnector->i2c);
}
kfree(aconnector->dm_dp_aux.aux.name);
+   drm_edid_free(aconnector->drm_edid);

kfree(connector);
 }

If that doesn't help, I did test dropping this patch and it doesn't 
affect the last patch in the series, that one still works so I'm fine 
with dropping it and we can follow up later.


On 9/25/2024 12:06, Alex Hung wrote:

Mario and Melissa,

This patch causes a regrerssion on 7900 XTX in an IGT test: 
amd_mem_leak's connector-suspend-resume.


Is this patch necessary on this series or is it independent from other 
patches, i.e. can it be dropped from this series until fixed??


Cheers,
Alex Hung

On 9/18/24 15:38, Mario Limonciello wrote:

From: Melissa Wen 

We can parse edid caps from drm_edid and drm_eld and any calls of
dm_helpers_parse_edid_caps is made in a state that we have drm_edid set
to amdgpu connector.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  5 +---
  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 30 ---
  drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  1 -
  .../drm/amd/display/dc/link/link_detection.c  |  6 ++--
  4 files changed, 16 insertions(+), 26 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 bd8fb9968c7c..bf847ac55475 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7123,10 +7123,7 @@ static void 
amdgpu_dm_connector_funcs_force(struct drm_connector *connector)

  memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
  memmove(dc_em_sink->dc_edid.raw_edid, edid,
  (edid->extensions + 1) * EDID_LENGTH);
-    dm_helpers_parse_edid_caps(
-    dc_link,
-    &dc_em_sink->dc_edid,
-    &dc_em_sink->edid_caps);
+    dm_helpers_parse_edid_caps(dc_link, &dc_em_sink->edid_caps);
  }
  }
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 d43ed3ea000b..8f4be7a1ec45 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
@@ -83,32 +83,24 @@ static void apply_edid_quirks(struct 
drm_edid_product_id *product_id,

   * dm_helpers_parse_edid_caps() - Parse edid caps
   *
   * @link: current detected link
- * @edid:    [in] pointer to edid
   * @edid_caps:    [in] pointer to edid caps
   *
   * Return: void
   */
-enum dc_edid_status dm_helpers_parse_edid_caps(
-    struct dc_link *link,
-    const struct dc_edid *edid,
-    struct dc_edid_caps *edid_caps)
+enum dc_edid_status dm_helpers_parse_edid_caps(struct dc_link *link,
+   struct dc_edid_caps *edid_caps)
  {
  struct amdgpu_dm_connector *aconnector = link->priv;
  struct drm_connector *connector = &aconnector->base;
  const struct drm_edid *drm_edid = aconnector->drm_edid;
  struct drm_edid_product_id product_id;
-    struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : 
NULL;

  int sad_count;
  int i = 0;
-
  enum dc_edid_status result = EDID_OK;
-    if (!edid_caps || !edid)
+    if (!edid_caps || !drm_edid)
  return EDID_BAD_INPUT;
-    if (!drm_edid_is_valid(edid_buf))
-    result = EDID_BAD_CHECKSUM;
-
  drm_edid_get_product_id(drm_edid, &product_id);
  edid_caps->manufacturer_id = 
le16_to_cpu(product_id.manufacturer_name);

@@ -920,19 +912,23 @@ enum dc_edid_status dm_helpers_read_local_edid(
  if (!drm_edid)
  return EDID_NO_RESPONSE;
-    edid = drm_edid_raw(drm_edid); // FIXME: Get rid of 
drm_edid_raw()

+    /* FIXME: Get rid of drm_edid_raw()
+ * Raw edid is still needed for dm_helpers_dp_write_dpcd()
+ */
+    edid = drm_edid_raw(drm_edid);
  sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
  memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink- 
>dc_edid.length);

  edid_status = dm_helpers_parse_edid_caps(
  link,
-    &sink->dc_edid,
 

Re: [PATCH v7 10/10] drm/amd/display: Fetch the EDID from _DDC if available for eDP

2024-09-19 Thread Mario Limonciello

On 9/19/2024 12:36, Hamza Mahfooz wrote:

On 9/19/24 13:29, Alex Deucher wrote:

On Thu, Sep 19, 2024 at 12:06 PM Mario Limonciello
 wrote:


On 9/19/2024 11:03, Alex Hung wrote:

A minor comment (see inline below).

Otherwise

Reviewed-by: Alex Hung 

On 2024-09-18 15:38, Mario Limonciello wrote:

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 DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
   .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 62 
++-

   drivers/gpu/drm/amd/include/amd_shared.h  |  5 ++
   2 files changed, 66 insertions(+), 1 deletion(-)

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 8f4be7a1ec45..05d3e00ecce0 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
@@ -23,6 +23,8 @@
    *
    */
+#include 
+
   #include 
   #include 
   #include 
@@ -874,6 +876,60 @@ bool dm_helpers_is_dp_sink_present(struct dc_link
*link)
   return dp_sink_present;
   }
+static int
+dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block,
size_t len)
+{
+    struct drm_connector *connector = data;
+    struct acpi_device *acpidev = 
ACPI_COMPANION(connector->dev->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, 
&edid);

+    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 const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+    struct drm_connector *connector = &aconnector->base;
+
+    if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+    return 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;
+
+    return drm_edid_read_custom(connector,
dm_helpers_probe_acpi_edid, connector);
+}
+
   enum dc_edid_status dm_helpers_read_local_edid(
   struct dc_context *ctx,
   struct dc_link *link,
@@ -896,7 +952,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
    * do check sum and retry to make sure read correct edid.
    */
   do {
-    drm_edid = drm_edid_read_ddc(connector, ddc);
+    drm_edid = dm_helpers_read_acpi_edid(aconnector);
+    if (drm_edid)
+    DRM_DEBUG_KMS("Using ACPI provided EDID for %s\n",
connector->name);


It is better to always output a message when ACPI's EDID is used 
without

enabling any debug options. How about DRM_INFO?


Thanks, DRM_INFO makes sense for discoverability and will adjust it.


I'd suggest using dev_info() or one of the newer DRM macros so we know
which device we are talking about if there are multiple GPUs in the
system.


Ya, I'd personally prefer moving amdgpu_dm over to the new(er) drm_.*
family of logging macros.


Thanks.  I've adjusted it to:

drm_info(connector->dev, "Using ACPI provided EDID for %s\n", 
connector->name);


Also there is a debug one used above that I adjusted to:

drm_dbg(connector->dev, "Failed to get EDID from ACPI: %d\n", r);





Alex






+    else
+    drm_edid = drm_edid_read_ddc(connector, ddc);
   drm_edid_connector_update(connector, drm_edid);
   aconnector->drm_edid = drm_edid;
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h
b/drivers/gpu/drm/amd/include/amd_shared.h
index 3f91926a50e9..1ec7c5e5249e 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -337,6 +337,11 @@ enum DC_DEBUG_MASK {
    * @DC_FORCE_IPS_ENABLE: If set, force enable all IPS, all the
time.
    */
   DC_FORCE_IPS_ENABLE = 0x4000,
+    /**
+ * @DC_DISABLE_ACPI_EDID: If set, don't attempt to fetch EDID for
+ * eDP display from ACPI _DDC method.
+ */
+    DC_DISABLE_ACPI_EDID = 0x8000,
   };
   enum amd_dpm_forced_level;






Re: [PATCH v7 10/10] drm/amd/display: Fetch the EDID from _DDC if available for eDP

2024-09-19 Thread Mario Limonciello

On 9/19/2024 11:03, Alex Hung wrote:

A minor comment (see inline below).

Otherwise

Reviewed-by: Alex Hung 

On 2024-09-18 15:38, Mario Limonciello wrote:

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 DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 62 ++-
  drivers/gpu/drm/amd/include/amd_shared.h  |  5 ++
  2 files changed, 66 insertions(+), 1 deletion(-)

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 8f4be7a1ec45..05d3e00ecce0 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
@@ -23,6 +23,8 @@
   *
   */
+#include 
+
  #include 
  #include 
  #include 
@@ -874,6 +876,60 @@ bool dm_helpers_is_dp_sink_present(struct dc_link 
*link)

  return dp_sink_present;
  }
+static int
+dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block, 
size_t len)

+{
+    struct drm_connector *connector = data;
+    struct acpi_device *acpidev = ACPI_COMPANION(connector->dev->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, &edid);
+    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 const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+    struct drm_connector *connector = &aconnector->base;
+
+    if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+    return 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;
+
+    return drm_edid_read_custom(connector, 
dm_helpers_probe_acpi_edid, connector);

+}
+
  enum dc_edid_status dm_helpers_read_local_edid(
  struct dc_context *ctx,
  struct dc_link *link,
@@ -896,7 +952,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
   * do check sum and retry to make sure read correct edid.
   */
  do {
-    drm_edid = drm_edid_read_ddc(connector, ddc);
+    drm_edid = dm_helpers_read_acpi_edid(aconnector);
+    if (drm_edid)
+    DRM_DEBUG_KMS("Using ACPI provided EDID for %s\n", 
connector->name);


It is better to always output a message when ACPI's EDID is used without 
enabling any debug options. How about DRM_INFO?


Thanks, DRM_INFO makes sense for discoverability and will adjust it.




+    else
+    drm_edid = drm_edid_read_ddc(connector, ddc);
  drm_edid_connector_update(connector, drm_edid);
  aconnector->drm_edid = drm_edid;
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h 
b/drivers/gpu/drm/amd/include/amd_shared.h

index 3f91926a50e9..1ec7c5e5249e 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -337,6 +337,11 @@ enum DC_DEBUG_MASK {
   * @DC_FORCE_IPS_ENABLE: If set, force enable all IPS, all the 
time.

   */
  DC_FORCE_IPS_ENABLE = 0x4000,
+    /**
+ * @DC_DISABLE_ACPI_EDID: If set, don't attempt to fetch EDID for
+ * eDP display from ACPI _DDC method.
+ */
+    DC_DISABLE_ACPI_EDID = 0x8000,
  };
  enum amd_dpm_forced_level;




[PATCH v7 01/10] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
v7: fix LKP robot issue
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 123 --
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  13 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  34 ++---
 4 files changed, 84 insertions(+), 90 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 6f4b753f5f51..b7d93787667c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3487,7 +3487,7 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
amdgpu_dm_update_freesync_caps(connector,
-   aconnector->edid);
+   aconnector->drm_edid);
} else {
amdgpu_dm_update_freesync_caps(connector, NULL);
if (!aconnector->dc_sink) {
@@ -3546,18 +3546,19 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
if (sink->dc_edid.length == 0) {
-   aconnector->edid = NULL;
+   aconnector->drm_edid = NULL;
if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(
&aconnector->dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+
+   aconnector->drm_edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
+   drm_edid_connector_update(connector, 
aconnector->drm_edid);
 
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
-   aconnector->edid);
+   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, 
edid);
}
 
if (!aconnector->timing_requested) {
@@ -3568,17 +3569,18 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
-   amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->drm_edid);
+   amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->drm_edid);
+   aconnector->drm_edid = NULL;
kfree(aconnector->timing_requested);
aconnector->timing_requested = NULL;
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
again on hotplug */
@@ -7105,32 +7107,24 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
-   struct edid *edid;
-   struct i2c_adapter *ddc;
-
-   if (dc_link && dc_link->aux_mode)
-   ddc = &aconnector->dm_dp_aux.aux.ddc;
-   else
-   ddc = &aconnector->i2c->base;
+   const struct drm_edid *drm_edid;
 
-   /*
-* 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_f

[PATCH v7 02/10] drm/amd/display: switch to setting physical address directly

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

Connectors have source physical address available in display
info. Use drm_dp_cec_attach() to use it instead of parsing the EDID
again.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++---
 1 file changed, 3 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 b7d93787667c..0b6c936be7a6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3548,8 +3548,7 @@ void amdgpu_dm_update_connector_after_detect(
if (sink->dc_edid.length == 0) {
aconnector->drm_edid = NULL;
if (aconnector->dc_link->aux_mode) {
-   drm_dp_cec_unset_edid(
-   &aconnector->dm_dp_aux.aux);
+   
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
}
} else {
const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
@@ -3558,7 +3557,8 @@ void amdgpu_dm_update_connector_after_detect(
drm_edid_connector_update(connector, 
aconnector->drm_edid);
 
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, 
edid);
+   drm_dp_cec_attach(&aconnector->dm_dp_aux.aux,
+ 
connector->display_info.source_physical_address);
}
 
if (!aconnector->timing_requested) {
-- 
2.34.1



[PATCH v7 03/10] drm/amd/display: always call connector_update when parsing freesync_caps

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

Update connector caps with drm_edid data before parsing info for
freesync.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 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 0b6c936be7a6..efc1609ff26f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3569,13 +3569,11 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_edid_connector_update(connector, aconnector->drm_edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -12088,6 +12086,8 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
amdgpu_dm_connector->dc_sink :
amdgpu_dm_connector->dc_em_sink;
 
+   drm_edid_connector_update(connector, drm_edid);
+
if (!drm_edid || !sink) {
dm_con_state = to_dm_connector_state(connector->state);
 
-- 
2.34.1



[PATCH v7 10/10] drm/amd/display: Fetch the EDID from _DDC if available for eDP

2024-09-18 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 DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 62 ++-
 drivers/gpu/drm/amd/include/amd_shared.h  |  5 ++
 2 files changed, 66 insertions(+), 1 deletion(-)

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 8f4be7a1ec45..05d3e00ecce0 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
@@ -23,6 +23,8 @@
  *
  */
 
+#include 
+
 #include 
 #include 
 #include 
@@ -874,6 +876,60 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link)
return dp_sink_present;
 }
 
+static int
+dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+   struct drm_connector *connector = data;
+   struct acpi_device *acpidev = ACPI_COMPANION(connector->dev->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, &edid);
+   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 const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+   struct drm_connector *connector = &aconnector->base;
+
+   if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+   return 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;
+
+   return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, 
connector);
+}
+
 enum dc_edid_status dm_helpers_read_local_edid(
struct dc_context *ctx,
struct dc_link *link,
@@ -896,7 +952,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
-   drm_edid = drm_edid_read_ddc(connector, ddc);
+   drm_edid = dm_helpers_read_acpi_edid(aconnector);
+   if (drm_edid)
+   DRM_DEBUG_KMS("Using ACPI provided EDID for %s\n", 
connector->name);
+   else
+   drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
aconnector->drm_edid = drm_edid;
 
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h 
b/drivers/gpu/drm/amd/include/amd_shared.h
index 3f91926a50e9..1ec7c5e5249e 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -337,6 +337,11 @@ enum DC_DEBUG_MASK {
 * @DC_FORCE_IPS_ENABLE: If set, force enable all IPS, all the time.
 */
DC_FORCE_IPS_ENABLE = 0x4000,
+   /**
+* @DC_DISABLE_ACPI_EDID: If set, don't attempt to fetch EDID for
+* eDP display from ACPI _DDC method.
+*/
+   DC_DISABLE_ACPI_EDID = 0x8000,
 };
 
 enum amd_dpm_forced_level;
-- 
2.34.1



[PATCH v7 07/10] drm/amd/display: get SAD from drm_eld when parsing EDID caps

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

drm_edid_connector_update() updates display info, filling ELD with audio
info from Short-Audio Descriptors in the last step of
update_dislay_info(). Our goal is stopping using raw edid, so we can
extract SAD from drm_eld instead of access raw edid to get audio caps.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 20 +--
 1 file changed, 10 insertions(+), 10 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 854e51c0b3fb..e0326127fd9a 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
@@ -98,9 +98,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
-   struct cea_sad *sads;
-   int sad_count = -1;
-   int sadb_count = -1;
+   int sad_count, sadb_count;
int i = 0;
uint8_t *sadb = NULL;
 
@@ -129,18 +127,21 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 
apply_edid_quirks(&product_id, edid_caps);
 
-   sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
+   sad_count = drm_eld_sad_count(connector->eld);
if (sad_count <= 0)
return result;
 
edid_caps->audio_mode_count = min(sad_count, DC_MAX_AUDIO_DESC_COUNT);
for (i = 0; i < edid_caps->audio_mode_count; ++i) {
-   struct cea_sad *sad = &sads[i];
+   struct cea_sad sad;
 
-   edid_caps->audio_modes[i].format_code = sad->format;
-   edid_caps->audio_modes[i].channel_count = sad->channels + 1;
-   edid_caps->audio_modes[i].sample_rate = sad->freq;
-   edid_caps->audio_modes[i].sample_size = sad->byte2;
+   if (drm_eld_sad_get(connector->eld, i, &sad) < 0)
+   continue;
+
+   edid_caps->audio_modes[i].format_code = sad.format;
+   edid_caps->audio_modes[i].channel_count = sad.channels + 1;
+   edid_caps->audio_modes[i].sample_rate = sad.freq;
+   edid_caps->audio_modes[i].sample_size = sad.byte2;
}
 
sadb_count = drm_edid_to_speaker_allocation((struct edid *) 
edid->raw_edid, &sadb);
@@ -155,7 +156,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
else
edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 
-   kfree(sads);
kfree(sadb);
 
return result;
-- 
2.34.1



[PATCH v7 09/10] drm/amd/display: remove dc_edid handler from dm_helpers_parse_edid_caps

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

We can parse edid caps from drm_edid and drm_eld and any calls of
dm_helpers_parse_edid_caps is made in a state that we have drm_edid set
to amdgpu connector.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  5 +---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 30 ---
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  1 -
 .../drm/amd/display/dc/link/link_detection.c  |  6 ++--
 4 files changed, 16 insertions(+), 26 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 bd8fb9968c7c..bf847ac55475 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7123,10 +7123,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
memmove(dc_em_sink->dc_edid.raw_edid, edid,
(edid->extensions + 1) * EDID_LENGTH);
-   dm_helpers_parse_edid_caps(
-   dc_link,
-   &dc_em_sink->dc_edid,
-   &dc_em_sink->edid_caps);
+   dm_helpers_parse_edid_caps(dc_link, &dc_em_sink->edid_caps);
}
 }
 
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 d43ed3ea000b..8f4be7a1ec45 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
@@ -83,32 +83,24 @@ static void apply_edid_quirks(struct drm_edid_product_id 
*product_id,
  * dm_helpers_parse_edid_caps() - Parse edid caps
  *
  * @link: current detected link
- * @edid:  [in] pointer to edid
  * @edid_caps: [in] pointer to edid caps
  *
  * Return: void
  */
-enum dc_edid_status dm_helpers_parse_edid_caps(
-   struct dc_link *link,
-   const struct dc_edid *edid,
-   struct dc_edid_caps *edid_caps)
+enum dc_edid_status dm_helpers_parse_edid_caps(struct dc_link *link,
+  struct dc_edid_caps *edid_caps)
 {
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
-   struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
int sad_count;
int i = 0;
-
enum dc_edid_status result = EDID_OK;
 
-   if (!edid_caps || !edid)
+   if (!edid_caps || !drm_edid)
return EDID_BAD_INPUT;
 
-   if (!drm_edid_is_valid(edid_buf))
-   result = EDID_BAD_CHECKSUM;
-
drm_edid_get_product_id(drm_edid, &product_id);
 
edid_caps->manufacturer_id = le16_to_cpu(product_id.manufacturer_name);
@@ -920,19 +912,23 @@ enum dc_edid_status dm_helpers_read_local_edid(
if (!drm_edid)
return EDID_NO_RESPONSE;
 
-   edid = drm_edid_raw(drm_edid); // FIXME: Get rid of 
drm_edid_raw()
+   /* FIXME: Get rid of drm_edid_raw()
+* Raw edid is still needed for dm_helpers_dp_write_dpcd()
+*/
+   edid = drm_edid_raw(drm_edid);
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, 
sink->dc_edid.length);
 
edid_status = dm_helpers_parse_edid_caps(
link,
-   &sink->dc_edid,
&sink->edid_caps);
 
-   /* We don't need the original edid anymore */
-   drm_edid_free(drm_edid);
-
-   } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
+   if (edid_status != EDID_OK) {
+   /* We can discard the drm_edid and retry */
+   drm_edid_free(drm_edid);
+   drm_edid_connector_update(connector, drm_edid);
+   }
+   } while (edid_status != EDID_OK && --retry > 0);
 
if (edid_status != EDID_OK)
DRM_ERROR("EDID err: %d, on connector: %s",
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h 
b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 2e4a46f1b499..4e1776b5f0d4 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -61,7 +61,6 @@ void dm_helpers_free_gpu_mem(
 
 enum dc_edid_status dm_helpers_parse_edid_caps(
struct dc_link *link,
-   c

[PATCH v7 08/10] drm/amd/display: get SADB from drm_eld when parsing EDID caps

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

drm_edid_connector_update() updates display info, filling ELD with
speaker allocation data in the last step of update_dislay_info(). Our
goal is stopping using raw edid, so we can extract SADB from drm_eld
instead of access raw edid to get audio caps.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 15 +++
 1 file changed, 3 insertions(+), 12 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 e0326127fd9a..d43ed3ea000b 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
@@ -98,9 +98,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
-   int sad_count, sadb_count;
+   int sad_count;
int i = 0;
-   uint8_t *sadb = NULL;
 
enum dc_edid_status result = EDID_OK;
 
@@ -144,20 +143,12 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->audio_modes[i].sample_size = sad.byte2;
}
 
-   sadb_count = drm_edid_to_speaker_allocation((struct edid *) 
edid->raw_edid, &sadb);
 
-   if (sadb_count < 0) {
-   DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", 
sadb_count);
-   sadb_count = 0;
-   }
-
-   if (sadb_count)
-   edid_caps->speaker_flags = sadb[0];
+   if (connector->eld[DRM_ELD_SPEAKER])
+   edid_caps->speaker_flags = connector->eld[DRM_ELD_SPEAKER];
else
edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 
-   kfree(sadb);
-
return result;
 }
 
-- 
2.34.1



[PATCH v7 05/10] drm/amd/display: use drm_edid_product_id for parsing EDID product info

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

Since [1], we can use drm_edid_product_id to get debug info from
drm_edid instead of directly parsing EDID.

Link: 
https://lore.kernel.org/dri-devel/cover.1712655867.git.jani.nik...@intel.com/ 
[1]
Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 38 ++-
 1 file changed, 20 insertions(+), 18 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 b8004ccdcc33..cf11ac4c1672 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
@@ -45,16 +45,16 @@
 #include "dm_helpers.h"
 #include "ddc_service_types.h"
 
-static u32 edid_extract_panel_id(struct edid *edid)
+static u32 edid_extract_panel_id(struct drm_edid_product_id *product_id)
 {
-   return (u32)edid->mfg_id[0] << 24   |
-  (u32)edid->mfg_id[1] << 16   |
-  (u32)EDID_PRODUCT_ID(edid);
+   return (u32)be16_to_cpu(product_id->manufacturer_name) << 16 |
+  (u32)le16_to_cpu(product_id->product_code);
 }
 
-static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps 
*edid_caps)
+static void apply_edid_quirks(struct drm_edid_product_id *product_id,
+ struct dc_edid_caps *edid_caps)
 {
-   uint32_t panel_id = edid_extract_panel_id(edid);
+   uint32_t panel_id = edid_extract_panel_id(product_id);
 
switch (panel_id) {
/* Workaround for some monitors which does not work well with FAMS */
@@ -94,6 +94,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 {
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
+   const struct drm_edid *drm_edid = aconnector->drm_edid;
+   struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
struct cea_sad *sads;
int sad_count = -1;
@@ -109,13 +111,13 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
if (!drm_edid_is_valid(edid_buf))
result = EDID_BAD_CHECKSUM;
 
-   edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
-   ((uint16_t) edid_buf->mfg_id[1])<<8;
-   edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
-   ((uint16_t) edid_buf->prod_code[1])<<8;
-   edid_caps->serial_number = edid_buf->serial;
-   edid_caps->manufacture_week = edid_buf->mfg_week;
-   edid_caps->manufacture_year = edid_buf->mfg_year;
+   drm_edid_get_product_id(drm_edid, &product_id);
+
+   edid_caps->manufacturer_id = le16_to_cpu(product_id.manufacturer_name);
+   edid_caps->product_id = le16_to_cpu(product_id.product_code);
+   edid_caps->serial_number = le32_to_cpu(product_id.serial_number);
+   edid_caps->manufacture_week = product_id.week_of_manufacture;
+   edid_caps->manufacture_year = product_id.year_of_manufacture;
 
drm_edid_get_monitor_name(edid_buf,
  edid_caps->display_name,
@@ -123,7 +125,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
 
-   apply_edid_quirks(edid_buf, edid_caps);
+   apply_edid_quirks(&product_id, edid_caps);
 
sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
if (sad_count <= 0)
@@ -909,9 +911,9 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
-
drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
+   aconnector->drm_edid = drm_edid;
 
/* DP Compliance Test 4.2.2.6 */
if (link->aux_mode && connector->edid_corrupt)
@@ -929,14 +931,14 @@ enum dc_edid_status dm_helpers_read_local_edid(
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, 
sink->dc_edid.length);
 
-   /* We don't need the original edid anymore */
-   drm_edid_free(drm_edid);
-
edid_status = dm_helpers_parse_edid_caps(
link,
&sink->dc_edid,
&sink->edid_caps);
 
+   /* We don't need the original edid anymore */
+   drm_edid_free(drm_edid);
+
} while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
 
if (edid_status != EDID_OK)
-- 
2.34.1



[PATCH v7 06/10] drm/amd/display: parse display name from drm_eld

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

We don't need to parse dc_edid to get the display name since it's
already set in drm_eld which in turn had it values updated when updating
connector with the opaque drm_edid.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  | 10 ++
 1 file changed, 6 insertions(+), 4 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 cf11ac4c1672..854e51c0b3fb 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
@@ -32,7 +32,7 @@
 #include 
 #include 
 #include 
-
+#include 
 #include "dm_services.h"
 #include "amdgpu.h"
 #include "dc.h"
@@ -78,6 +78,7 @@ static void apply_edid_quirks(struct drm_edid_product_id 
*product_id,
}
 }
 
+#define AMDGPU_ELD_DISPLAY_NAME_SIZE_IN_CHARS 13
 /**
  * dm_helpers_parse_edid_caps() - Parse edid caps
  *
@@ -119,9 +120,10 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->manufacture_week = product_id.week_of_manufacture;
edid_caps->manufacture_year = product_id.year_of_manufacture;
 
-   drm_edid_get_monitor_name(edid_buf,
- edid_caps->display_name,
- AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
+   memset(edid_caps->display_name, 0, 
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
+   memcpy(edid_caps->display_name,
+  &connector->eld[DRM_ELD_MONITOR_NAME_STRING],
+  AMDGPU_ELD_DISPLAY_NAME_SIZE_IN_CHARS);
 
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
 
-- 
2.34.1



[PATCH v7 00/10] drm/amd/display: Use drm_edid for more code

2024-09-18 Thread Mario Limonciello
This is the successor of Melissa's v5 series that was posted [1] as well
as my series that was posted [2].

Melissa's patches are mostly unmodified from v5, but the series has been
rebase on the new 6.10 based amd-staging-drm-next.

As were both touching similar code for fetching the EDID, I've merged the
pertinent parts of my series into this one in allowing the connector to
fetch the EDID from _DDC if available for eDP as well.

There are still some remaining uses of drm_edid_raw() but they touch pure
DC code, so a wrapper or macro will probably be needed to convert them.
This can be for follow ups later on.

Link: https://lore.kernel.org/amd-gfx/20240807203207.2830-1-m...@igalia.com/ [1]
Link: 
https://lore.kernel.org/dri-devel/20240214215756.6530-1-mario.limoncie...@amd.com/
 [2]

v7:
 * Rebase on amd-staging-drm-next which is now 6.10 based
 * Fix the two LKP robot reported issues

Mario Limonciello (1):
  drm/amd/display: Fetch the EDID from _DDC if available for eDP

Melissa Wen (9):
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid
  drm/amd/display: switch to setting physical address directly
  drm/amd/display: always call connector_update when parsing
freesync_caps
  drm/amd/display: remove redundant freesync parser for DP
  drm/amd/display: use drm_edid_product_id for parsing EDID product info
  drm/amd/display: parse display name from drm_eld
  drm/amd/display: get SAD from drm_eld when parsing EDID caps
  drm/amd/display: get SADB from drm_eld when parsing EDID caps
  drm/amd/display: remove dc_edid handler from
dm_helpers_parse_edid_caps

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 200 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 172 +--
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  34 +--
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |   1 -
 .../drm/amd/display/dc/link/link_detection.c  |   6 +-
 drivers/gpu/drm/amd/include/amd_shared.h  |   5 +
 7 files changed, 200 insertions(+), 222 deletions(-)


base-commit: 0569603f945225067d963c8ba4fda31d967ab584
-- 
2.34.1



[PATCH v7 04/10] drm/amd/display: remove redundant freesync parser for DP

2024-09-18 Thread Mario Limonciello
From: Melissa Wen 

When updating connector under drm_edid infrastructure, many calculations
and validations are already done and become redundant inside AMD driver.
Remove those driver-specific code in favor of the DRM common code.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 74 +--
 1 file changed, 4 insertions(+), 70 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 efc1609ff26f..bd8fb9968c7c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -12064,9 +12064,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
const struct drm_edid *drm_edid)
 {
int i = 0;
-   const struct detailed_timing *timing;
-   const struct detailed_non_pixel *data;
-   const struct detailed_data_monitor_range *range;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
@@ -12093,8 +12090,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   connector->display_info.monitor_range.min_vfreq = 0;
-   connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
 
goto update;
@@ -12114,67 +12109,10 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
 sink->sink_signal == SIGNAL_TYPE_EDP)) {
-   bool edid_check_required = false;
-
-   if (amdgpu_dm_connector->dc_link &&
-   
amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
-   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) {
-   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
-   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
-   if (amdgpu_dm_connector->max_vfreq -
-   amdgpu_dm_connector->min_vfreq > 10)
-   freesync_capable = true;
-   } else {
-   edid_check_required = edid->version > 1 ||
- (edid->version == 1 &&
-  edid->revision > 1);
-   }
-   }
-
-   if (edid_check_required) {
-   for (i = 0; i < 4; i++) {
-
-   timing  = &edid->detailed_timings[i];
-   data= &timing->data.other_data;
-   range   = &data->data.range;
-   /*
-* Check if monitor has continuous frequency 
mode
-*/
-   if (data->type != EDID_DETAIL_MONITOR_RANGE)
-   continue;
-   /*
-* Check for flag range limits only. If flag == 
1 then
-* no additional timing information provided.
-* Default GTF, GTF Secondary curve and CVT are 
not
-* supported
-*/
-   if (range->flags != 1)
-   continue;
-
-   connector->display_info.monitor_range.min_vfreq 
= range->min_vfreq;
-   connector->display_info.monitor_range.max_vfreq 
= range->max_vfreq;
-
-   if (edid->revision >= 4) {
-   if (data->pad2 & 
DRM_EDID_RANGE_OFFSET_MIN_VFREQ)
-   
connector->display_info.monitor_range.min_vfreq += 255;
-   if (data->pad2 & 
DRM_EDID_RANGE_OFFSET_MAX_VFREQ)
-   
connector->display_info.monitor_range.max_vfreq += 255;
-   }
-
-   amdgpu_dm_connector->min_vfreq =
-   
connector->display_info.monitor_range.min_vfreq;
- 

[PATCH] drm/amd/display: Allow backlight to go below `AMDGPU_DM_DEFAULT_MIN_BACKLIGHT`

2024-09-15 Thread Mario Limonciello
From: Mario Limonciello 

The issue with panel power savings compatibility below
`AMDGPU_DM_DEFAULT_MIN_BACKLIGHT` happens at
`AMDGPU_DM_DEFAULT_MIN_BACKLIGHT` as well.

That issue will be fixed separately, so don't prevent the backlight
brightness from going that low.

Cc: Harry Wentland 
Cc: Thomas Weißschuh 
Link: 
https://lore.kernel.org/amd-gfx/be04226a-a9e3-4a45-a83b-6d263c655...@t-8ch.de/T/#m400dee4e2fc61fe9470334d20a7c8c89c9aef44f
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 ad66f09cd0bb..80b8594fcc33 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4449,7 +4449,7 @@ static void amdgpu_dm_update_backlight_caps(struct 
amdgpu_display_manager *dm,
int spread = caps.max_input_signal - caps.min_input_signal;
 
if (caps.max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
-   caps.min_input_signal < AMDGPU_DM_DEFAULT_MIN_BACKLIGHT ||
+   caps.min_input_signal < 0 ||
spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
spread < AMDGPU_DM_MIN_SPREAD) {
DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, 
max=%d\n",
-- 
2.43.0



Re: [PATCH] drm/amd/display: Validate backlight caps are sane

2024-09-13 Thread Mario Limonciello

On 9/13/2024 15:36, Alex Deucher wrote:

On Fri, Sep 13, 2024 at 2:51 PM Mario Limonciello
 wrote:


On 9/13/2024 13:47, Harry Wentland wrote:



On 2024-09-13 14:00, Mario Limonciello wrote:

Currently amdgpu takes backlight caps provided by the ACPI tables
on systems as is.  If the firmware sets maximums that are too low
this means that users don't get a good experience.

To avoid having to maintain a quirk list of such systems, do a sanity
check on the values.  Check that the spread is at least half of the
values that amdgpu would use if no ACPI table was found and if not
use the amdgpu defaults.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3020
Signed-off-by: Mario Limonciello 
---
   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c| 16 
   1 file changed, 16 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 5942fc4e1c86..ad66f09cd0bb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4428,6 +4428,7 @@ static int amdgpu_dm_mode_config_init(struct 
amdgpu_device *adev)

   #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12
   #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
+#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - 
AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
   #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50

   static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager 
*dm,
@@ -4442,6 +4443,21 @@ static void amdgpu_dm_update_backlight_caps(struct 
amdgpu_display_manager *dm,
  return;

  amdgpu_acpi_get_backlight_caps(&caps);
+
+/* validate the firmware value is sane */
+if (caps.caps_valid) {
+int spread = caps.max_input_signal - caps.min_input_signal;
+
+if (caps.max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+caps.min_input_signal < AMDGPU_DM_DEFAULT_MIN_BACKLIGHT ||


Would we still want to allow signals below AMDGPU_DM_DEFAULT_MIN_BACKLIGHT
(but above 0)? The min backlight value of 12 is a bit conservative and
I wouldn't be surprised if systems set it lower via ACPI.

The rest looks like great checks that we should absolutely have.


I'm waffling about that one because Thomas' testing showed that there
was some problems with panel power savings when he quirked the Framework
panels below their ACPI default (12) in his v6 series of the Framework
quirks.


What about systems without the need for a quirk?  E.g., the vendor put
a value less than AMDGPU_DM_DEFAULT_MIN_BACKLIGHT in the ACPI tables
because they validated it and it works.  Won't this break that?



From what I can tell from the observations that Thomas had (mentioned 
in this commit message) setting it below 12 causes panel power saving to 
not work properly; the issue should be specifically in how DC/DMCUB 
handles that case.


I think once that's fixed we should open it up further.


Alex



So my thought process was we should put in an explicit check for now and
then when we have panel power savings working without a modeset landed
then we can also add code to the backlight set callback to turn off
panel power savings when set below AMDGPU_DM_DEFAULT_MIN_BACKLIGHT to
prevent the issue he found.



Harry


+spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+spread < AMDGPU_DM_MIN_SPREAD) {
+DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, 
max=%d\n",
+  caps.min_input_signal, 
caps.max_input_signal);
+caps.caps_valid = false;
+}
+}
+
  if (caps.caps_valid) {
  dm->backlight_caps[bl_idx].caps_valid = true;
  if (caps.aux_support)








Re: [PATCH] drm/amd/display: Validate backlight caps are sane

2024-09-13 Thread Mario Limonciello

On 9/13/2024 13:47, Harry Wentland wrote:



On 2024-09-13 14:00, Mario Limonciello wrote:

Currently amdgpu takes backlight caps provided by the ACPI tables
on systems as is.  If the firmware sets maximums that are too low
this means that users don't get a good experience.

To avoid having to maintain a quirk list of such systems, do a sanity
check on the values.  Check that the spread is at least half of the
values that amdgpu would use if no ACPI table was found and if not
use the amdgpu defaults.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3020
Signed-off-by: Mario Limonciello 
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c| 16 
  1 file changed, 16 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 5942fc4e1c86..ad66f09cd0bb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4428,6 +4428,7 @@ static int amdgpu_dm_mode_config_init(struct 
amdgpu_device *adev)
  
  #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12

  #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
+#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - 
AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
  #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50
  
  static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,

@@ -4442,6 +4443,21 @@ static void amdgpu_dm_update_backlight_caps(struct 
amdgpu_display_manager *dm,
return;
  
  	amdgpu_acpi_get_backlight_caps(&caps);

+
+   /* validate the firmware value is sane */
+   if (caps.caps_valid) {
+   int spread = caps.max_input_signal - caps.min_input_signal;
+
+   if (caps.max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+   caps.min_input_signal < AMDGPU_DM_DEFAULT_MIN_BACKLIGHT ||


Would we still want to allow signals below AMDGPU_DM_DEFAULT_MIN_BACKLIGHT
(but above 0)? The min backlight value of 12 is a bit conservative and
I wouldn't be surprised if systems set it lower via ACPI.

The rest looks like great checks that we should absolutely have.


I'm waffling about that one because Thomas' testing showed that there 
was some problems with panel power savings when he quirked the Framework 
panels below their ACPI default (12) in his v6 series of the Framework 
quirks.


So my thought process was we should put in an explicit check for now and 
then when we have panel power savings working without a modeset landed 
then we can also add code to the backlight set callback to turn off 
panel power savings when set below AMDGPU_DM_DEFAULT_MIN_BACKLIGHT to 
prevent the issue he found.




Harry


+   spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+   spread < AMDGPU_DM_MIN_SPREAD) {
+   DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, 
max=%d\n",
+ caps.min_input_signal, 
caps.max_input_signal);
+   caps.caps_valid = false;
+   }
+   }
+
if (caps.caps_valid) {
dm->backlight_caps[bl_idx].caps_valid = true;
if (caps.aux_support)






[PATCH] drm/amd/display: Validate backlight caps are sane

2024-09-13 Thread Mario Limonciello
Currently amdgpu takes backlight caps provided by the ACPI tables
on systems as is.  If the firmware sets maximums that are too low
this means that users don't get a good experience.

To avoid having to maintain a quirk list of such systems, do a sanity
check on the values.  Check that the spread is at least half of the
values that amdgpu would use if no ACPI table was found and if not
use the amdgpu defaults.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3020
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c| 16 
 1 file changed, 16 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 5942fc4e1c86..ad66f09cd0bb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4428,6 +4428,7 @@ static int amdgpu_dm_mode_config_init(struct 
amdgpu_device *adev)
 
 #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12
 #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
+#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - 
AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
 #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50
 
 static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
@@ -4442,6 +4443,21 @@ static void amdgpu_dm_update_backlight_caps(struct 
amdgpu_display_manager *dm,
return;
 
amdgpu_acpi_get_backlight_caps(&caps);
+
+   /* validate the firmware value is sane */
+   if (caps.caps_valid) {
+   int spread = caps.max_input_signal - caps.min_input_signal;
+
+   if (caps.max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+   caps.min_input_signal < AMDGPU_DM_DEFAULT_MIN_BACKLIGHT ||
+   spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
+   spread < AMDGPU_DM_MIN_SPREAD) {
+   DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, 
max=%d\n",
+ caps.min_input_signal, 
caps.max_input_signal);
+   caps.caps_valid = false;
+   }
+   }
+
if (caps.caps_valid) {
dm->backlight_caps[bl_idx].caps_valid = true;
if (caps.aux_support)
-- 
2.43.0



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

2024-09-11 Thread Mario Limonciello
From: 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 DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 63 ++-
 drivers/gpu/drm/amd/include/amd_shared.h  |  1 +
 2 files changed, 63 insertions(+), 1 deletion(-)

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 1118986bb3e2..26d5fff6e185 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
@@ -23,6 +23,8 @@
  *
  */
 
+#include 
+
 #include 
 #include 
 #include 
@@ -874,6 +876,61 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link)
return dp_sink_present;
 }
 
+static int
+dm_helpers_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;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, &edid);
+   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 const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+   struct drm_connector *connector = &aconnector->base;
+
+   if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+   return 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;
+
+   return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, 
connector);
+}
+
 enum dc_edid_status dm_helpers_read_local_edid(
struct dc_context *ctx,
struct dc_link *link,
@@ -896,7 +953,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
-   drm_edid = drm_edid_read_ddc(connector, ddc);
+   drm_edid = dm_helpers_read_acpi_edid(aconnector);
+   if (drm_edid)
+   DRM_DEBUG_KMS("Using ACPI provided EDID for %s\n", 
connector->name);
+   else
+   drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
aconnector->drm_edid = drm_edid;
 
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h 
b/drivers/gpu/drm/amd/include/amd_shared.h
index f5b725f10a7c..9702eba767f9 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -264,6 +264,7 @@ enum DC_DEBUG_MASK {
DC_DISABLE_PSR_SU = 0x200,
DC_DISABLE_REPLAY = 0x400,
DC_DISABLE_IPS = 0x800,
+   DC_DISABLE_ACPI_EDID = 0x1000,
 };
 
 enum amd_dpm_forced_level;
-- 
2.43.0



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

2024-09-11 Thread Mario Limonciello
From: 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 DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 63 ++-
 drivers/gpu/drm/amd/include/amd_shared.h  |  1 +
 2 files changed, 63 insertions(+), 1 deletion(-)

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 1118986bb3e2..26d5fff6e185 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
@@ -23,6 +23,8 @@
  *
  */
 
+#include 
+
 #include 
 #include 
 #include 
@@ -874,6 +876,61 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link)
return dp_sink_present;
 }
 
+static int
+dm_helpers_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;
+
+   /* fetch the entire edid from BIOS */
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, &edid);
+   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 const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+   struct drm_connector *connector = &aconnector->base;
+
+   if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+   return 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;
+
+   return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, 
connector);
+}
+
 enum dc_edid_status dm_helpers_read_local_edid(
struct dc_context *ctx,
struct dc_link *link,
@@ -896,7 +953,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
-   drm_edid = drm_edid_read_ddc(connector, ddc);
+   drm_edid = dm_helpers_read_acpi_edid(aconnector);
+   if (drm_edid)
+   DRM_DEBUG_KMS("Using ACPI provided EDID for %s\n", 
connector->name);
+   else
+   drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
aconnector->drm_edid = drm_edid;
 
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h 
b/drivers/gpu/drm/amd/include/amd_shared.h
index f5b725f10a7c..9702eba767f9 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -264,6 +264,7 @@ enum DC_DEBUG_MASK {
DC_DISABLE_PSR_SU = 0x200,
DC_DISABLE_REPLAY = 0x400,
DC_DISABLE_IPS = 0x800,
+   DC_DISABLE_ACPI_EDID = 0x1000,
 };
 
 enum amd_dpm_forced_level;
-- 
2.43.0



[PATCH v6 08/10] drm/amd/display: get SADB from drm_eld when parsing EDID caps

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

drm_edid_connector_update() updates display info, filling ELD with
speaker allocation data in the last step of update_dislay_info(). Our
goal is stopping using raw edid, so we can extract SADB from drm_eld
instead of access raw edid to get audio caps.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
v6: Move changelog below cutlist
v5: add more informative commit description (Alex H)
---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 15 +++
 1 file changed, 3 insertions(+), 12 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 1bc9c12ab120..72ea78ff2c5b 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
@@ -98,9 +98,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
-   int sad_count, sadb_count;
+   int sad_count;
int i = 0;
-   uint8_t *sadb = NULL;
 
enum dc_edid_status result = EDID_OK;
 
@@ -144,20 +143,12 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->audio_modes[i].sample_size = sad.byte2;
}
 
-   sadb_count = drm_edid_to_speaker_allocation((struct edid *) 
edid->raw_edid, &sadb);
 
-   if (sadb_count < 0) {
-   DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", 
sadb_count);
-   sadb_count = 0;
-   }
-
-   if (sadb_count)
-   edid_caps->speaker_flags = sadb[0];
+   if (connector->eld[DRM_ELD_SPEAKER])
+   edid_caps->speaker_flags = connector->eld[DRM_ELD_SPEAKER];
else
edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 
-   kfree(sadb);
-
return result;
 }
 
-- 
2.43.0



[PATCH v6 06/10] drm/amd/display: parse display name from drm_eld

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

We don't need to parse dc_edid to get the display name since it's
already set in drm_eld which in turn had it values updated when updating
connector with the opaque drm_edid.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c  | 10 ++
 1 file changed, 6 insertions(+), 4 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 3f280bc36e87..b42821a02c9a 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
@@ -32,7 +32,7 @@
 #include 
 #include 
 #include 
-
+#include 
 #include "dm_services.h"
 #include "amdgpu.h"
 #include "dc.h"
@@ -78,6 +78,7 @@ static void apply_edid_quirks(struct drm_edid_product_id 
*product_id,
}
 }
 
+#define AMDGPU_ELD_DISPLAY_NAME_SIZE_IN_CHARS 13
 /**
  * dm_helpers_parse_edid_caps() - Parse edid caps
  *
@@ -119,9 +120,10 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->manufacture_week = product_id.week_of_manufacture;
edid_caps->manufacture_year = product_id.year_of_manufacture;
 
-   drm_edid_get_monitor_name(edid_buf,
- edid_caps->display_name,
- AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
+   memset(edid_caps->display_name, 0, 
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
+   memcpy(edid_caps->display_name,
+  &connector->eld[DRM_ELD_MONITOR_NAME_STRING],
+  AMDGPU_ELD_DISPLAY_NAME_SIZE_IN_CHARS);
 
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
 
-- 
2.43.0



[PATCH v6 09/10] drm/amd/display: remove dc_edid handler from dm_helpers_parse_edid_caps

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

We can parse edid caps from drm_edid and drm_eld and any calls of
dm_helpers_parse_edid_caps is made in a state that we have drm_edid set
to amdgpu connector.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
v6:
- Move changelog below cutlist
- Rebase on v6.11-rc7
v5: also remove the parameter from kernel-doc (kernel test bot)
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  5 +---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 30 ---
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  1 -
 .../drm/amd/display/dc/link/link_detection.c  |  6 ++--
 4 files changed, 16 insertions(+), 26 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 a1379ac0e628..d3074a020ba1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7059,10 +7059,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
memmove(dc_em_sink->dc_edid.raw_edid, edid,
(edid->extensions + 1) * EDID_LENGTH);
-   dm_helpers_parse_edid_caps(
-   dc_link,
-   &dc_em_sink->dc_edid,
-   &dc_em_sink->edid_caps);
+   dm_helpers_parse_edid_caps(dc_link, &dc_em_sink->edid_caps);
}
 }
 
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 72ea78ff2c5b..1118986bb3e2 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
@@ -83,32 +83,24 @@ static void apply_edid_quirks(struct drm_edid_product_id 
*product_id,
  * dm_helpers_parse_edid_caps() - Parse edid caps
  *
  * @link: current detected link
- * @edid:  [in] pointer to edid
  * @edid_caps: [in] pointer to edid caps
  *
  * Return: void
  */
-enum dc_edid_status dm_helpers_parse_edid_caps(
-   struct dc_link *link,
-   const struct dc_edid *edid,
-   struct dc_edid_caps *edid_caps)
+enum dc_edid_status dm_helpers_parse_edid_caps(struct dc_link *link,
+  struct dc_edid_caps *edid_caps)
 {
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
-   struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
int sad_count;
int i = 0;
-
enum dc_edid_status result = EDID_OK;
 
-   if (!edid_caps || !edid)
+   if (!edid_caps || !drm_edid)
return EDID_BAD_INPUT;
 
-   if (!drm_edid_is_valid(edid_buf))
-   result = EDID_BAD_CHECKSUM;
-
drm_edid_get_product_id(drm_edid, &product_id);
 
edid_caps->manufacturer_id = le16_to_cpu(product_id.manufacturer_name);
@@ -920,19 +912,23 @@ enum dc_edid_status dm_helpers_read_local_edid(
if (!drm_edid)
return EDID_NO_RESPONSE;
 
-   edid = drm_edid_raw(drm_edid); // FIXME: Get rid of 
drm_edid_raw()
+   /* FIXME: Get rid of drm_edid_raw()
+* Raw edid is still needed for dm_helpers_dp_write_dpcd()
+*/
+   edid = drm_edid_raw(drm_edid);
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, 
sink->dc_edid.length);
 
edid_status = dm_helpers_parse_edid_caps(
link,
-   &sink->dc_edid,
&sink->edid_caps);
 
-   /* We don't need the original edid anymore */
-   drm_edid_free(drm_edid);
-
-   } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
+   if (edid_status != EDID_OK) {
+   /* We can discard the drm_edid and retry */
+   drm_edid_free(drm_edid);
+   drm_edid_connector_update(connector, drm_edid);
+   }
+   } while (edid_status != EDID_OK && --retry > 0);
 
if (edid_status != EDID_OK)
DRM_ERROR("EDID err: %d, on connector: %s",
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h 
b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 34adae7ab6e8..bcdfc46c844e 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -61,

[PATCH v6 07/10] drm/amd/display: get SAD from drm_eld when parsing EDID caps

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

drm_edid_connector_update() updates display info, filling ELD with audio
info from Short-Audio Descriptors in the last step of
update_dislay_info(). Our goal is stopping using raw edid, so we can
extract SAD from drm_eld instead of access raw edid to get audio caps.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
v6:
- Move changelog to below cutlist
v5:
- squash with `don't give initial values for sad/b_count` (Alex H)
- add more informative commit description (Alex H)
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 20 +--
 1 file changed, 10 insertions(+), 10 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 b42821a02c9a..1bc9c12ab120 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
@@ -98,9 +98,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
const struct drm_edid *drm_edid = aconnector->drm_edid;
struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
-   struct cea_sad *sads;
-   int sad_count = -1;
-   int sadb_count = -1;
+   int sad_count, sadb_count;
int i = 0;
uint8_t *sadb = NULL;
 
@@ -129,18 +127,21 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 
apply_edid_quirks(&product_id, edid_caps);
 
-   sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
+   sad_count = drm_eld_sad_count(connector->eld);
if (sad_count <= 0)
return result;
 
edid_caps->audio_mode_count = min(sad_count, DC_MAX_AUDIO_DESC_COUNT);
for (i = 0; i < edid_caps->audio_mode_count; ++i) {
-   struct cea_sad *sad = &sads[i];
+   struct cea_sad sad;
 
-   edid_caps->audio_modes[i].format_code = sad->format;
-   edid_caps->audio_modes[i].channel_count = sad->channels + 1;
-   edid_caps->audio_modes[i].sample_rate = sad->freq;
-   edid_caps->audio_modes[i].sample_size = sad->byte2;
+   if (drm_eld_sad_get(connector->eld, i, &sad) < 0)
+   continue;
+
+   edid_caps->audio_modes[i].format_code = sad.format;
+   edid_caps->audio_modes[i].channel_count = sad.channels + 1;
+   edid_caps->audio_modes[i].sample_rate = sad.freq;
+   edid_caps->audio_modes[i].sample_size = sad.byte2;
}
 
sadb_count = drm_edid_to_speaker_allocation((struct edid *) 
edid->raw_edid, &sadb);
@@ -155,7 +156,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
else
edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 
-   kfree(sads);
kfree(sadb);
 
return result;
-- 
2.43.0



[PATCH v6 05/10] drm/amd/display: use drm_edid_product_id for parsing EDID product info

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

Since [1], we can use drm_edid_product_id to get debug info from
drm_edid instead of directly parsing EDID.

Link: 
https://lore.kernel.org/dri-devel/cover.1712655867.git.jani.nik...@intel.com/ 
[1]
Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
v6: Split apply_edid_quirks() to two lines
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 38 ++-
 1 file changed, 20 insertions(+), 18 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 be72f14f5429..3f280bc36e87 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
@@ -45,16 +45,16 @@
 #include "dm_helpers.h"
 #include "ddc_service_types.h"
 
-static u32 edid_extract_panel_id(struct edid *edid)
+static u32 edid_extract_panel_id(struct drm_edid_product_id *product_id)
 {
-   return (u32)edid->mfg_id[0] << 24   |
-  (u32)edid->mfg_id[1] << 16   |
-  (u32)EDID_PRODUCT_ID(edid);
+   return (u32)be16_to_cpu(product_id->manufacturer_name) << 16 |
+  (u32)le16_to_cpu(product_id->product_code);
 }
 
-static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps 
*edid_caps)
+static void apply_edid_quirks(struct drm_edid_product_id *product_id,
+ struct dc_edid_caps *edid_caps)
 {
-   uint32_t panel_id = edid_extract_panel_id(edid);
+   uint32_t panel_id = edid_extract_panel_id(product_id);
 
switch (panel_id) {
/* Workaround for some monitors which does not work well with FAMS */
@@ -94,6 +94,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 {
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
+   const struct drm_edid *drm_edid = aconnector->drm_edid;
+   struct drm_edid_product_id product_id;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
struct cea_sad *sads;
int sad_count = -1;
@@ -109,13 +111,13 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
if (!drm_edid_is_valid(edid_buf))
result = EDID_BAD_CHECKSUM;
 
-   edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
-   ((uint16_t) edid_buf->mfg_id[1])<<8;
-   edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
-   ((uint16_t) edid_buf->prod_code[1])<<8;
-   edid_caps->serial_number = edid_buf->serial;
-   edid_caps->manufacture_week = edid_buf->mfg_week;
-   edid_caps->manufacture_year = edid_buf->mfg_year;
+   drm_edid_get_product_id(drm_edid, &product_id);
+
+   edid_caps->manufacturer_id = le16_to_cpu(product_id.manufacturer_name);
+   edid_caps->product_id = le16_to_cpu(product_id.product_code);
+   edid_caps->serial_number = le32_to_cpu(product_id.serial_number);
+   edid_caps->manufacture_week = product_id.week_of_manufacture;
+   edid_caps->manufacture_year = product_id.year_of_manufacture;
 
drm_edid_get_monitor_name(edid_buf,
  edid_caps->display_name,
@@ -123,7 +125,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
 
-   apply_edid_quirks(edid_buf, edid_caps);
+   apply_edid_quirks(&product_id, edid_caps);
 
sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
if (sad_count <= 0)
@@ -909,9 +911,9 @@ enum dc_edid_status dm_helpers_read_local_edid(
 * do check sum and retry to make sure read correct edid.
 */
do {
-
drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
+   aconnector->drm_edid = drm_edid;
 
/* DP Compliance Test 4.2.2.6 */
if (link->aux_mode && connector->edid_corrupt)
@@ -929,14 +931,14 @@ enum dc_edid_status dm_helpers_read_local_edid(
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, 
sink->dc_edid.length);
 
-   /* We don't need the original edid anymore */
-   drm_edid_free(drm_edid);
-
edid_status = dm_helpers_parse_edid_caps(
link,
&sink->dc_edid,
&sink->edid_caps);
 
+   /* We don't need the original edid anymore */
+   drm_edid_free(drm_edid);
+
} while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
 
if (edid_status != EDID_OK)
-- 
2.43.0



[PATCH v6 04/10] drm/amd/display: remove redundant freesync parser for DP

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

When updating connector under drm_edid infrastructure, many calculations
and validations are already done and become redundant inside AMD driver.
Remove those driver-specific code in favor of the DRM common code.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
v6:
 * Drop unneeded is_dp_capable_without_timing_msa()
 * Rebase on v6.11-rc7
 * Add Co-developed-by tag
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 91 +--
 1 file changed, 4 insertions(+), 87 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 49a71c575e45..a1379ac0e628 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11737,25 +11737,6 @@ static int amdgpu_dm_atomic_check(struct drm_device 
*dev,
return ret;
 }
 
-static bool is_dp_capable_without_timing_msa(struct dc *dc,
-struct amdgpu_dm_connector 
*amdgpu_dm_connector)
-{
-   u8 dpcd_data;
-   bool capable = false;
-
-   if (amdgpu_dm_connector->dc_link &&
-   dm_helpers_dp_read_dpcd(
-   NULL,
-   amdgpu_dm_connector->dc_link,
-   DP_DOWN_STREAM_PORT_COUNT,
-   &dpcd_data,
-   sizeof(dpcd_data))) {
-   capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
-   }
-
-   return capable;
-}
-
 static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
unsigned int offset,
unsigned int total_length,
@@ -12011,9 +11992,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
const struct drm_edid *drm_edid)
 {
int i = 0;
-   const struct detailed_timing *timing;
-   const struct detailed_non_pixel *data;
-   const struct detailed_data_monitor_range *range;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
@@ -12040,8 +12018,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   connector->display_info.monitor_range.min_vfreq = 0;
-   connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
 
goto update;
@@ -12061,67 +12037,12 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
 sink->sink_signal == SIGNAL_TYPE_EDP)) {
-   bool edid_check_required = false;
-
-   if (is_dp_capable_without_timing_msa(adev->dm.dc,
-amdgpu_dm_connector)) {
-   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) {
-   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
-   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
-   if (amdgpu_dm_connector->max_vfreq -
-   amdgpu_dm_connector->min_vfreq > 10)
-   freesync_capable = true;
-   } else {
-   edid_check_required = edid->version > 1 ||
- (edid->version == 1 &&
-  edid->revision > 1);
-   }
-   }
 
-   if (edid_check_required) {
-   for (i = 0; i < 4; i++) {
-
-   timing  = &edid->detailed_timings[i];
-   data= &timing->data.other_data;
-   range   = &data->data.range;
-   /*
-* Check if monitor has continuous frequency 
mode
-*/
-   if (data->type != EDID_DETAIL_MONITOR_RANGE)
-   continue;
-   /*
-* Check for flag range limits only. If flag == 
1 then
-* no additional timing information provided.
-* Default GTF, GTF Secondary curve and CVT are 
not
-* supported
- 

[PATCH v6 01/10] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.

Signed-off-by: Melissa Wen 
Co-developed-by: Mario Limonciello 
Signed-off-by: Mario Limonciello 
---
v6: Move changelog to cutlist
Update text of commit message
Add missing newline (checkpatch.pl)
Split long line in dm_dp_mst_get_modes()
v5: remove deprecated comments (Alex H)
use edid from dc_sink instead of call drm_edid_raw for now (Alex H)
remove unnecessary cast (Alex H)
v4: rename edid to drm_edid in amdgpu_connector (Jani)
call drm_edid_connector_update to clear edid in case of NULL (Jani)
keep setting NULL instead of free drm_edid (Jani)
check drm_edid not NULL, instead of valid (Jani)
v3: fix general protection fault on mst
v2: use const to fix warnings (Alex Hung)
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 121 --
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  13 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  34 ++---
 4 files changed, 83 insertions(+), 89 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 5942fc4e1c86..4927fdd45073 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3436,7 +3436,7 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
amdgpu_dm_update_freesync_caps(connector,
-   aconnector->edid);
+   aconnector->drm_edid);
} else {
amdgpu_dm_update_freesync_caps(connector, NULL);
if (!aconnector->dc_sink) {
@@ -3495,18 +3495,19 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
if (sink->dc_edid.length == 0) {
-   aconnector->edid = NULL;
+   aconnector->drm_edid = NULL;
if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(
&aconnector->dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+
+   aconnector->drm_edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
+   drm_edid_connector_update(connector, 
aconnector->drm_edid);
 
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
-   aconnector->edid);
+   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, 
edid);
}
 
if (!aconnector->timing_requested) {
@@ -3517,17 +3518,18 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
-   amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->drm_edid);
+   amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->drm_edid);
+   aconnector->drm_edid = NULL;
kfree(aconnector->timing_requested);
aconnector->timing_requested = NULL;
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
again on hotplug */
@@ -7041,32 +7043,24 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector)

[PATCH v6 03/10] drm/amd/display: always call connector_update when parsing freesync_caps

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

Update connector caps with drm_edid data before parsing info for
freesync.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 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 f19afa117f15..49a71c575e45 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3518,13 +3518,11 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_edid_connector_update(connector, aconnector->drm_edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -12035,6 +12033,8 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
amdgpu_dm_connector->dc_sink :
amdgpu_dm_connector->dc_em_sink;
 
+   drm_edid_connector_update(connector, drm_edid);
+
if (!drm_edid || !sink) {
dm_con_state = to_dm_connector_state(connector->state);
 
-- 
2.43.0



[PATCH v6 02/10] drm/amd/display: switch to setting physical address directly

2024-09-11 Thread Mario Limonciello
From: Melissa Wen 

Connectors have source physical address available in display
info. Use drm_dp_cec_attach() to use it instead of parsing the EDID
again.

Signed-off-by: Melissa Wen 
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++---
 1 file changed, 3 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 4927fdd45073..f19afa117f15 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3497,8 +3497,7 @@ void amdgpu_dm_update_connector_after_detect(
if (sink->dc_edid.length == 0) {
aconnector->drm_edid = NULL;
if (aconnector->dc_link->aux_mode) {
-   drm_dp_cec_unset_edid(
-   &aconnector->dm_dp_aux.aux);
+   
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
}
} else {
const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
@@ -3507,7 +3506,8 @@ void amdgpu_dm_update_connector_after_detect(
drm_edid_connector_update(connector, 
aconnector->drm_edid);
 
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, 
edid);
+   drm_dp_cec_attach(&aconnector->dm_dp_aux.aux,
+ 
connector->display_info.source_physical_address);
}
 
if (!aconnector->timing_requested) {
-- 
2.43.0



[PATCH v6 00/10] drm/amd/display: Use drm_edid for more code

2024-09-11 Thread Mario Limonciello
From: Mario Limonciello 

This is the successor of Melissa's v5 series that was posted [1] as well
as my series that was posted [2].

Melissa's patches are mostly unmodified from v5, but modified to apply on
top of v6.11-rc7 instead.
The same limitations she called out with amd-staging-drm-next missing
symbols from the development release still apply. So applying this series
will probably need to wait for that to be rebased.

As were both touching similar code for fetching the EDID, I've merged the
pertinent parts of my series into this one in allowing the connector to
fetch the EDID from _DDC if available for eDP as well.

There are still some remaining uses of drm_edid_raw() but they touch pure
DC code, so a wrapper or macro will probably be needed to convert them.
This can be for follow ups later on.

Link: https://lore.kernel.org/amd-gfx/20240807203207.2830-1-m...@igalia.com/ 
[1] 
Link: 
https://lore.kernel.org/dri-devel/20240214215756.6530-1-mario.limoncie...@amd.com/
 [2]
Mario Limonciello (1):
  drm/amd: Fetch the EDID from _DDC if available for eDP

Melissa Wen (9):
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid
  drm/amd/display: switch to setting physical address directly
  drm/amd/display: always call connector_update when parsing
freesync_caps
  drm/amd/display: remove redundant freesync parser for DP
  drm/amd/display: use drm_edid_product_id for parsing EDID product info
  drm/amd/display: parse display name from drm_eld
  drm/amd/display: get SAD from drm_eld when parsing EDID caps
  drm/amd/display: get SADB from drm_eld when parsing EDID caps
  drm/amd/display: remove dc_edid handler from
dm_helpers_parse_edid_caps

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 215 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 173 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  34 +--
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |   1 -
 .../drm/amd/display/dc/link/link_detection.c  |   6 +-
 drivers/gpu/drm/amd/include/amd_shared.h  |   1 +
 7 files changed, 196 insertions(+), 238 deletions(-)

-- 
2.43.0



Re: [PATCH] amdgpu: disable amdgpu_dpm on THTF-SW831-1W-DS25_MB board

2024-08-28 Thread Mario Limonciello

On 8/28/2024 11:14, Alex Deucher wrote:

On Wed, Aug 28, 2024 at 11:47 AM WangYuli  wrote:



On 2024/8/28 23:30, Alex Deucher wrote:

On Wed, Aug 28, 2024 at 7:28 AM WangYuli  wrote:

This will disable dpm on all devices that you might install on this
platform.  If this is specific to a particular platform and board
combination, it might be better to check the platform in the
dpm_init() code for the specific chip that is problematic.
Additionally, disabling dpm will result in boot clocks which means
performance will be very low.

Alex


This motherboard model doesn't have combinations with different
platforms or chipsets now.Their model numbers are unique,so it seems
unnecessary to add extra judgment.


The error message looks to be from an SI board which is a dGPU.  Is
that dGPU integrated into the motherboard?  Does the motherboard have
PCIe slots?  If there are PCIe slots you could presumably put any GPU
into it and if you did, dpm would be disabled by default.

Alex


I would also then question whether the SI board also has failures in 
other systems.  If notit could point at BIOS bugs with the PCIe 
implementation from the MB.


One thing that you can try to do is turn off pcie port pm using the 
kernel command line and see if things improve.  Some motherboards have 
had issues with this in the past.


Re: [PATCH] amdgpu: disable amdgpu_dpm on THTF-SW831-1W-DS25_MB board

2024-08-28 Thread Mario Limonciello

On 8/28/2024 05:59, WangYuli wrote:

From: wenlunpeng 

The quirk is for reboot-stability.

A device reboot stress test has been observed to cause
random system hangs when amdgpu_dpm is enabled.

Disabling amdgpu_dpm can fix this.

However, a boot-param can still overwrite it to enable
amdgpu_dpm.

Serial log when error occurs:
...
Console: switching to colour frame buffer device 160x45
amdgpu :01:00.0: fb0: amdgpudrmfb frame buffer device
[drm:amdgpu_device_ip_late_init] *ERROR* late_init of IP block  failed 
-22
amdgpu :01:00.0: amdgpu_device_ip_late_init failed
amdgpu :01:00.0: Fatal error during GPU init
[drm] amdgpu: finishing device.
Console: switching to colour dummy device 80x25
...


This is production hardware?

Have you already checked whether a BIOS upgrade for the device could 
help this issue?




Signed-off-by: wenlunpeng 
Signed-off-by: WangYuli 


Just to clarify did you guys co-work on this patch, or are you 
submitting on behalf of wenlunpeng?  It right now shows up as you 
submitting on behalf of wenlunpeng.  If you co-worked on it you should 
also use a Co-Developed-by tag.



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

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 094498a0964b..81716fcac7cd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -32,6 +32,7 @@
  #include 
  
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -3023,10 +3024,32 @@ static struct pci_driver amdgpu_kms_pci_driver = {
.dev_groups = amdgpu_sysfs_groups,
  };
  
+static int quirk_set_amdgpu_dpm_0(const struct dmi_system_id *dmi)

+{
+   amdgpu_dpm = 0;
+   pr_info("Identified '%s', set amdgpu_dpm to 0.\n", dmi->ident);
+   return 1;
+}
+
+static const struct dmi_system_id amdgpu_quirklist[] = {
+   {
+   .ident = "DS25 Desktop",
+   .matches = {
+   DMI_MATCH(DMI_BOARD_NAME, "THTF-SW831-1W-DS25_MB"),


As this is suspected to be a BIOS issue, I would like to better 
understand if the BIOS upgrade fixes it.  If it does but you would still 
like a quirk for the system it should include the BIOS version here.



+   },
+   .callback = quirk_set_amdgpu_dpm_0,
+   },
+   {}
+};
+
  static int __init amdgpu_init(void)
  {
int r;
  
+	/* quirks for some hardware, applied only when it's untouched */

+   if (amdgpu_dpm == -1)
+   dmi_check_system(amdgpu_quirklist);
+
if (drm_firmware_drivers_only())
return -EINVAL;
  




Re: [PATCH v6 2/4] drm/amd/display: Add support for minimum backlight quirk

2024-08-26 Thread Mario Limonciello

On 8/24/2024 13:33, Thomas Weißschuh wrote:

Not all platforms provide the full range of PWM backlight capabilities
supported by the hardware through ATIF.
Use the generic drm panel minimum backlight quirk infrastructure to
override the capabilities where necessary.

Testing the backlight quirk together with the "panel_power_savings"
sysfs file has not shown any negative impact.
One quirk seems to be that 0% at panel_power_savings=0 seems to be
slightly darker than at panel_power_savings=4.


Thanks; This is the kind of thing I was worried about.

Harry, Leo,

Is that expected?  I wonder if we need to internally turn off panel 
power savings in display code when brightness falls a threshold (12 IIRC 
was the real "minimum" advertised in the table?).




Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 
Reviewed-by: Mario Limonciello 
---
  drivers/gpu/drm/amd/amdgpu/Kconfig|  1 +
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++
  2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 0051fb1b437f..655c10aef2e3 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -23,6 +23,7 @@ config DRM_AMDGPU
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
+   select DRM_PANEL_BACKLIGHT_QUIRKS
# 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
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 983a977632ff..056960ea335c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -93,6 +93,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -,6 +3334,8 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
struct drm_connector *conn_base;
struct amdgpu_device *adev;
struct drm_luminance_range_info *luminance_range;
+   const struct drm_edid *drm_edid;
+   int min_input_signal_override;
  
  	if (aconnector->bl_idx == -1 ||

aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
@@ -3367,6 +3370,13 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
caps->aux_min_input_signal = 0;
caps->aux_max_input_signal = 512;
}
+
+   drm_edid = drm_edid_alloc(aconnector->edid,
+ EDID_LENGTH * (aconnector->edid->extensions + 
1));
+   min_input_signal_override = 
drm_get_panel_min_brightness_quirk(drm_edid);
+   drm_edid_free(drm_edid);
+   if (min_input_signal_override >= 0)
+   caps->min_input_signal = min_input_signal_override;
  }
  
  void amdgpu_dm_update_connector_after_detect(






Re: [PATCH] drm/amd: Don't wake dGPUs while reading sensors

2024-08-25 Thread Mario Limonciello




On 8/25/24 15:40, Luna Nova wrote:

Raised this as an issue a while back on the bug tracker and it got closed as 
WONTFIX. https://gitlab.freedesktop.org/drm/amd/-/issues/2229
Been running a patched kernel with a similar patch locally ever since because 
even figuring out everything on the system that's accidentally waking the GPU 
was too time consuming.

I'd love if this gets accepted.
I think fundamentally waking the device to ask how much power it is using thus 
increasing the power usage makes no sense - by trying to measure it we changed 
it, so if power can't be measured while off it only makes sense to return an 
error. Same applies for other sensors that currently wake the GPU - most of 
them are changing the property by waking it.

Because this behavior is odd and it's not obvious on single GPU systems that anything's 
going wrong app and lib devs are likely to keep making this "mistake" forever.

Luna


So FWIW I did file a v2 [1] that "undoes" the debugfs changes.

[1] 
https://lore.kernel.org/amd-gfx/20240823145527.150749-1-mario.limoncie...@amd.com/


If there is too much push back to an error code another option we can do 
is return "0" for this case, which will make "sense" for some sysfs 
files specifically if in d3cold.  However for d3hot and some sysfs it 
isn't fully true.


[PATCH v2 2/2] drm/amd: Don't wake dGPUs while reading sensors

2024-08-23 Thread Mario Limonciello
If the dGPU is off, then reading the sysfs files with a sensor monitoring
application will wake it. Change the behavior to return an error when the
dGPU is in runtime PM.  Leave the behavior the same for debugfs files.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/pm/amdgpu_pm.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index bbd6f3e617358..cca08eea0e26a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -101,14 +101,18 @@ static bool amdgpu_sysfs_attr_accessible(struct 
amdgpu_device *adev)
 {
if (amdgpu_in_reset(adev))
return false;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return false;
return true;
 }
 
 static bool amdgpu_debugfs_attr_accessible(struct amdgpu_device *adev)
 {
-   return amdgpu_sysfs_attr_accessible(adev);
+   if (amdgpu_in_reset(adev))
+   return false;
+   if (adev->in_suspend && !adev->in_runpm)
+   return false;
+   return true;
 }
 
 /**
-- 
2.43.0



[PATCH v2 1/2] drm/amd: Reduce sysfs and debugfs attribute boilerplate

2024-08-23 Thread Mario Limonciello
All accesses to attributes have a check for reset/suspend/runpm. Move this
code into dedicated functions. No intended functional changes.

Signed-off-by: Mario Limonciello 
---
v1->v2:
 * Split out to two patches to reduce boilerplate with common functions
 * Different behavior for sysfs and debugfs

 drivers/gpu/drm/amd/pm/amdgpu_pm.c | 194 +
 1 file changed, 59 insertions(+), 135 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index d5d6ab484e5ad..bbd6f3e617358 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -97,6 +97,20 @@ const char * const amdgpu_pp_profile_name[] = {
"UNCAPPED",
 };
 
+static bool amdgpu_sysfs_attr_accessible(struct amdgpu_device *adev)
+{
+   if (amdgpu_in_reset(adev))
+   return false;
+   if (adev->in_suspend && !adev->in_runpm)
+   return false;
+   return true;
+}
+
+static bool amdgpu_debugfs_attr_accessible(struct amdgpu_device *adev)
+{
+   return amdgpu_sysfs_attr_accessible(adev);
+}
+
 /**
  * DOC: power_dpm_state
  *
@@ -140,9 +154,7 @@ static ssize_t amdgpu_get_power_dpm_state(struct device 
*dev,
enum amd_pm_state_type pm;
int ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -171,9 +183,7 @@ static ssize_t amdgpu_set_power_dpm_state(struct device 
*dev,
enum amd_pm_state_type  state;
int ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
if (strncmp("battery", buf, strlen("battery")) == 0)
@@ -268,9 +278,7 @@ static ssize_t 
amdgpu_get_power_dpm_force_performance_level(struct device *dev,
enum amd_dpm_forced_level level = 0xff;
int ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -307,9 +315,7 @@ static ssize_t 
amdgpu_set_power_dpm_force_performance_level(struct device *dev,
enum amd_dpm_forced_level level;
int ret = 0;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
if (strncmp("low", buf, strlen("low")) == 0) {
@@ -369,9 +375,7 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev,
uint32_t i;
int buf_len, ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -407,9 +411,7 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev,
enum amd_pm_state_type pm = 0;
int i = 0, ret = 0;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -446,9 +448,7 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
if (adev->pm.pp_force_state_enabled)
@@ -469,9 +469,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,
unsigned long idx;
int ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
adev->pm.pp_force_state_enabled = false;
@@ -539,9 +537,7 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
char *table = NULL;
int size, ret;
 
-   if (amdgpu_in_reset(adev))
-   return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (!amdgpu_sysfs_attr_accessible(adev))
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -575,9 +571,7 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
struct amdgpu

Re: [PATCH] drm/amd: Don't wake dGPUs while reading sensors

2024-08-23 Thread Mario Limonciello

On 8/23/2024 09:31, Alex Deucher wrote:

On Fri, Aug 23, 2024 at 10:13 AM Mario Limonciello
 wrote:


On 8/23/2024 09:09, Alex Deucher wrote:

On Mon, Aug 19, 2024 at 10:30 PM Mario Limonciello  wrote:


From: Mario Limonciello 

If the dGPU is off, then reading the sysfs files with a sensor monitoring
application will wake it. Change the behavior to return an error when the
dGPU is in D3cold.


I'm a little concerned that this will generate a flurry of bug reports
if this now reports an error.  One more comment below.



Do you have a particular app you're worried about, or just a general
worry?  I've had a lot of people reach out to me complaining about
battery life on A+A systems, and it comes down to the use of sensor
monitoring software waking the dGPU which people don't seem to expect.


Nothing in particular.  Just expecting reports of "I checked my GPU
temperature and it returned an error.  It was working with the last
kernel."



I did double check that software like 'sensors', 'mission center' and
'nvtop' don't freak out from this change.


Do we know what other devices do?  


I'm not sure.  Let me CC Luke Jones, he might know.


I wonder if it would make more
sense to have the userspace tools check the runpm state before trying
to access the device.  Of course there are a lot of them and fixing
them all is non-trivial...


Yes that's another way to go about it.  But I've raised a bug with 
mission center folks 8 months ago [1] to tell them to stop querying 
dGPUs in runtime PM, and Luke Jones also raised it with them 4 months 
earlier [2] but it's still not sorted in their project.


[1] https://gitlab.com/mission-center-devs/mission-center/-/issues/143
[2] https://gitlab.com/mission-center-devs/mission-center/-/issues/30

I suspect we'll hit similar road blocks with the dozens of other 
softwares that do this.  So that's why I was thinking cut off the 
snake's head.




Alex



Here is what 'sensors' shows on my local workstation with this change.

amdgpu-pci-6100
Adapter: PCI adapter
vddgfx:   N/A
ERROR: Can't get value of subfeature fan1_min: Can't read
ERROR: Can't get value of subfeature fan1_max: Can't read
fan1: N/A  (min =0 RPM, max =0 RPM)
edge: N/A  (crit = +97.0°C, hyst = -273.1°C)
ERROR: Can't get value of subfeature power1_cap: Can't read
PPT:  N/A  (cap =   0.00 W)



Signed-off-by: Mario Limonciello 
---
   drivers/gpu/drm/amd/pm/amdgpu_pm.c | 90 +++---
   1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index c11952a4389bc..d6e38466fbb82 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -142,7 +142,7 @@ static ssize_t amdgpu_get_power_dpm_state(struct device 
*dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
  return -EPERM;

  ret = pm_runtime_get_sync(ddev->dev);
@@ -173,7 +173,7 @@ static ssize_t amdgpu_set_power_dpm_state(struct device 
*dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
  return -EPERM;

  if (strncmp("battery", buf, strlen("battery")) == 0)
@@ -270,7 +270,7 @@ static ssize_t 
amdgpu_get_power_dpm_force_performance_level(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
  return -EPERM;

  ret = pm_runtime_get_sync(ddev->dev);
@@ -309,7 +309,7 @@ static ssize_t 
amdgpu_set_power_dpm_force_performance_level(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
  return -EPERM;

  if (strncmp("low", buf, strlen("low")) == 0) {
@@ -371,7 +371,7 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
  return -EPERM;

  ret = pm_runtime_get_sync(ddev->dev);
@@ -409,7 +409,7 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+  

Re: [PATCH] drm/amd: Don't wake dGPUs while reading sensors

2024-08-23 Thread Mario Limonciello

On 8/23/2024 09:09, Alex Deucher wrote:

On Mon, Aug 19, 2024 at 10:30 PM Mario Limonciello  wrote:


From: Mario Limonciello 

If the dGPU is off, then reading the sysfs files with a sensor monitoring
application will wake it. Change the behavior to return an error when the
dGPU is in D3cold.


I'm a little concerned that this will generate a flurry of bug reports
if this now reports an error.  One more comment below.



Do you have a particular app you're worried about, or just a general 
worry?  I've had a lot of people reach out to me complaining about 
battery life on A+A systems, and it comes down to the use of sensor 
monitoring software waking the dGPU which people don't seem to expect.


I did double check that software like 'sensors', 'mission center' and 
'nvtop' don't freak out from this change.


Here is what 'sensors' shows on my local workstation with this change.

amdgpu-pci-6100
Adapter: PCI adapter
vddgfx:   N/A
ERROR: Can't get value of subfeature fan1_min: Can't read
ERROR: Can't get value of subfeature fan1_max: Can't read
fan1: N/A  (min =0 RPM, max =0 RPM)
edge: N/A  (crit = +97.0°C, hyst = -273.1°C)
ERROR: Can't get value of subfeature power1_cap: Can't read
PPT:  N/A  (cap =   0.00 W)



Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/amd/pm/amdgpu_pm.c | 90 +++---
  1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index c11952a4389bc..d6e38466fbb82 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -142,7 +142,7 @@ static ssize_t amdgpu_get_power_dpm_state(struct device 
*dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 ret = pm_runtime_get_sync(ddev->dev);
@@ -173,7 +173,7 @@ static ssize_t amdgpu_set_power_dpm_state(struct device 
*dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 if (strncmp("battery", buf, strlen("battery")) == 0)
@@ -270,7 +270,7 @@ static ssize_t 
amdgpu_get_power_dpm_force_performance_level(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 ret = pm_runtime_get_sync(ddev->dev);
@@ -309,7 +309,7 @@ static ssize_t 
amdgpu_set_power_dpm_force_performance_level(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 if (strncmp("low", buf, strlen("low")) == 0) {
@@ -371,7 +371,7 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 ret = pm_runtime_get_sync(ddev->dev);
@@ -409,7 +409,7 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 ret = pm_runtime_get_sync(ddev->dev);
@@ -448,7 +448,7 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 if (adev->pm.pp_force_state_enabled)
@@ -471,7 +471,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 adev->pm.pp_force_state_enabled = false;
@@ -541,7 +541,7 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,

 if (amdgpu_in_reset(adev))
 return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
 return -EPERM;

 ret = pm_runtime_get_sync(ddev->

Re: [PATCH] drm/amd: Don't wake dGPUs while reading sensors

2024-08-23 Thread Mario Limonciello

On 8/23/2024 08:44, Hamza Mahfooz wrote:

On 8/19/24 22:04, Mario Limonciello wrote:

From: Mario Limonciello 

If the dGPU is off, then reading the sysfs files with a sensor monitoring
application will wake it. Change the behavior to return an error when the
dGPU is in D3cold.

Signed-off-by: Mario Limonciello 
---
  drivers/gpu/drm/amd/pm/amdgpu_pm.c | 90 +++---
  1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c

index c11952a4389bc..d6e38466fbb82 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -142,7 +142,7 @@ static ssize_t amdgpu_get_power_dpm_state(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)


Seems like this expression is used rather often, so it might be good to
have an inline function for it. Something like the following:

static inline bool amdgpu_is_d3cold(struct amdgpu_dev *adev)
{
 return adev->in_suspend || adev->in_runpm;
}



Thanks for the review.  Not only in that expression used frequently but 
also the check if it's in reset.  Considering that I'm thinking to make 
a non-inline function for every one of these like this to drop the 
boilerplate.


static bool amdgpu_attr_accessible(struct amdgpu_dev *adev)
{
if (amdgpu_in_reset(adev))
return false;
if (adev->in_suspend)
return false;
if (adev->in_runpm)
return false;
return true;
}

and then each use can be:

if (!amdgpu_attr_accessible(adev))
return -EPERM;


  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -173,7 +173,7 @@ static ssize_t amdgpu_set_power_dpm_state(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  if (strncmp("battery", buf, strlen("battery")) == 0)
@@ -270,7 +270,7 @@ static ssize_t 
amdgpu_get_power_dpm_force_performance_level(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -309,7 +309,7 @@ static ssize_t 
amdgpu_set_power_dpm_force_performance_level(struct device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  if (strncmp("low", buf, strlen("low")) == 0) {
@@ -371,7 +371,7 @@ static ssize_t amdgpu_get_pp_num_states(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -409,7 +409,7 @@ static ssize_t amdgpu_get_pp_cur_state(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -448,7 +448,7 @@ static ssize_t amdgpu_get_pp_force_state(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  if (adev->pm.pp_force_state_enabled)
@@ -471,7 +471,7 @@ static ssize_t amdgpu_set_pp_force_state(struct 
device *dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  adev->pm.pp_force_state_enabled = false;
@@ -541,7 +541,7 @@ static ssize_t amdgpu_get_pp_table(struct device 
*dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -577,7 +577,7 @@ static ssize_t amdgpu_set_pp_table(struct device 
*dev,

  if (amdgpu_in_reset(adev))
  return -EPERM;
-    if (adev->in_suspend && !adev->in_runpm)
+    if (adev->in_suspend || adev->in_runpm)
  return -EPERM;
  ret = pm_runtime_get_sync(ddev->dev);
@@ -760,7 +760,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct 
device *dev,

  if (amdgpu_in_reset(adev))

Re: [PATCH] drm/amdgpu: fix OLAND card ip_init failed during kdump caputrue kernel boot

2024-08-22 Thread Mario Limonciello

On 7/23/2024 04:42, Lu Yao wrote:

[Why]
When running kdump test on a machine with R7340 card, a hang is caused due
to the failure of 'amdgpu_device_ip_init()', error message as follows:

   '[drm:amdgpu_device_ip_init [amdgpu]] *ERROR* hw_init of IP block  
failed -22'
   '[drm:uvd_v3_1_hw_init [amdgpu]] *ERROR* amdgpu: UVD Firmware validate fail 
(-22).'
   '[drm:amdgpu_device_ip_init [amdgpu]] *ERROR* hw_init of IP block  
failed -22'
   'amdgpu :01:00.0: amdgpu: amdgpu_device_ip_init failed'
   'amdgpu :01:00.0: amdgpu: Fatal error during GPU init'

This is because the caputrue kernel does not power off when it starts,


Presumably you mean:
s/caputrue/capture/


cause hardware status does not reset.

[How]
Add 'is_kdump_kernel()' judgment.
For 'si_dpm' block, use disable and then enable.
For 'uvd_v3_1' block, skip loading during the initialization phase.

Signed-off-by: Lu Yao 
---
During test, I first modified the 'amdgpu_device_ip_hw_init_phase*', make
it does not end directly when a block hw_init failed.

After analysis, 'si_dpm' block failed at 'si_dpm_enable()->
amdgpu_si_is_smc_running()', calling 'si_dpm_disable()' before can resolve.
'uvd_v3_1' block failed at 'uvd_v3_1_hw_init()->uvd_v3_1_fw_validate()',
read mmUVD_FW_STATUS value is 0x27220102, I didn't find out why. But for
caputrue kernel, UVD is not required. Therefore, don't added this block.


Hmm, a few thoughs.

1) Although you used this for the R7340, these concepts you're 
identifying probably make sense on most AMD GPUs.  SUch checks might be 
better to uplevel to earlier in IP discovery code.


2) I'd actually argue we don't want to have the kdump capture kernel do 
ANY hardware init.  You're going to lose hardware state which "could" be 
valuable information for debugging a problem that caused a panic.


That being said, I'm not really sure what framebuffer can drive the 
display across a kexec if you don't load amdgpu.  What actually happens 
if you blacklist amdgpu in the capture kernel?


What happens with your patch in place?

At least for me I'd like to see a kernel log from both cases.


---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h| 1 +
  drivers/gpu/drm/amd/amdgpu/si.c| 6 --
  drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c | 6 ++
  3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 137a88b8de45..52ebc24561c4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -50,6 +50,7 @@
  #include 
  #include 
  #include 
+#include 
  
  #include 

  #include 
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index 85235470e872..fc0daed1b829 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -2739,7 +2739,8 @@ int si_set_ip_blocks(struct amdgpu_device *adev)
  #endif
else
amdgpu_device_ip_block_add(adev, &dce_v6_0_ip_block);
-   amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block);
+   if (!is_kdump_kernel())
+   amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block);
/* amdgpu_device_ip_block_add(adev, &vce_v1_0_ip_block); */
break;
case CHIP_OLAND:
@@ -2757,7 +2758,8 @@ int si_set_ip_blocks(struct amdgpu_device *adev)
  #endif
else
amdgpu_device_ip_block_add(adev, &dce_v6_4_ip_block);
-   amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block);
+   if (!is_kdump_kernel())
+   amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block);
/* amdgpu_device_ip_block_add(adev, &vce_v1_0_ip_block); */
break;
case CHIP_HAINAN:
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c 
b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index a1baa13ab2c2..8700a22ba809 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -1848,6 +1848,7 @@ static int si_calculate_sclk_params(struct amdgpu_device 
*adev,
  static void si_thermal_start_smc_fan_control(struct amdgpu_device *adev);
  static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev);
  static void si_dpm_set_irq_funcs(struct amdgpu_device *adev);
+static void si_dpm_disable(struct amdgpu_device *adev);
  
  static struct si_power_info *si_get_pi(struct amdgpu_device *adev)

  {
@@ -6811,6 +6812,11 @@ static int si_dpm_enable(struct amdgpu_device *adev)
struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
int ret;
  
+	if (is_kdump_kernel()) {

+   si_dpm_disable(adev);
+   udelay(50);
+   }
+
if (amdgpu_si_is_smc_running(adev))
return -EINVAL;
if (pi->voltage_control || si_pi->voltage_control_svi2)




Re: [PATCH v5 2/4] drm/amd/display: Add support for minimum backlight quirk

2024-08-22 Thread Mario Limonciello

On 8/22/2024 01:14, Thomas Weißschuh wrote:

On 2024-08-21 15:54:14+, Mario Limonciello wrote:

On 8/18/2024 01:56, Thomas Weißschuh wrote:

Not all platforms provide correct PWM backlight capabilities through ATIF.


I don't think correct is an accurate term here.  How about 'optimial'?


Looks typoed to me :-)


heh.



What about this?

Not all platforms provide the full range of PWM backlight capabilities
supported by the hardware through ATIF.


Sounds great, thanks!




Use the generic drm panel minimum backlight quirk infrastructure to
override the capabilities where necessary.

Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 


The code looks fine to me but please wait for an ack from someone on the AMD
display team.

Also, I would like to see comments about the testing with panel power
savings enabled to avoid a conflict.


Ack.



Reviewed-by: Mario Limonciello 

---
   drivers/gpu/drm/amd/amdgpu/Kconfig|  1 +
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++
   2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 0051fb1b437f..655c10aef2e3 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -23,6 +23,7 @@ config DRM_AMDGPU
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
+   select DRM_PANEL_BACKLIGHT_QUIRKS
# 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
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 983a977632ff..056960ea335c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -93,6 +93,7 @@
   #include 
   #include 
   #include 
+#include 
   #include 
   #include 
   #include 
@@ -,6 +3334,8 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
struct drm_connector *conn_base;
struct amdgpu_device *adev;
struct drm_luminance_range_info *luminance_range;
+   const struct drm_edid *drm_edid;
+   int min_input_signal_override;
if (aconnector->bl_idx == -1 ||
aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
@@ -3367,6 +3370,13 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
caps->aux_min_input_signal = 0;
caps->aux_max_input_signal = 512;
}
+
+   drm_edid = drm_edid_alloc(aconnector->edid,
+ EDID_LENGTH * (aconnector->edid->extensions + 
1));
+   min_input_signal_override = 
drm_get_panel_min_brightness_quirk(drm_edid);
+   drm_edid_free(drm_edid);
+   if (min_input_signal_override >= 0)
+   caps->min_input_signal = min_input_signal_override;
   }
   void amdgpu_dm_update_connector_after_detect(







Re: [PATCH v5 1/4] drm: Add panel backlight quirks

2024-08-22 Thread Mario Limonciello

On 8/22/2024 01:12, Thomas Weißschuh wrote:

On 2024-08-21 15:51:17+, Mario Limonciello wrote:

On 8/18/2024 01:56, Thomas Weißschuh wrote:

Panels using a PWM-controlled backlight source do not have a standard
way to communicate their valid PWM ranges.
On x86 the ranges are read from ACPI through driver-specific tables.
The built-in ranges are not necessarily correct, or may grow stale if an
older device can be retrofitted with newer panels.

Add a quirk infrastructure with which the minimum valid backlight value
can be maintained as part of the kernel.

Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 


One small nit below but otherwise this patch is fine to me.

Reviewed-by: Mario Limonciello 


---
   Documentation/gpu/drm-kms-helpers.rst|  3 ++
   drivers/gpu/drm/Kconfig  |  4 ++
   drivers/gpu/drm/Makefile |  1 +
   drivers/gpu/drm/drm_panel_backlight_quirks.c | 70 

   include/drm/drm_utils.h  |  4 ++
   5 files changed, 82 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index 8435e8621cc0..a26989500129 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -230,6 +230,9 @@ Panel Helper Reference
   .. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c
  :export:
+.. kernel-doc:: drivers/gpu/drm/drm_panel_backlight_quirks.c
+   :export:
+
   Panel Self Refresh Helper Reference
   ===
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6b2c6b91f962..9ebb8cdb535e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -454,6 +454,10 @@ config DRM_HYPERV
   config DRM_EXPORT_FOR_TESTS
bool
+# Separate option as not all DRM drivers use it
+config DRM_PANEL_BACKLIGHT_QUIRKS
+   tristate
+
   config DRM_LIB_RANDOM
bool
default n
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 68cc9258ffc4..adf85999aee2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -92,6 +92,7 @@ drm-$(CONFIG_DRM_PANIC) += drm_panic.o
   obj-$(CONFIG_DRM)+= drm.o
   obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
+obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
   #
   # Memory-management helpers
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c 
b/drivers/gpu/drm/drm_panel_backlight_quirks.c
new file mode 100644
index ..6b8bbed77c7f
--- /dev/null
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct drm_panel_min_backlight_quirk {
+   struct {
+   enum dmi_field field;
+   const char * const value;
+   } dmi_match;
+   struct drm_edid_ident ident;
+   u8 min_brightness;
+};
+
+static const struct drm_panel_min_backlight_quirk 
drm_panel_min_backlight_quirks[] = {
+};
+
+static bool drm_panel_min_backlight_quirk_matches(const struct 
drm_panel_min_backlight_quirk *quirk,
+ const struct drm_edid *edid)
+{
+   if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
+   return false;
+
+   if (!drm_edid_match(edid, &quirk->ident))
+   return false;
+
+   return true;
+}
+
+/**
+ * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level 
for a panel.
+ * @edid: EDID of the panel to check
+ *
+ * This function checks for platform specific (e.g. DMI based) quirks
+ * providing info on the minimum backlight brightness for systems where this
+ * cannot be probed correctly from the hard-/firm-ware.
+ *
+ * Returns:
+ * A negative error value or
+ * an override value in the range [0, 255] representing 0-100% to be scaled to
+ * the drivers target range.
+ */
+int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
+{
+   const struct drm_panel_min_backlight_quirk *quirk;
+   size_t i;


Nit: this doesn't really seem like it needs to be size_t.  Shouldn't it just
be an unsigned int?


ARRAY_SIZE() works with sizeof() which returns size_t.
It doesn't really matter, but I slightly prefer to keep the size_t.


Ah thanks, I didn't realize that.  Feel free to leave as is then.




+
+   if (!IS_ENABLED(CONFIG_DMI))
+   return -ENODATA;
+
+   if (!edid)
+   return -EINVAL;
+
+   for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
+   quirk = &drm_panel_min_backlight_quirks[i];
+
+   if (drm_panel_min_backlight_quirk_matches(quirk, edid))
+   return quirk->min_brightness;
+   }
+
+   return -ENODATA;
+}
+EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
+
+MODULE_DESCRI

Re: [PATCH v5 4/4] drm: panel-backlight-quirks: Add Framework 13 glossy and 2.8k panels

2024-08-21 Thread Mario Limonciello

On 8/18/2024 01:56, Thomas Weißschuh wrote:

From: "Dustin L. Howett" 

I have tested these panels on the Framework Laptop 13 AMD with firmware
revision 3.05 (latest at time of submission).

Signed-off-by: Dustin L. Howett 


When you send someone else's patch you need to add your own S-o-b as 
well.  Please add that for v6.  Otherwise:


Reviewed-by: Mario Limonciello 


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

diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c 
b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index f2aefff618dd..c477d98ade2b 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -25,6 +25,22 @@ static const struct drm_panel_min_backlight_quirk 
drm_panel_min_backlight_quirks
.ident.name = "NE135FBM-N41",
.min_brightness = 0,
},
+   /* 13 inch glossy panel */
+   {
+   .dmi_match.field = DMI_BOARD_VENDOR,
+   .dmi_match.value = "Framework",
+   .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 
0x095f),
+   .ident.name = "NE135FBM-N41",
+   .min_brightness = 0,
+   },
+   /* 13 inch 2.8k panel */
+   {
+   .dmi_match.field = DMI_BOARD_VENDOR,
+   .dmi_match.value = "Framework",
+   .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 
0x0cb4),
+   .ident.name = "NE135A1M-NY1",
+   .min_brightness = 0,
+   },
  };
  
  static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,






Re: [PATCH v5 3/4] drm: panel-backlight-quirks: Add Framework 13 matte panel

2024-08-21 Thread Mario Limonciello

On 8/18/2024 01:56, Thomas Weißschuh wrote:

The value of "min_input_signal" returned from ATIF on a Framework AMD 13
is "12". This leads to a fairly bright minimum display backlight.

Add a quirk to override that the minimum backlight PWM to "0" which
leads to a much lower minimum brightness, which is still visible.

Tested on a Framework AMD 13 BIOS 3.05 with the matte panel.

Link: https://community.frame.work/t/25711/9
Link: https://community.frame.work/t/47036
Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 

Reviewed-by: Mario Limonciello 

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

diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c 
b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index 6b8bbed77c7f..f2aefff618dd 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -17,6 +17,14 @@ struct drm_panel_min_backlight_quirk {
  };
  
  static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks[] = {

+   /* 13 inch matte panel */
+   {
+   .dmi_match.field = DMI_BOARD_VENDOR,
+   .dmi_match.value = "Framework",
+   .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 
0x0bca),
+   .ident.name = "NE135FBM-N41",
+   .min_brightness = 0,
+   },
  };
  
  static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,






Re: [PATCH v5 2/4] drm/amd/display: Add support for minimum backlight quirk

2024-08-21 Thread Mario Limonciello

On 8/18/2024 01:56, Thomas Weißschuh wrote:

Not all platforms provide correct PWM backlight capabilities through ATIF.


I don't think correct is an accurate term here.  How about 'optimial'?


Use the generic drm panel minimum backlight quirk infrastructure to
override the capabilities where necessary.

Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 


The code looks fine to me but please wait for an ack from someone on the 
AMD display team.


Also, I would like to see comments about the testing with panel power 
savings enabled to avoid a conflict.


Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/amd/amdgpu/Kconfig|  1 +
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++
  2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 0051fb1b437f..655c10aef2e3 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -23,6 +23,7 @@ config DRM_AMDGPU
select DRM_BUDDY
select DRM_SUBALLOC_HELPER
select DRM_EXEC
+   select DRM_PANEL_BACKLIGHT_QUIRKS
# 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
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 983a977632ff..056960ea335c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -93,6 +93,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -,6 +3334,8 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
struct drm_connector *conn_base;
struct amdgpu_device *adev;
struct drm_luminance_range_info *luminance_range;
+   const struct drm_edid *drm_edid;
+   int min_input_signal_override;
  
  	if (aconnector->bl_idx == -1 ||

aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
@@ -3367,6 +3370,13 @@ static void update_connector_ext_caps(struct 
amdgpu_dm_connector *aconnector)
caps->aux_min_input_signal = 0;
caps->aux_max_input_signal = 512;
}
+
+   drm_edid = drm_edid_alloc(aconnector->edid,
+ EDID_LENGTH * (aconnector->edid->extensions + 
1));
+   min_input_signal_override = 
drm_get_panel_min_brightness_quirk(drm_edid);
+   drm_edid_free(drm_edid);
+   if (min_input_signal_override >= 0)
+   caps->min_input_signal = min_input_signal_override;
  }
  
  void amdgpu_dm_update_connector_after_detect(






Re: [PATCH v5 1/4] drm: Add panel backlight quirks

2024-08-21 Thread Mario Limonciello

On 8/18/2024 01:56, Thomas Weißschuh wrote:

Panels using a PWM-controlled backlight source do not have a standard
way to communicate their valid PWM ranges.
On x86 the ranges are read from ACPI through driver-specific tables.
The built-in ranges are not necessarily correct, or may grow stale if an
older device can be retrofitted with newer panels.

Add a quirk infrastructure with which the minimum valid backlight value
can be maintained as part of the kernel.

Signed-off-by: Thomas Weißschuh 
Tested-by: Dustin L. Howett 


One small nit below but otherwise this patch is fine to me.

Reviewed-by: Mario Limonciello 


---
  Documentation/gpu/drm-kms-helpers.rst|  3 ++
  drivers/gpu/drm/Kconfig  |  4 ++
  drivers/gpu/drm/Makefile |  1 +
  drivers/gpu/drm/drm_panel_backlight_quirks.c | 70 
  include/drm/drm_utils.h  |  4 ++
  5 files changed, 82 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index 8435e8621cc0..a26989500129 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -230,6 +230,9 @@ Panel Helper Reference
  .. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c
 :export:
  
+.. kernel-doc:: drivers/gpu/drm/drm_panel_backlight_quirks.c

+   :export:
+
  Panel Self Refresh Helper Reference
  ===
  
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig

index 6b2c6b91f962..9ebb8cdb535e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -454,6 +454,10 @@ config DRM_HYPERV
  config DRM_EXPORT_FOR_TESTS
bool
  
+# Separate option as not all DRM drivers use it

+config DRM_PANEL_BACKLIGHT_QUIRKS
+   tristate
+
  config DRM_LIB_RANDOM
bool
default n
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 68cc9258ffc4..adf85999aee2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -92,6 +92,7 @@ drm-$(CONFIG_DRM_PANIC) += drm_panic.o
  obj-$(CONFIG_DRM) += drm.o
  
  obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o

+obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
  
  #

  # Memory-management helpers
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c 
b/drivers/gpu/drm/drm_panel_backlight_quirks.c
new file mode 100644
index ..6b8bbed77c7f
--- /dev/null
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct drm_panel_min_backlight_quirk {
+   struct {
+   enum dmi_field field;
+   const char * const value;
+   } dmi_match;
+   struct drm_edid_ident ident;
+   u8 min_brightness;
+};
+
+static const struct drm_panel_min_backlight_quirk 
drm_panel_min_backlight_quirks[] = {
+};
+
+static bool drm_panel_min_backlight_quirk_matches(const struct 
drm_panel_min_backlight_quirk *quirk,
+ const struct drm_edid *edid)
+{
+   if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
+   return false;
+
+   if (!drm_edid_match(edid, &quirk->ident))
+   return false;
+
+   return true;
+}
+
+/**
+ * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level 
for a panel.
+ * @edid: EDID of the panel to check
+ *
+ * This function checks for platform specific (e.g. DMI based) quirks
+ * providing info on the minimum backlight brightness for systems where this
+ * cannot be probed correctly from the hard-/firm-ware.
+ *
+ * Returns:
+ * A negative error value or
+ * an override value in the range [0, 255] representing 0-100% to be scaled to
+ * the drivers target range.
+ */
+int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
+{
+   const struct drm_panel_min_backlight_quirk *quirk;
+   size_t i;


Nit: this doesn't really seem like it needs to be size_t.  Shouldn't it 
just be an unsigned int?



+
+   if (!IS_ENABLED(CONFIG_DMI))
+   return -ENODATA;
+
+   if (!edid)
+   return -EINVAL;
+
+   for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
+   quirk = &drm_panel_min_backlight_quirks[i];
+
+   if (drm_panel_min_backlight_quirk_matches(quirk, edid))
+   return quirk->min_brightness;
+   }
+
+   return -ENODATA;
+}
+EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
+
+MODULE_DESCRIPTION("Quirks for panel backlight overrides");
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
index 70775748d243..15fa9b6865f4 100644
--- a/include/drm/drm_utils.h
+++ b/include/drm/drm_utils.h
@@ -12,8 +12,12 @@
  
  #include 
  
+struct drm_edi

Re: [PATCH v5 0/4] drm: Minimum backlight overrides and implementation for amdgpu

2024-08-21 Thread Mario Limonciello

On 8/18/2024 01:56, Thomas Weißschuh wrote:

The value of "min_input_signal" returned from ATIF on a Framework AMD 13
is "12". This leads to a fairly bright minimum display backlight.

Introduce a quirk to override "min_input_signal" to "0" which leads to a
much lower minimum brightness, which is still readable even in daylight.



Apologies for my delayed response, I've been OOO a while.

An earlier version of this series I had asked if this could be tested 
specifically with panel_power_savings enabled to ensure we're not 
causing a regression with such a low minimum and panel power savings 
turned up to the maximum.  If such a dependency does exist, I believe 
panel power savings will need to get an extra check introduced to 
disable it when the brightness falls below the previous threshold that 
was programmed by the firmware.


Did that ever get checked?


Tested on a Framework AMD 13 BIOS 3.05 and Framework AMD 16.



As far as I can tell this series doesn't apply any quirks to Framework 
16.  So by testing, do you mean that you tested that it didn't cause 
regressions (which it shouldn't; the panels don't match!).



One solution would be a fixed firmware version, which was announced but
has no timeline. >
---
Changes in v5:
- Forward-declare struct drm_edid
- Reorder patches, quirk entries are last
- Add patch from Dustin for additional quirk entries
- Link to v4: 
https://lore.kernel.org/r/20240812-amdgpu-min-backlight-quirk-v4-0-56a63ff89...@weissschuh.net

Changes in v4:
- Switch back to v2 implementation
- Add MODULE_DESCRIPTION()
- Simplify quirk infrastructure to only handle min backlight quirks.
   It can be extended if necessary.
- Expand documentation.
- Link to v3: 
https://lore.kernel.org/r/20240731-amdgpu-min-backlight-quirk-v3-0-46d40bb21...@weissschuh.net

Changes in v3:
- Switch to cmdline override parameter
- Link to v2: 
https://lore.kernel.org/r/20240623-amdgpu-min-backlight-quirk-v2-0-cecf7f49d...@weissschuh.net

Changes in v2:
- Introduce proper drm backlight quirk infrastructure
- Quirk by EDID and DMI instead of only DMI
- Limit quirk to only single Framework 13 matte panel
- Link to v1: 
https://lore.kernel.org/r/20240610-amdgpu-min-backlight-quirk-v1-1-8459895a5...@weissschuh.net

---
Dustin L. Howett (1):
   drm: panel-backlight-quirks: Add Framework 13 glossy and 2.8k panels

Thomas Weißschuh (3):
   drm: Add panel backlight quirks
   drm/amd/display: Add support for minimum backlight quirk
   drm: panel-backlight-quirks: Add Framework 13 matte panel

  Documentation/gpu/drm-kms-helpers.rst |  3 +
  drivers/gpu/drm/Kconfig   |  4 +
  drivers/gpu/drm/Makefile  |  1 +
  drivers/gpu/drm/amd/amdgpu/Kconfig|  1 +
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +++
  drivers/gpu/drm/drm_panel_backlight_quirks.c  | 94 +++
  include/drm/drm_utils.h   |  4 +
  7 files changed, 117 insertions(+)
---
base-commit: c3f2d783a459980eafd24c5af94ccd56a615961f
change-id: 20240610-amdgpu-min-backlight-quirk-8402fd8e736a

Best regards,




Re: commit 9d8c094ddab0 breaks Xorg/xfce4

2024-08-20 Thread Mario Limonciello

On 8/1/2024 11:52, Bert Karwatzki wrote:

Since linux-next-20240801 starting Xorg/xfce4 fails on my MSI Alpha15 Laptop.
I bisected this to the following commit and reverting this in 
linux-next-20240801
fixes the issue for me. Gnome (with Xwayland) works as usual.

9d8c094ddab05db88d183ba82e23be807848cad8 is the first bad commit
commit 9d8c094ddab05db88d183ba82e23be807848cad8
Author: Mario Limonciello 
Date:   Wed Jul 3 00:17:22 2024 -0500

 drm/amd: Add power_saving_policy drm property to eDP connectors

 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 ABM and PSR
 can be enabled again.

 Signed-off-by: Mario Limonciello 
 Reviewed-by: Leo Li 
 Signed-off-by: Hamza Mahfooz 
 Link: 
https://patchwork.freedesktop.org/patch/msgid/20240703051722.328-3-mario.limoncie...@amd.com

  drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 52 
+++-
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 ++
  3 files changed, 53 insertions(+), 5 deletions(-)

Bert Karwatzki


Thanks for reporting this.  It's an odd issue!
I could reproduce it using SDDM (which uses X by "default").

Just to close the loop on it, it's been reverted for other reasons:
https://gitlab.freedesktop.org/drm/misc/kernel/-/commit/717b432b6d55e1dcefcb5e2ec315bf66b6ab8c54

When something comes back in a different form I'll double check X again too.


Re: [PATCH] drm/amd/display: change the panel power savings level without a modeset

2024-08-19 Thread Mario Limonciello

On 8/9/24 15:42, Hamza Mahfooz wrote:

We don't actually need to request that the compositor does a full
modeset to modify the panel power savings level, we can instead
just make a request to DMUB, to set the new level dynamically.

Cc: Harry Wentland 
Cc: Leo Li 
Cc: Mario Limonciello 
Cc: Sebastian Wick 
Signed-off-by: Hamza Mahfooz 
---


Thanks, this will solve the side effects that users of GNOME shell were 
seeing when the attribute was modified.


I tested it on an applicable laptop running 6.11-rc4 and it works 
correctly.  I have one nit below, but feel free to ignore it if you 
don't agree.


Here's some tags:

Tested-by: Mario Limonciello 
Reviewed-by: Mario Limonciello 
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3578


  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 +++-
  drivers/gpu/drm/amd/display/dc/core/dc.c  | 39 +++
  drivers/gpu/drm/amd/display/dc/dc.h   |  2 +
  3 files changed, 41 insertions(+), 17 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 dd8353283bda..00a8a5959aa9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6819,9 +6819,14 @@ static ssize_t panel_power_savings_store(struct device 
*device,
 const char *buf, size_t count)
  {
struct drm_connector *connector = dev_get_drvdata(device);
+   struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
struct drm_device *dev = connector->dev;
+   struct amdgpu_device *adev = drm_to_adev(dev);
+   struct dc *dc = adev->dm.dc;
+   struct pipe_ctx *pipe_ctx;
long val;
int ret;
+   int i;
  
  	ret = kstrtol(buf, 0, &val);
  
@@ -6836,7 +6841,17 @@ static ssize_t panel_power_savings_store(struct device *device,

ABM_LEVEL_IMMEDIATE_DISABLE;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
  
-	drm_kms_helper_hotplug_event(dev);

+   mutex_lock(&adev->dm.dc_lock);
+   for (i = 0; i < dc->res_pool->pipe_count; i++) {
+   pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+
+   if (pipe_ctx->stream &&
+   pipe_ctx->stream->link == aconn->dc_link) {
+   dc_set_abm_level(dc, pipe_ctx, val);
+   break;
+   }
+   }
+   mutex_unlock(&adev->dm.dc_lock);
  
  	return count;

  }
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 3ba2acfdae2a..60081cd978b7 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -3319,6 +3319,23 @@ static bool update_planes_and_stream_state(struct dc *dc,
  
  }
  
+void dc_set_abm_level(struct dc *dc, struct pipe_ctx *pipe_ctx, int level)

+{
+   struct timing_generator *tg = pipe_ctx->stream_res.tg;
+   struct abm *abm = pipe_ctx->stream_res.abm;
+
+   if (!abm)
+   return;


AFAICT this is a programmer error if this was to actually happen.
I'd think a WARN_ON() makes sense here.


+
+   if (tg->funcs->is_blanked && !tg->funcs->is_blanked(tg))
+   tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
+
+   if (level == ABM_LEVEL_IMMEDIATE_DISABLE)
+   dc->hwss.set_abm_immediate_disable(pipe_ctx);
+   else
+   abm->funcs->set_abm_level(abm, level);
+}
+
  static void commit_planes_do_stream_update(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -3447,22 +3464,12 @@ static void commit_planes_do_stream_update(struct dc 
*dc,
dc->link_srv->set_dpms_on(dc->current_state, 
pipe_ctx);
}
  
-			if (stream_update->abm_level && pipe_ctx->stream_res.abm) {

-   bool should_program_abm = true;
-
-   // if otg funcs defined check if blanked before 
programming
-   if (pipe_ctx->stream_res.tg->funcs->is_blanked)
-   if 
(pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg))
-   should_program_abm = false;
-
-   if (should_program_abm) {
-   if (*stream_update->abm_level == 
ABM_LEVEL_IMMEDIATE_DISABLE) {
-   
dc->hwss.set_abm_immediate_disable(pipe_ctx);
-   } else {
-   
pipe_ctx->stream_res.abm->funcs->set_abm_level(
-  

[PATCH] drm/amd: Don't wake dGPUs while reading sensors

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

If the dGPU is off, then reading the sysfs files with a sensor monitoring
application will wake it. Change the behavior to return an error when the
dGPU is in D3cold.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/pm/amdgpu_pm.c | 90 +++---
 1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c 
b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index c11952a4389bc..d6e38466fbb82 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -142,7 +142,7 @@ static ssize_t amdgpu_get_power_dpm_state(struct device 
*dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -173,7 +173,7 @@ static ssize_t amdgpu_set_power_dpm_state(struct device 
*dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
if (strncmp("battery", buf, strlen("battery")) == 0)
@@ -270,7 +270,7 @@ static ssize_t 
amdgpu_get_power_dpm_force_performance_level(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -309,7 +309,7 @@ static ssize_t 
amdgpu_set_power_dpm_force_performance_level(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
if (strncmp("low", buf, strlen("low")) == 0) {
@@ -371,7 +371,7 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -409,7 +409,7 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -448,7 +448,7 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
if (adev->pm.pp_force_state_enabled)
@@ -471,7 +471,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
adev->pm.pp_force_state_enabled = false;
@@ -541,7 +541,7 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -577,7 +577,7 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -760,7 +760,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device 
*dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
if (count > 127 || count == 0)
@@ -862,7 +862,7 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device 
*dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if (adev->in_suspend && !adev->in_runpm)
+   if (adev->in_suspend || adev->in_runpm)
return -EPERM;
 
ret = pm_runtime_get_sync(ddev->dev);
@@ -922,7 +922,7 @@ static ssize_t amdgpu_set_pp_features(struct device *dev,
 
if (amdgpu_in_reset(adev))
return -EPERM;
-   if 

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

2024-08-06 Thread Mario Limonciello

On 8/6/24 13:42, Sebastian Wick wrote:

From: Sebastian Wick 

This reverts commit 63d0b87213a0ba241b3fcfba3fe7b0aed0cd1cc5.

The panel_power_savings sysfs entry can be used to change the displayed
colorimetry which breaks color managed setups.

The "do not break userspace" rule which was violated here is enough
reason to revert this commit.

The bigger problem is that this feature is part of the display chain
which is supposed to be controlled by KMS. This sysfs entry bypasses the
DRM master process and splits control to two independent processes which
do not know about each other. This is what caused the broken user space.
It also causes modesets which can be extremely confusing for the DRM
master process, causing unexpected timings.

We should in general not allow anything other than KMS to control the
display path. If we make an exception to this rule, this must be first
discussed on dri-devel with all the stakeholders approving the
exception.

This has not happened which is the second reason to revert this commit.

Signed-off-by: Sebastian Wick 


For anyone who hasn't seen it, there has been a bunch of discussions 
that have transpired on this topic and what to do about it on [1] as 
well as some other linked places on that bug.


Also FWIW there was a discussion on the merits of the sysfs file on 
dri-devel during the initial patch submission [2].


If this revert ends up going through, please also revert 
0887054d14ae23061e28e28747cdea7e40be9224 in the same series so the 
feature can "at least" be accessed by the compositor and changed at 
runtime like the sysfs file had allowed.


[1] https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/issues/159
[2] 
https://lore.kernel.org/dri-devel/20240202152837.7388-1-hamza.mahf...@amd.com/



---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 80 ---
  1 file changed, 80 deletions(-)

diff --git ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
../drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 4d4c75173fc3..16c9051d9ccf 100644
--- ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ ../drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6772,82 +6772,10 @@ 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(&dev->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(&dev->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, &val);
-
-   if (ret)
-   return ret;
-
-   if (val < 0 || val > 4)
-   return -EINVAL;
-
-   drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-   to_dm_connector_state(connector->state)->abm_level = val ?:
-   ABM_LEVEL_IMMEDIATE_DISABLE;
-   drm_modeset_unlock(&dev->mode_config.connection_mutex);
-
-   drm_kms_helper_hotplug_event(dev);
-
-   return count;
-}
-
-static DEVICE_ATTR_RW(panel_power_savings);
-
-static struct attribute *amdgpu_attrs[] = {
-   &dev_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);
  
-	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&

-   amdgpu_dm_abm_level < 0)
-   sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group);
-
drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
  }
  
@@ -6952,14 +6880,6 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)

  

Re: amdgpu [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data

2024-07-11 Thread Mario Limonciello

On 7/10/2024 13:03, Thomas Glanzmann wrote:

Hello,

* Thomas Glanzmann  [2024-07-10 07:19]:

[   11.902016] amdgpu :0b:00.0: [drm] *ERROR* 
dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data


I resolved the issue by updating my firmware:

git clone 
https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
cd linux-firmware.git
sudo make install
sudo reboot

Cheers,
 Thomas



You're not the first person to complain about problems root caused with 
extremely outdated firmware in Debian.


Can I ask you to please file a request with Debian to update all of 
amdgpu firmware to a new snapshot?


Thanks,


[PATCH] drm/amd: Fail the suspend sequence if the GPU doesn't use S3 or S0i3

2024-07-10 Thread Mario Limonciello
As part of the S3 suspend sequence dGPUs will evict VRAM.  If there is
high memory pressure at this time, there is a chance this fails.

systemd has a policy to try to "fall back" from S3 to s2idle and see
if that works.  When under high memory pressure this also fails, and
harder.  Really we don't want this flow to be possible.

Fail the sequence if the dGPU won't be suspended using either method.

Link: https://gitlab.freedesktop.org/drm/amd/-/issues/3476
Link: https://github.com/systemd/systemd/issues/25151
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 802debd8d9f0..6a5a3e132319 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2562,7 +2562,7 @@ static int amdgpu_pmops_suspend(struct device *dev)
else if (amdgpu_acpi_is_s3_active(adev))
adev->in_s3 = true;
if (!adev->in_s0ix && !adev->in_s3)
-   return 0;
+   return -EINVAL;
return amdgpu_device_suspend(drm_dev, true);
 }
 
-- 
2.45.2



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

2024-07-02 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 ABM and PSR
can be enabled again.

Signed-off-by: Mario Limonciello 
---
v3->v4:
 * Fix enabling again after disable (Xaver)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 50 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 3 files changed, 51 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 f866a02f4f48..34da987350f5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6417,6 +6417,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 || 
!dm_old_state->abm_level) ?
+   ABM_LEVEL_IMMEDIATE_DISABLE :
+   dm_old_state->abm_level;
+   dm_new_state->psr_forbidden = val & 
DRM_MODE_REQUIRE_LOW_LATENCY;
+   ret = 0;
}
 
return ret;
@@ -6459,6 +6466,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;
@@ -6485,9 +6499,12 @@ static ssize_t panel_power_savings_show(struct device 
*device,
u8 val;
 
drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
 
return sysfs_emit(buf, "%u\n", val);
@@ -6511,10 +6528,16 @@ static ssize_t panel_power_savings_store(struct device 
*device,
return -EINVAL;
 
drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
 
+   if (ret)
+   return ret;
+
drm_kms_helper_hotplug_event(dev);
 
return count;
@@ -7685,6 +7708,13 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_requested_bpc =

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

2024-07-02 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.

v3->v4:
 * Fixup for Xaver's reported issue
v2->v3:
 * Updates from Leo's comments (see individual patches)

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 | 50 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 drivers/gpu/drm/drm_connector.c   | 48 ++
 include/drm/drm_connector.h   |  2 +
 include/drm/drm_mode_config.h |  5 ++
 include/uapi/drm/drm_mode.h   |  7 +++
 7 files changed, 113 insertions(+), 5 deletions(-)

-- 
2.43.0



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

2024-07-02 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.

Acked-by: Leo Li 
Signed-off-by: Mario Limonciello 
---
v3->v4:
 * Handle -ENOMEM case too
---
 drivers/gpu/drm/drm_connector.c | 48 +
 include/drm/drm_connector.h |  2 ++
 include/drm/drm_mode_config.h   |  5 
 include/uapi/drm/drm_mode.h |  7 +
 4 files changed, 62 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4d2df7f64dc5..f8b3e4dfeb0d 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,39 @@ 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);
+   if (!power_saving)
+   return -ENOMEM;
+
+   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 

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

2024-07-02 Thread Mario Limonciello

On 7/1/2024 17:34, Xaver Hugl wrote:

Am Mo., 1. Juli 2024 um 21:02 Uhr schrieb Mario Limonciello
:

Hmm I'm a bit surprised the IGT tests I did didn't catch this.

Are you working on a system with two GPUs by chance (like a Framework
16)?  If so; can you try the "other GPU"?


No, I tested on a Framework 13.


As it seems your PR to span 3 projects and I've never built KDE before
can you spit out some artifacts somewhere that I can have a play with to
reproduce your result and find the kernel issue?  Arch pkgs would be
preferable for me, but some RPMs or DEBs are fine too.


Here you go: https://nx44777.your-storageshare.de/s/2j4Jy5anDwwzCtF
and https://nx44777.your-storageshare.de/s/2rxJ4Tp2L8gdc8Y
You can set the drm property to "Require color accuracy" with
"kscreen-doctor output.1.allowColorPowerSaving.disallow" and to zero
again with "kscreen-doctor output.1.allowColorPowerSaving.allow"


Thanks, I snagged the artifacts.  Of course when I tried to reproduce I 
hit a new issue where my series is causing problems with DSC on my panel.


X crashes and consequently SDDM doesn't come up so I don't even get to 
the point I can toggle the knob.


Mostly posting trace below in case root cause jumps out at anyone what 
actually went wrong.  It reproduces with amdgpu.abmlevel=0 on both 6.9.7 
and 6.10-rc6, but drop my patches and it's gone.


[drm] DSC precompute is not needed.
[ cut here ]
WARNING: CPU: 7 PID: 321 at 
drivers/gpu/drm/amd/amdgpu/../display/dc/dsc/dcn20/dcn20_dsc.c:272 
dsc2_disable+0xec/0x170 [amdgpu]
Modules linked in: amdgpu(+) amdxcp i2c_algo_bit drm_ttm_helper ttm 
drm_exec gpu_sched drm_suballoc_helper drm_buddy drm_display_helper 
drm_kms_helper drm drm_panel_orientation_quirks nvme serio_raw nvme_core 
video
CPU: 7 PID: 321 Comm: (udev-worker) Not tainted 
6.9.7-2-gde664ea69218 #241
Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP05, 
BIOS 03.05 03/29/2024

RIP: 0010:dsc2_disable+0xec/0x170 [amdgpu]
Code: 4c 24 0c 44 8b 43 10 48 8b 40 10 48 8b 30 48 85 f6 74 04 48 8b 76 
08 48 c7 c1 98 71 49 c1 ba 08 00 00 00 31 ff e8 84 53 7d ff <0f> 0b 48 
8b 53 20 48 8b 43 28 45 31 c9 48 8b 7b 08 0f b6 8a b4 00

RSP: 0018:b96f80a46e80 EFLAGS: 00010246
RAX:  RBX: 95a144c19000 RCX: c1497198
RDX: 0008 RSI: 95a141d8b0c8 RDI: 
RBP: 95a1552002d8 R08:  R09: 
R10: 014b R11:  R12: 95a14f41d680
R13: 0001 R14: 95a151338000 R15: 95a151338000
FS:  7f3e17557880() GS:95a4ae78() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 55ab019b1288 CR3: 00010bb2c000 CR4: 00f50ef0
PKRU: 5554
Call Trace:
 
 ? dsc2_disable+0xec/0x170 [amdgpu]
 ? __warn.cold+0x8e/0xe8
 ? dsc2_disable+0xec/0x170 [amdgpu]
 ? report_bug+0xef/0x1d0
 ? handle_bug+0x3c/0x80
 ? exc_invalid_op+0x13/0x60
 ? asm_exc_invalid_op+0x16/0x20
 ? dsc2_disable+0xec/0x170 [amdgpu]
 link_set_dsc_on_stream+0x3f2/0x470 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? dm_helpers_dp_write_dsc_enable+0x286/0x720 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? disable_link+0x1e1/0x210 [amdgpu]
 link_set_dsc_enable+0x7f/0x90 [amdgpu]
 link_set_dpms_off+0x1ad/0x990 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? dmub_srv_get_fw_boot_status+0x43/0x60 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? dm_read_reg_func+0x57/0xc0 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 dc_commit_state_no_check+0x878/0x1990 [amdgpu]
 dc_commit_streams+0x29d/0x580 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 amdgpu_dm_atomic_commit_tail+0x686/0x44c0 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? dcn314_validate_bandwidth+0x181/0x3f0 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? dma_resv_get_fences+0xb7/0x310
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? amdgpu_dm_plane_helper_prepare_fb+0x1a0/0x2b0 [amdgpu]
 commit_tail+0xbf/0x170 [drm_kms_helper]
 drm_atomic_helper_commit+0x116/0x140 [drm_kms_helper]
 drm_atomic_commit+0x99/0xd0 [drm]
 ? __pfx___drm_printfn_info+0x10/0x10 [drm]
 drm_client_modeset_commit_atomic+0x1e2/0x220 [drm]
 drm_client_modeset_commit_locked+0x56/0x160 [drm]
 ? srso_alias_return_thunk+0x5/0xfbef5
 drm_client_modeset_commit+0x21/0x40 [drm]
 __drm_fb_helper_restore_fbdev_mode_unlocked+0xae/0xf0 [drm_kms_helper]
 drm_fb_helper_set_par+0x2c/0x40 [drm_kms_helper]
 fbcon_init+0x2d6/0x670
 visual_init+0xea/0x180
 do_bind_con_driver.isra.0+0x241/0x390
 ? fbcon_startup+0x1fe/0x2e0
 do_take_over_console+0x177/0x1f0
 ? kmalloc_trace+0x246/0x2f0
 do_fbcon_takeover+0x72/0x130
 fbcon_fb_registered+0x33/0x80
 register_framebuffer+0x192/0x2b0
 __drm_fb_helper_initial_c

Re: [PATCH v2 0/3] drm: backlight quirk infrastructure and lower minimum for Framework AMD 13

2024-07-02 Thread Mario Limonciello

On 6/23/2024 3:51, Thomas Weißschuh wrote:

The value of "min_input_signal" returned from ATIF on a Framework AMD 13
is "12". This leads to a fairly bright minimum display backlight.

Add a generic quirk infrastructure for backlight configuration to
override the settings provided by the firmware.
Also add amdgpu as a user of that infrastructure and a quirk for the
Framework 13 matte panel.
Most likely this will also work for the glossy panel, but I can't test
that.

One solution would be a fixed firmware version, but given that the
problem exists since the release of the hardware, it has been known for
a month that the hardware can go lower and there was no acknowledgment
from Framework in any way, I'd like to explore this alternative
way forward.

Notes:

* Should the quirk infrastructure be part of drm_edid.c?
* The current allocation of struct drm_edid in amdgpu is bad.
   But it is done the same way in other parts of amdgpu.
   I do have patches migrating amdgpu to proper usage of struct drm_edid [0]

Mario:

I intentionally left out the consideration of the firmware version.
The quirk will stay correct even if the firmware starts reporting
correct values.
If there are strong opinions it would be easy to add, though.

Based on amdgpu/drm-next.

[0] 
https://lore.kernel.org/lkml/20240616-amdgpu-edid-bios-v1-1-2874f212b...@weissschuh.net/



Thomas,

Are you doing any testing of this lower backlight value specifically 
with panel power savings enabled?  If not can you please check that?


Specifically write the maximum value of "4" to the sysfs file:

/sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings

Thanks,


---
Changes in v2:
- Introduce proper drm backlight quirk infrastructure
- Quirk by EDID and DMI instead of only DMI
- Limit quirk to only single Framework 13 matte panel
- Link to v1: 
https://lore.kernel.org/r/20240610-amdgpu-min-backlight-quirk-v1-1-8459895a5...@weissschuh.net

---
Thomas Weißschuh (3):
   drm: Add panel backlight quirks
   drm: panel-backlight-quirks: Add Framework 13 matte panel
   drm/amd/display: Add support backlight quirks

  Documentation/gpu/drm-kms-helpers.rst |  3 +
  drivers/gpu/drm/Kconfig   |  4 ++
  drivers/gpu/drm/Makefile  |  1 +
  drivers/gpu/drm/amd/amdgpu/Kconfig|  1 +
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 28 +
  drivers/gpu/drm/drm_panel_backlight_quirks.c  | 76 +++
  include/drm/drm_utils.h   | 11 
  7 files changed, 124 insertions(+)
---
base-commit: 1ecef5589320fd56af599b624d59c355d162ac7b
change-id: 20240610-amdgpu-min-backlight-quirk-8402fd8e736a

Best regards,




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

2024-07-01 Thread Mario Limonciello

On 7/1/2024 13:47, Xaver Hugl wrote:

Am Do., 20. Juni 2024 um 22:22 Uhr schrieb Xaver Hugl :

Merging can only happen once a real world userspace application has
implemented support for it. I'll try to do that sometime next week in
KWin


Here's the promised implementation:
https://invent.kde.org/plasma/kwin/-/merge_requests/6028


Thanks!



In testing with the patches on top of kernel 6.9.6, setting the
property to `Require color accuracy` makes the sysfs file correctly
report "Device or resource busy" when trying to change the power
saving level, but setting the property to zero doesn't really work.
Once KWin sets the property to zero, changing the power saving level
"works" but the screen blanks for a moment (might just be a single
frame) and reading from the file returns zero again, with the visuals
and backlight level unchanged as well.


Hmm I'm a bit surprised the IGT tests I did didn't catch this.

Are you working on a system with two GPUs by chance (like a Framework 
16)?  If so; can you try the "other GPU"?


As it seems your PR to span 3 projects and I've never built KDE before 
can you spit out some artifacts somewhere that I can have a play with to 
reproduce your result and find the kernel issue?  Arch pkgs would be 
preferable for me, but some RPMs or DEBs are fine too.




Re: [PATCH] drm/amd/display: use vmalloc for struct dc_state

2024-06-26 Thread Mario Limonciello

On 6/26/2024 16:45, Alex Deucher wrote:

This is a big structure so use vmalloc as malloc can
fail when there is memory pressure.


vmalloc can be a bit slower, but I think it's fine for this context and 
better to handle memory pressure more nicely.


Reviewed-by: Mario Limonciello 



Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3454
Signed-off-by: Alex Deucher 
---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)

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 5d4f831b1e55..080c1d5f7412 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
@@ -1491,9 +1491,10 @@ int pre_validate_dsc(struct drm_atomic_state *state,
 * from dm_state->context.
 */
  
-	local_dc_state = kmemdup(dm_state->context, sizeof(struct dc_state), GFP_KERNEL);

+   local_dc_state = vmalloc(sizeof(struct dc_state));
if (!local_dc_state)
return -ENOMEM;
+   memcpy(local_dc_state, dm_state->context, sizeof(struct dc_state));
  
  	for (i = 0; i < local_dc_state->stream_count; i++) {

struct dc_stream_state *stream = dm_state->context->streams[i];
@@ -1563,7 +1564,7 @@ int pre_validate_dsc(struct drm_atomic_state *state,
dc_stream_release(local_dc_state->streams[i]);
}
  
-	kfree(local_dc_state);

+   vfree(local_dc_state);
  
  	return ret;

  }




[PATCH 2/2] Documentation/amdgpu: Add Ryzen 9000 series processors

2024-06-24 Thread Mario Limonciello
These have been announced so add them to the table.

Link: 
https://www.amd.com/en/products/processors/desktops/ryzen/9000-series/amd-ryzen-9-9950x.html
Signed-off-by: Mario Limonciello 
---
 Documentation/gpu/amdgpu/apu-asic-info-table.csv | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/gpu/amdgpu/apu-asic-info-table.csv 
b/Documentation/gpu/amdgpu/apu-asic-info-table.csv
index 61140ba32793..5dd4b8762d19 100644
--- a/Documentation/gpu/amdgpu/apu-asic-info-table.csv
+++ b/Documentation/gpu/amdgpu/apu-asic-info-table.csv
@@ -7,6 +7,7 @@ SteamDeck, VANGOGH, DCN 3.0.1, 10.3.1, VCN 3.1.0, 5.2.1, 11.5.0
 Ryzen 5000 series / Ryzen 7x30 series, GREEN SARDINE / Cezanne / Barcelo / 
Barcelo-R, DCN 2.1, 9.3, VCN 2.2, 4.1.1, 12.0.1
 Ryzen 6000 series / Ryzen 7x35 series / Ryzen 7x36 series, YELLOW CARP / 
Rembrandt / Rembrandt-R, 3.1.2, 10.3.3, VCN 3.1.1, 5.2.3, 13.0.3
 Ryzen 7000 series (AM5), Raphael, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5
+Ryzen 9000 series (AM5), Granite Ridge, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5
 Ryzen 7x45 series (FL1), Dragon Range, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5
 Ryzen 7x20 series, Mendocino, 3.1.6, 10.3.7, 3.1.1, 5.2.7, 13.0.8
 Ryzen 7x40 series, Phoenix, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 
13.0.11
-- 
2.34.1



[PATCH 1/2] Documentation/amdgpu: Add Ryzen AI 300 series processors

2024-06-24 Thread Mario Limonciello
These have been announced so add them to the table.

Link: 
https://www.amd.com/en/products/processors/laptop/ryzen/300-series/amd-ryzen-ai-9-hx-370.html
Signed-off-by: Mario Limonciello 
---
 Documentation/gpu/amdgpu/apu-asic-info-table.csv | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/gpu/amdgpu/apu-asic-info-table.csv 
b/Documentation/gpu/amdgpu/apu-asic-info-table.csv
index 18868abe2a91..61140ba32793 100644
--- a/Documentation/gpu/amdgpu/apu-asic-info-table.csv
+++ b/Documentation/gpu/amdgpu/apu-asic-info-table.csv
@@ -11,3 +11,4 @@ Ryzen 7x45 series (FL1), Dragon Range, 3.1.5, 10.3.6, 3.1.2, 
5.2.6, 13.0.5
 Ryzen 7x20 series, Mendocino, 3.1.6, 10.3.7, 3.1.1, 5.2.7, 13.0.8
 Ryzen 7x40 series, Phoenix, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 
13.0.11
 Ryzen 8x40 series, Hawk Point, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 
13.0.11
+Ryzen AI 300 series, Strix Point, 3.5.0, 11.5.0, 4.0.5, 6.1.0, 14.0.0
-- 
2.34.1



Re: [PATCH v2 1/3] drm: Add panel backlight quirks

2024-06-24 Thread Mario Limonciello

On 6/23/2024 15:55, Hans de Goede wrote:

Hi,

On 6/23/24 10:20 PM, Mario Limonciello wrote:

On 6/23/2024 03:51, Thomas Weißschuh wrote:

Panels using a PWM-controlled backlight source without an do not have a
standard way to communicate their valid PWM ranges.
On x86 the ranges are read from ACPI through driver-specific tables.
The built-in ranges are not necessarily correct, or may grow stale if an
older device can be retrofitted with newer panels.

Add a quirk infrastructure with which the valid backlight ranges can be
maintained as part of the kernel.



So I was just talking to some folks in the Linux handheld gaming community 
(added to CC) about an issue they have where they need to know the correct 
panel orientation.  Due to reuse of panels across vendors the orientation on 
one might not be appropriate on another.  The trick is then to detect the combo 
of both the panel and the DMI data.

It's the same "kind" of problem where something advertised in the firmware 
should be ignored but only on a panel + SMBIOS combination.

So I am wondering if what you're proposing here could be more generalized.  IE 
"drm_panel_quirks.c" instead?

Thoughts?


Note we already have a quirk mechanism for non upright mounted lcd-panels:

drivers/gpu/drm/drm_panel_orientation_quirks.c

note that the info here is shared with the simpledrm and
efifb drivers, so if the chose is made to extend this then
that needs to be taken into account.

Regards,

Hans


Thanks for sharing.  Totally agree this is this the better way to go for 
what I raised.


Re: [PATCH v2 1/3] drm: Add panel backlight quirks

2024-06-23 Thread Mario Limonciello

On 6/23/2024 03:51, Thomas Weißschuh wrote:

Panels using a PWM-controlled backlight source without an do not have a
standard way to communicate their valid PWM ranges.
On x86 the ranges are read from ACPI through driver-specific tables.
The built-in ranges are not necessarily correct, or may grow stale if an
older device can be retrofitted with newer panels.

Add a quirk infrastructure with which the valid backlight ranges can be
maintained as part of the kernel.



So I was just talking to some folks in the Linux handheld gaming 
community (added to CC) about an issue they have where they need to know 
the correct panel orientation.  Due to reuse of panels across vendors 
the orientation on one might not be appropriate on another.  The trick 
is then to detect the combo of both the panel and the DMI data.


It's the same "kind" of problem where something advertised in the 
firmware should be ignored but only on a panel + SMBIOS combination.


So I am wondering if what you're proposing here could be more 
generalized.  IE "drm_panel_quirks.c" instead?


Thoughts?


Signed-off-by: Thomas Weißschuh 
---
  Documentation/gpu/drm-kms-helpers.rst|  3 ++
  drivers/gpu/drm/Kconfig  |  4 ++
  drivers/gpu/drm/Makefile |  1 +
  drivers/gpu/drm/drm_panel_backlight_quirks.c | 67 
  include/drm/drm_utils.h  | 11 +
  5 files changed, 86 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index 59cfe8a7a8ba..1998a2675210 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -224,6 +224,9 @@ Panel Helper Reference
  .. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c
 :export:
  
+.. kernel-doc:: drivers/gpu/drm/drm_panel_backlight_quirks.c

+   :export:
+
  Panel Self Refresh Helper Reference
  ===
  
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig

index 959b19a04101..50ccb43315bf 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -443,6 +443,10 @@ config DRM_EXPORT_FOR_TESTS
  config DRM_PANEL_ORIENTATION_QUIRKS
tristate
  
+# Separate option as not all DRM drivers use it

+config DRM_PANEL_BACKLIGHT_QUIRKS
+   tristate
+
  config DRM_LIB_RANDOM
bool
default n
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f9ca4f8fa6c5..6669913b907e 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -92,6 +92,7 @@ drm-$(CONFIG_DRM_PANIC) += drm_panic.o
  obj-$(CONFIG_DRM) += drm.o
  
  obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o

+obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
  
  #

  # Memory-management helpers
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c 
b/drivers/gpu/drm/drm_panel_backlight_quirks.c
new file mode 100644
index ..a89b5fd1940e
--- /dev/null
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct drm_panel_backlight_entry {
+   struct {
+   enum dmi_field field;
+   const char * const value;
+   } dmi_match;
+   struct drm_edid_ident ident;
+   struct drm_panel_backlight_quirk quirk;
+};
+
+static const struct drm_panel_backlight_entry drm_panel_backlight_entries[] = {
+};
+
+static bool drm_panel_backlight_entry_matches(const struct 
drm_panel_backlight_entry *entry,
+ const struct drm_edid *edid)
+{
+   if (!dmi_match(entry->dmi_match.field, entry->dmi_match.value))
+   return false;
+
+   if (!drm_edid_match(edid, &entry->ident))
+   return false;
+
+   return true;
+}
+
+/**
+ * drm_get_panel_panel_quirk - Check for panel backlight quirks
+ * @edid: EDID of the panel to check
+ *
+ * This function checks for platform specific (e.g. DMI based) quirks
+ * providing info on backlight control for systems where this cannot be
+ * probed from the hard-/firm-ware.
+ *
+ * Returns:
+ * A struct drm_panel_backlight_quirk if a quirk is found or NULL otherwise.
+ */
+const struct drm_panel_backlight_quirk *drm_get_panel_backlight_quirk(const 
struct drm_edid *edid)
+{
+   const struct drm_panel_backlight_entry *entry;
+   size_t i;
+
+   if (!IS_ENABLED(CONFIG_DMI))
+   return NULL;
+
+   if (!edid)
+   return NULL;
+
+   for (i = 0; i < ARRAY_SIZE(drm_panel_backlight_entries); i++) {
+   entry = &drm_panel_backlight_entries[i];
+
+   if (drm_panel_backlight_entry_matches(entry, edid))
+   return &entry->quirk;
+   }
+
+   return NULL;
+}
+EXPORT_SYMBOL(drm_get_panel_backlight_quirk);
+
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_utils.h b/inclu

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

2024-06-18 Thread Mario Limonciello

On 6/18/2024 17:36, Leo Li wrote:



On 2024-06-05 22:04, Mario Limonciello wrote:

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 

Reviewed-by: Leo Li 


Thanks!  I don't have permissions, so can you (or someone else) please 
apply to drm-misc-next for me?


After it's merged I'll rebase and work on the feedback for the new IGT 
tests.




Thanks!


---
v2->v3:
  * Use `disallow_edp_enter_psr` instead
  * Drop case in dm_update_crtc_state()
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 ++
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 50 +--
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
  3 files changed, 51 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 f1d67c6f4b98..5fd7210b2479 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6436,6 +6436,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;
@@ -6478,6 +6485,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;
@@ -6504,9 +6518,12 @@ static ssize_t panel_power_savings_show(struct 
device *device,

  u8 val;
  drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
  return sysfs_emit(buf, "%u\n", val);
@@ -6530,10 +6547,16 @@ static ssize_t 
panel_power_savings_store(struct device *device,

  return -EINVAL;
  drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
+    if (ret)
+    return ret;
+
  drm_kms_helper_hotplug_event(dev);
  return count;
@@ -7704,6 +7727,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;

+ 

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

2024-06-18 Thread Mario Limonciello

On 6/18/2024 15:20, Leo Li wrote:



On 2024-05-22 18:08, Mario Limonciello wrote:

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(&data->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, &ref_fb);
+    igt_create_color_fb(data->fd, data->mode->hdisplay,
+    data->mode->vdisplay, DRM_FORMAT_XRGB, 0, 0.0,
+    1.0, 0.0, &ref_fb2);
+
+    igt_plane_set_fb(data->primary, &ref_fb);
+
+    igt_display_commit_atomic(&data->display, 
DRM_MODE_ATOMIC_ALLOW_MODESET, 0);

+
+    for (i = 0; i < N_FLIPS; i++) {
+    if (i % 2 == 0)
+    flip_fb = &ref_fb2;
+    else
+    flip_fb = &ref_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_fail_on* or igt_assert* should be used here, igt_require simply 
'skips' the

test if the condition evaluates to false.



Got it; thanks.

Should we be instead asserting psr_state == PSR_STATE0 here for 
disabled, since

we've set REQUIRE_LOW_LATENCY?


Yeah I think you're right.



I think as part of this test, we can also check that PSR re-enables after
clearing the power saving policy. Something like

ret = clear_power_saving_policy(data->fd, output);
... do some flipping ...
sleep(PSR_SETTLE_DELAY);
psr_state = igt_amd_read_psr_state(data->fd, output->name);
igt_assert_f(psr_state == PSR_STATE3,
  "Panel not in PSR after clearing power saving policy\n");



Agree, thanks.


Thanks,
Leo


+
+    igt_remove_fb(data->fd, &ref_fb);
+    igt_remove_fb(data->fd, &ref_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(&data, true, .75);

+    igt_describe("Test whether PSR can be forbidden");
+    igt_subtest("psr_forbidden") psr_forbidden(&data);
  igt_fixture
  {




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

2024-06-18 Thread Mario Limonciello

On 6/18/2024 15:20, Leo Li wrote:


Thanks for the tests! FYI IGT patches should also cc 
igt-...@lists.freedesktop.org


Some comments inline:

On 2024-05-22 18:08, Mario Limonciello wrote:

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(&data->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;


Is there a purpose of setting target abm to 0 (disabled) here?

I suppose it should fail given that we've set REQUIRE_COLOR_ACCURACY. 
Though I'm

not sure why we can't keep target = 3.


Yes I think this would work as well to prove a failure.  I'll change it.



Thanks,
Leo


+    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(&data);
  igt_subtest("abm_gradual")
  abm_gradual(&data);
+    igt_subtest("abm_forbidden")
+    abm_forbidden(&data);
  igt_fixture {
  igt_display_fini(&data.display);




[PATCH] drm/amd: Don't initialize ISP hardware without FW

2024-06-18 Thread Mario Limonciello
Although designs may contain an ISP IP block, the camera might be a USB
camera. Because of this the ISP firmware is considered optional from
amdgpu.  However if the firmware doesn't get loaded the hardware should
not be initialized.

Adjust the return code for early init to ensure the IP block doesn't go
through the other init and fini sequences. Also decrease the message
about firmware load failure to debug so it's not as alarming to users.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
index 215bae809153..4766e99dd98f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -142,8 +142,8 @@ static int isp_early_init(void *handle)
isp->parent = adev->dev;
 
if (isp_load_fw_by_psp(adev)) {
-   DRM_WARN("%s: isp fw load failed\n", __func__);
-   return 0;
+   DRM_DEBUG_DRIVER("%s: isp fw load failed\n", __func__);
+   return -ENOENT;
}
 
return 0;
-- 
2.34.1



Re: [PATCH 1/2] drm/amdgpu: fix UBSAN warning in kv_dpm.c

2024-06-14 Thread Mario Limonciello

On 6/14/2024 13:33, Alex Deucher wrote:

Adds bounds check for sumo_vid_mapping_entry.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3392
Signed-off-by: Alex Deucher 

Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c 
b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
index 6bb42d04b247..e8b6989a40f3 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
@@ -164,6 +164,8 @@ static void sumo_construct_vid_mapping_table(struct 
amdgpu_device *adev,
  
  	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {

if (table[i].ulSupportedSCLK != 0) {
+   if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES)
+   continue;

vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
table[i].usVoltageID;

vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =




Re: [PATCH 2/2] drm/radeon: fix UBSAN warning in kv_dpm.c

2024-06-14 Thread Mario Limonciello

On 6/14/2024 13:33, Alex Deucher wrote:

Adds bounds check for sumo_vid_mapping_entry.

Signed-off-by: Alex Deucher 

Reviewed-by: Mario Limonciello 

---
  drivers/gpu/drm/radeon/sumo_dpm.c | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c 
b/drivers/gpu/drm/radeon/sumo_dpm.c
index 21d27e6235f3..b11f7c5bbcbe 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1619,6 +1619,8 @@ void sumo_construct_vid_mapping_table(struct 
radeon_device *rdev,
  
  	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {

if (table[i].ulSupportedSCLK != 0) {
+   if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES)
+   continue;

vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
table[i].usVoltageID;

vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =




[PATCH 2/2] drm/amd/pm: powerplay: Add `__counted_by` attribute for flexible arrays

2024-06-14 Thread Mario Limonciello
This attribute is used to hint the length of flexible arrays to
compiler and sanitizers.

Signed-off-by: Mario Limonciello 
---
 .../drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h | 36 +-
 drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h  | 38 +--
 2 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h 
b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h
index 2cf2a7b12623..7711e892c31f 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h
@@ -163,8 +163,8 @@ typedef struct _ATOM_Tonga_State {
 
 typedef struct _ATOM_Tonga_State_Array {
UCHAR ucRevId;
-   UCHAR ucNumEntries; /* Number of entries. */
-   ATOM_Tonga_State entries[]; /* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_State entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_State_Array;
 
 typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
@@ -178,8 +178,8 @@ typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
 
 typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Tonga_MCLK_Dependency_Record entries[];
/* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_MCLK_Dependency_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_MCLK_Dependency_Table;
 
 typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
@@ -193,8 +193,8 @@ typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
 
 typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Tonga_SCLK_Dependency_Record entries[];
 /* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_SCLK_Dependency_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_SCLK_Dependency_Table;
 
 typedef struct _ATOM_Polaris_SCLK_Dependency_Record {
@@ -209,8 +209,8 @@ typedef struct _ATOM_Polaris_SCLK_Dependency_Record {
 
 typedef struct _ATOM_Polaris_SCLK_Dependency_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Polaris_SCLK_Dependency_Record entries[];  
 /* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Polaris_SCLK_Dependency_Record entries[] 
__counted_by(ucNumEntries);
 } ATOM_Polaris_SCLK_Dependency_Table;
 
 typedef struct _ATOM_Tonga_PCIE_Record {
@@ -221,8 +221,8 @@ typedef struct _ATOM_Tonga_PCIE_Record {
 
 typedef struct _ATOM_Tonga_PCIE_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Tonga_PCIE_Record entries[];   
/* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_PCIE_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_PCIE_Table;
 
 typedef struct _ATOM_Polaris10_PCIE_Record {
@@ -234,8 +234,8 @@ typedef struct _ATOM_Polaris10_PCIE_Record {
 
 typedef struct _ATOM_Polaris10_PCIE_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; /* Number 
of entries. */
-   ATOM_Polaris10_PCIE_Record entries[];  /* 
Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Polaris10_PCIE_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Polaris10_PCIE_Table;
 
 
@@ -251,8 +251,8 @@ typedef struct _ATOM_Tonga_MM_Dependency_Record {
 
 typedef struct _ATOM_Tonga_MM_Dependency_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Tonga_MM_Dependency_Record entries[]; /* 
Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_MM_Dependency_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_MM_Dependency_Table;
 
 typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
@@ -264,8 +264,8 @@ typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
 
 typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
UCHAR ucRevId;
-   UCHAR ucNumEntries; 
/* Number of entries. */
-   ATOM_Tonga_Voltage_Lookup_Record entries[]; 
/* Dynamically allocate entries. */
+   UCHAR ucNumEntries;
+   ATOM_Tonga_Voltage_Lookup_Record entries[] __counted_by(ucNumEntries);
 } ATOM_Tonga_Voltage_Lookup_Table;
 
 typedef struct _ATOM_Tonga_Fan_Table

[PATCH 1/2] drm/amdgpu/pptable: Fix __counted_by attribute

2024-06-14 Thread Mario Limonciello
The attribute is not helpful if commented out.

Cc: Tasos Sahanidis 
Fixes: c6c4dd540125 ("drm/amdgpu/pptable: Fix UBSAN array-index-out-of-bounds")
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/include/pptable.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/include/pptable.h 
b/drivers/gpu/drm/amd/include/pptable.h
index f83ace2d7ec3..984770d0eb4c 100644
--- a/drivers/gpu/drm/amd/include/pptable.h
+++ b/drivers/gpu/drm/amd/include/pptable.h
@@ -480,7 +480,7 @@ typedef struct _StateArray{
//how many states we have
UCHAR ucNumEntries;
 
-   ATOM_PPLIB_STATE_V2 states[] /* __counted_by(ucNumEntries) */;
+   ATOM_PPLIB_STATE_V2 states[] __counted_by(ucNumEntries);
 }StateArray;
 
 
-- 
2.43.0



Re: [PATCH v3] drm/fb-helper: Detect when lid is closed during initialization

2024-06-14 Thread Mario Limonciello

On 6/14/2024 09:17, Thomas Zimmermann wrote:

Hi

Am 14.06.24 um 15:47 schrieb Mario Limonciello:

On 6/14/2024 03:15, Thomas Zimmermann wrote:

Hi Mario

Am 13.06.24 um 07:17 schrieb Mario Limonciello:

If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the
lid status and if it's closed disable any eDP connectors.

Also set up a workqueue to monitor for any future lid events.


After reading through this patchset, I think fbdev emulation is not 
the right place for this code, as lid state is global.


You could put this into drm_client_modeset.c and track lid state per 
client. drm_fb_helper_lid_work() would call the client's hotplug 
callback. But preferable, lid state should be tracked per DRM device 
in struct drm_mode_config and call drm_client_dev_hotplug() on each 
lid-state event. Thoughts? Best regards Thomas


This is pretty similar to what I first did when moving from ACPI over 
to generic input switch.


It works for the initial configuration.  But I don't believe it makes 
sense for the lid switch events because not all DRM clients will 
"want" to respond to the lid switch events.  By leaving it up to the 
client for everything except fbdev emulation they can also track the 
lid switch and decide the policy.



All our current clients do fbdev emulation, possibly others would be the 
panic screen and a boot-up logo. A panic screen doesn't do actual mode 
setting, but any other client would most likely want enable and disable 
the display depending on the lid state. Having this code in the DRM 
client helpers make perfect sense. But as it's global state, it makes no 
sense to set this up per client. Hence the suggestion to manage this in 
per DRM device.


It would also make sense to try to integrate this into the probe 
helpers. When the lid state changes, the probe helpers would invoke the 
driver's regular hotplugging code.


Got it; I'll do some experimentation with this change, thanks for the 
feedback.







I also worry about what happens if the kernel does a hotplug callback 
on lid events as well at the client choosing to do it. Don't we end up 
with two modesets?  So then I would think you need a handshake of some 
sort to decide whether to do it for a given client where fbdev 
emulation would opt in and then all other clients can choose to opt in 
or not.



What do you mean by the kernel does a hotplug event and the client does 
one? There should really only be one place to handle all of this. If we 
end up with two modesets, we'd get an additional flicker when the lid 
gets opened.




I'll see if my worry is founded after I move it all over.



Best regards
Thomas





Suggested-by: Dmitry Torokhov 
Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
v2->v3:
  * Use input device instead of ACPI device
  * Detect lid open/close events
---
  drivers/gpu/drm/drm_client_modeset.c |  29 ++
  drivers/gpu/drm/drm_fb_helper.c  | 132 
+++

  include/drm/drm_device.h |   6 ++
  include/drm/drm_fb_helper.h  |   2 +
  4 files changed, 169 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c

index 31af5cf37a09..b8adfe87334b 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -257,6 +257,34 @@ static void 
drm_client_connectors_enabled(struct drm_connector **connectors,

  enabled[i] = drm_connector_enabled(connectors[i], false);
  }
+static void drm_client_match_edp_lid(struct drm_device *dev,
+ struct drm_connector **connectors,
+ unsigned int connector_count,
+ bool *enabled)
+{
+    int i;
+
+    for (i = 0; i < connector_count; i++) {
+    struct drm_connector *connector = connectors[i];
+
+    switch (connector->connector_type) {
+    case DRM_MODE_CONNECTOR_LVDS:
+    case DRM_MODE_CONNECTOR_eDP:
+    if (!enabled[i])
+    continue;
+    break;
+    default:
+    continue;
+    }
+
+    if (dev->lid_closed) {
+    drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",

+    connector->base.id, connector->name);
+    enabled[i] = false;
+    }
+    }
+}
+
  static bool drm_client_target_cloned(struct drm_device *dev,
   struct drm_connector **connectors,
   unsigned int connector_count,
@@ -844,6 +872,7 @@ int drm_client_modeset_probe(struct 
drm_client_dev *client, unsigned int width,

  memset(crtcs, 0, connector_count * sizeof(*crtcs));
  memset(offsets, 0, connector_count * sizeof(

Re: [PATCH v3] drm/fb-helper: Detect when lid is closed during initialization

2024-06-14 Thread Mario Limonciello

On 6/14/2024 03:15, Thomas Zimmermann wrote:

Hi Mario

Am 13.06.24 um 07:17 schrieb Mario Limonciello:

If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the
lid status and if it's closed disable any eDP connectors.

Also set up a workqueue to monitor for any future lid events.


After reading through this patchset, I think fbdev emulation is not the 
right place for this code, as lid state is global.


You could put this into drm_client_modeset.c and track lid state per 
client. drm_fb_helper_lid_work() would call the client's hotplug 
callback. But preferable, lid state should be tracked per DRM device in 
struct drm_mode_config and call drm_client_dev_hotplug() on each 
lid-state event. Thoughts? Best regards Thomas


This is pretty similar to what I first did when moving from ACPI over to 
generic input switch.


It works for the initial configuration.  But I don't believe it makes 
sense for the lid switch events because not all DRM clients will "want" 
to respond to the lid switch events.  By leaving it up to the client for 
everything except fbdev emulation they can also track the lid switch and 
decide the policy.


I also worry about what happens if the kernel does a hotplug callback on 
lid events as well at the client choosing to do it.  Don't we end up 
with two modesets?  So then I would think you need a handshake of some 
sort to decide whether to do it for a given client where fbdev emulation 
would opt in and then all other clients can choose to opt in or not.




Suggested-by: Dmitry Torokhov 
Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
v2->v3:
  * Use input device instead of ACPI device
  * Detect lid open/close events
---
  drivers/gpu/drm/drm_client_modeset.c |  29 ++
  drivers/gpu/drm/drm_fb_helper.c  | 132 +++
  include/drm/drm_device.h |   6 ++
  include/drm/drm_fb_helper.h  |   2 +
  4 files changed, 169 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c

index 31af5cf37a09..b8adfe87334b 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -257,6 +257,34 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,

  enabled[i] = drm_connector_enabled(connectors[i], false);
  }
+static void drm_client_match_edp_lid(struct drm_device *dev,
+ struct drm_connector **connectors,
+ unsigned int connector_count,
+ bool *enabled)
+{
+    int i;
+
+    for (i = 0; i < connector_count; i++) {
+    struct drm_connector *connector = connectors[i];
+
+    switch (connector->connector_type) {
+    case DRM_MODE_CONNECTOR_LVDS:
+    case DRM_MODE_CONNECTOR_eDP:
+    if (!enabled[i])
+    continue;
+    break;
+    default:
+    continue;
+    }
+
+    if (dev->lid_closed) {
+    drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",

+    connector->base.id, connector->name);
+    enabled[i] = false;
+    }
+    }
+}
+
  static bool drm_client_target_cloned(struct drm_device *dev,
   struct drm_connector **connectors,
   unsigned int connector_count,
@@ -844,6 +872,7 @@ int drm_client_modeset_probe(struct drm_client_dev 
*client, unsigned int width,

  memset(crtcs, 0, connector_count * sizeof(*crtcs));
  memset(offsets, 0, connector_count * sizeof(*offsets));
+    drm_client_match_edp_lid(dev, connectors, connector_count, 
enabled);
  if (!drm_client_target_cloned(dev, connectors, 
connector_count, modes,

    offsets, enabled, width, height) &&
  !drm_client_target_preferred(dev, connectors, 
connector_count, modes,
diff --git a/drivers/gpu/drm/drm_fb_helper.c 
b/drivers/gpu/drm/drm_fb_helper.c

index d612133e2cf7..41dd5887599a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,8 @@
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  #include 
+#include 
+#include 
  #include 
  #include 
  #include 
@@ -413,6 +415,128 @@ static void drm_fb_helper_damage_work(struct 
work_struct *work)

  drm_fb_helper_fb_dirty(helper);
  }
+static void drm_fb_helper_lid_event(struct input_handle *handle, 
unsigned int type,

+    unsigned int code, int value)
+{
+    if (type == EV_SW && code == SW_LID) {
+    struct drm_fb_helper *fb_helper = handle->handler->private;
+
+    if (value != fb_helper->dev->lid_closed) {
+    fb_he

[PATCH v3] drm/fb-helper: Detect when lid is closed during initialization

2024-06-12 Thread Mario Limonciello
If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the
lid status and if it's closed disable any eDP connectors.

Also set up a workqueue to monitor for any future lid events.

Suggested-by: Dmitry Torokhov 
Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
v2->v3:
 * Use input device instead of ACPI device
 * Detect lid open/close events
---
 drivers/gpu/drm/drm_client_modeset.c |  29 ++
 drivers/gpu/drm/drm_fb_helper.c  | 132 +++
 include/drm/drm_device.h |   6 ++
 include/drm/drm_fb_helper.h  |   2 +
 4 files changed, 169 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 31af5cf37a09..b8adfe87334b 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -257,6 +257,34 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,
enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
+static void drm_client_match_edp_lid(struct drm_device *dev,
+struct drm_connector **connectors,
+unsigned int connector_count,
+bool *enabled)
+{
+   int i;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   if (!enabled[i])
+   continue;
+   break;
+   default:
+   continue;
+   }
+
+   if (dev->lid_closed) {
+   drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",
+   connector->base.id, connector->name);
+   enabled[i] = false;
+   }
+   }
+}
+
 static bool drm_client_target_cloned(struct drm_device *dev,
 struct drm_connector **connectors,
 unsigned int connector_count,
@@ -844,6 +872,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, 
unsigned int width,
memset(crtcs, 0, connector_count * sizeof(*crtcs));
memset(offsets, 0, connector_count * sizeof(*offsets));
 
+   drm_client_match_edp_lid(dev, connectors, connector_count, 
enabled);
if (!drm_client_target_cloned(dev, connectors, connector_count, 
modes,
  offsets, enabled, width, height) 
&&
!drm_client_target_preferred(dev, connectors, 
connector_count, modes,
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d612133e2cf7..41dd5887599a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,8 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -413,6 +415,128 @@ static void drm_fb_helper_damage_work(struct work_struct 
*work)
drm_fb_helper_fb_dirty(helper);
 }
 
+static void drm_fb_helper_lid_event(struct input_handle *handle, unsigned int 
type,
+   unsigned int code, int value)
+{
+   if (type == EV_SW && code == SW_LID) {
+   struct drm_fb_helper *fb_helper = handle->handler->private;
+
+   if (value != fb_helper->dev->lid_closed) {
+   fb_helper->dev->lid_closed = value;
+   queue_work(fb_helper->input_wq, &fb_helper->lid_work);
+   }
+   }
+}
+
+struct drm_fb_lid {
+   struct input_handle handle;
+};
+
+static int drm_fb_helper_lid_connect(struct input_handler *handler,
+struct input_dev *dev,
+const struct input_device_id *id)
+{
+   struct drm_fb_helper *fb_helper = handler->private;
+   struct drm_fb_lid *lid;
+   char *name;
+   int error;
+
+   lid = kzalloc(sizeof(*lid), GFP_KERNEL);
+   if (!lid)
+   return -ENOMEM;
+
+   name = kasprintf(GFP_KERNEL, "drm-fb-helper-lid-%s", 
dev_name(&dev->dev));
+   if (!name) {
+   error = -ENOMEM;
+   goto err_free_lid;
+   }
+
+   lid->handle.dev = dev;
+   lid->handle.handler = handler;
+   lid->handle.name = name;
+   lid->handle.private = lid;
+
+   error = input_register_handle(&lid->handle

Re: [PATCH] drm/amd: force min_input_signal to 0 on Framework AMD 13/16

2024-06-10 Thread Mario Limonciello

On 6/10/2024 15:12, Thomas Weißschuh wrote:

On 2024-06-10 14:58:02+, Mario Limonciello wrote:

+Kieran

On 6/10/2024 14:26, Thomas Weißschuh wrote:

The value of "min_input_signal" returned from ATIF on a Framework AMD 13
is "12". This leads to a fairly bright minimum display backlight.

Introduce a quirk to override "min_input_signal" to "0" which leads to a
much lower minimum brightness, which is still readable even in daylight.

Tested on a Framework AMD 13 BIOS 3.05 and Framework AMD 16.

Link: https://community.frame.work/t/25711/9
Link: https://community.frame.work/t/47036
Signed-off-by: Thomas Weißschuh 
---
   drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 35 

   1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 7099ff9cf8c5..b481889f7491 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -25,6 +25,7 @@
   #include 
   #include 
   #include 
+#include 
   #include 
   #include 
   #include 
@@ -130,6 +131,35 @@ static struct amdgpu_acpi_priv {
struct amdgpu_atcs atcs;
   } amdgpu_acpi_priv;
+struct amdgpu_acpi_quirks {
+   bool ignore_min_input_signal;
+};
+
+static const struct dmi_system_id amdgpu_acpi_quirk_table[] = {
+   {
+   /* the Framework Laptop 13 (AMD Ryzen) and 16 (AMD Ryzen) */
+   .matches = {
+   DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
+   DMI_MATCH(DMI_PRODUCT_NAME, "AMD Ryzen"),
+   DMI_MATCH(DMI_PRODUCT_FAMILY, "Laptop"),
+   },


Two problems I see:

1) This really "should" be fixed in the BIOS. I added Kieran to the thread
for comments if that's viable.


Agreed!


2) IMO this is going to match too liberally across all potential Framework
models.  If they introduce a refreshed motherboard for either product then
the quirk would apply to both products when we don't know that such a
deficiency would exist.


Also agreed.
In addition to be really specific this should also match by display type
(via EDID?).

So far this was only tested with the matte panel.
(I forgot to mention that, sorry)


Yeah; I would expect this also matters for the new high res panel that 
they announced whether this value can work.





You can reference drivers/platform/x86/amd/pmc/pmc-quirks.c for what we used
for a quirk that was matching against a single product and single BIOS.


Will do for the next revision, but let's gather some feedback first.


👍




But FWIW if that issue isn't fixed in the next BIOS I think we'll end up
needing to tear out the BIOS string match and match just the platform.


I'm wondering what the longterm strategy will have to be.
Given that there are different kinds of displays, and new ones will be
released, each new display type will require an update to the firmware.

When there are no firmware updates for a device anymore, but new,
compatible displays are released, then the kernel will need the quirks
again.


Yeah I think all this points to the 'best' home for this is BIOS.

Framework can test whether the 0 value works on all the displays they 
want to support and look for negative impacts for all OSes they support.





+   .driver_data = &(struct amdgpu_acpi_quirks) {
+   .ignore_min_input_signal = true,
+   },
+   },
+   {}
+};
+
+static const struct amdgpu_acpi_quirks *amdgpu_acpi_get_quirks(void)
+{
+   const struct dmi_system_id *dmi_id;
+
+   dmi_id = dmi_first_match(amdgpu_acpi_quirk_table);
+   if (!dmi_id)
+   return NULL;
+   return dmi_id->driver_data;
+}
+
   /* Call the ATIF method
*/
   /**
@@ -1388,6 +1418,7 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device 
*adev)
*/
   void amdgpu_acpi_detect(void)
   {
+   const struct amdgpu_acpi_quirks *quirks = amdgpu_acpi_get_quirks();
struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif;
struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs;
struct pci_dev *pdev = NULL;
@@ -1429,6 +1460,10 @@ void amdgpu_acpi_detect(void)
ret);
atif->backlight_caps.caps_valid = false;
}
+   if (quirks && quirks->ignore_min_input_signal) {
+   DRM_INFO("amdgpu_acpi quirk: min_input_signal=0\n");
+   atif->backlight_caps.min_input_signal = 0;
+   }
} else {
atif->backlight_caps.caps_valid = false;
}

---
base-commit: 83a7eefedc9b56fe7bfeff13b6c7356688ffa670
change-id: 20240610-amdgpu-min-backlight-quirk-8402fd8e736a

Best regards,






Re: [PATCH] drm/amd: force min_input_signal to 0 on Framework AMD 13/16

2024-06-10 Thread Mario Limonciello

+Kieran

On 6/10/2024 14:26, Thomas Weißschuh wrote:

The value of "min_input_signal" returned from ATIF on a Framework AMD 13
is "12". This leads to a fairly bright minimum display backlight.

Introduce a quirk to override "min_input_signal" to "0" which leads to a
much lower minimum brightness, which is still readable even in daylight.

Tested on a Framework AMD 13 BIOS 3.05 and Framework AMD 16.

Link: https://community.frame.work/t/25711/9
Link: https://community.frame.work/t/47036
Signed-off-by: Thomas Weißschuh 
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 35 
  1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 7099ff9cf8c5..b481889f7491 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -25,6 +25,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -130,6 +131,35 @@ static struct amdgpu_acpi_priv {
struct amdgpu_atcs atcs;
  } amdgpu_acpi_priv;
  
+struct amdgpu_acpi_quirks {

+   bool ignore_min_input_signal;
+};
+
+static const struct dmi_system_id amdgpu_acpi_quirk_table[] = {
+   {
+   /* the Framework Laptop 13 (AMD Ryzen) and 16 (AMD Ryzen) */
+   .matches = {
+   DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
+   DMI_MATCH(DMI_PRODUCT_NAME, "AMD Ryzen"),
+   DMI_MATCH(DMI_PRODUCT_FAMILY, "Laptop"),
+   },


Two problems I see:

1) This really "should" be fixed in the BIOS. I added Kieran to the 
thread for comments if that's viable.


2) IMO this is going to match too liberally across all potential 
Framework models.  If they introduce a refreshed motherboard for either 
product then the quirk would apply to both products when we don't know 
that such a deficiency would exist.


You can reference drivers/platform/x86/amd/pmc/pmc-quirks.c for what we 
used for a quirk that was matching against a single product and single 
BIOS.


But FWIW if that issue isn't fixed in the next BIOS I think we'll end up 
needing to tear out the BIOS string match and match just the platform.




+   .driver_data = &(struct amdgpu_acpi_quirks) {
+   .ignore_min_input_signal = true,
+   },
+   },
+   {}
+};
+
+static const struct amdgpu_acpi_quirks *amdgpu_acpi_get_quirks(void)
+{
+   const struct dmi_system_id *dmi_id;
+
+   dmi_id = dmi_first_match(amdgpu_acpi_quirk_table);
+   if (!dmi_id)
+   return NULL;
+   return dmi_id->driver_data;
+}
+
  /* Call the ATIF method
   */
  /**
@@ -1388,6 +1418,7 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device 
*adev)
   */
  void amdgpu_acpi_detect(void)
  {
+   const struct amdgpu_acpi_quirks *quirks = amdgpu_acpi_get_quirks();
struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif;
struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs;
struct pci_dev *pdev = NULL;
@@ -1429,6 +1460,10 @@ void amdgpu_acpi_detect(void)
ret);
atif->backlight_caps.caps_valid = false;
}
+   if (quirks && quirks->ignore_min_input_signal) {
+   DRM_INFO("amdgpu_acpi quirk: min_input_signal=0\n");
+   atif->backlight_caps.min_input_signal = 0;
+   }
} else {
atif->backlight_caps.caps_valid = false;
}

---
base-commit: 83a7eefedc9b56fe7bfeff13b6c7356688ffa670
change-id: 20240610-amdgpu-min-backlight-quirk-8402fd8e736a

Best regards,




Re: [PATCH v2] drm/amd/display: Guard ACPI calls with CONFIG_ACPI

2024-06-10 Thread Mario Limonciello

On 6/10/2024 10:58, sunpeng...@amd.com wrote:

From: Leo Li 

To fix CONFIG_ACPI disabled build error.

v2: Instead of ifdef-ing inside function, define a no-op stub for
amdgpu_acpi_get_backlight_caps when CONFIG_ACPI=n

Fixes: ec6f30c776ad ("drm/amd/display: Set default brightness according to 
ACPI")
Signed-off-by: Leo Li 
---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 1f71c7b98d77..083f353cff6e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1576,6 +1576,7 @@ static inline int amdgpu_acpi_power_shift_control(struct 
amdgpu_device *adev,
  u8 dev_state, bool drv_state) 
{ return 0; }
  static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
 enum amdgpu_ss ss_state) { 
return 0; }
+static inline void amdgpu_acpi_get_backlight_caps(struct 
amdgpu_dm_backlight_caps *caps) { }
  #endif
  
  #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)


Reviewed-by: Mario Limonciello 


Re: [PATCH] drm/amd/display: Guard ACPI calls with CONFIG_ACPI

2024-06-10 Thread Mario Limonciello

On 6/10/2024 09:55, sunpeng...@amd.com wrote:

From: Leo Li 

To fix CONFIG_ACPI disabled build error.

Fixes: ec6f30c776ad ("drm/amd/display: Set default brightness according to 
ACPI")
Signed-off-by: Leo Li 
---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++
  1 file changed, 6 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 a2c098f1b07c..6b3634db4c15 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4572,7 +4572,9 @@ amdgpu_dm_register_backlight_device(struct 
amdgpu_dm_connector *aconnector)
struct drm_device *drm = aconnector->base.dev;
struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
struct backlight_properties props = { 0 };
+#if defined(CONFIG_ACPI)
struct amdgpu_dm_backlight_caps caps = { 0 };
+#endif
char bl_name[16];
  
  	if (aconnector->bl_idx == -1)

@@ -4585,6 +4587,7 @@ amdgpu_dm_register_backlight_device(struct 
amdgpu_dm_connector *aconnector)
return;
}
  
+#if defined(CONFIG_ACPI)

amdgpu_acpi_get_backlight_caps(&caps);
if (caps.caps_valid) {
if (power_supply_is_system_supplied() > 0)
@@ -4593,6 +4596,9 @@ amdgpu_dm_register_backlight_device(struct 
amdgpu_dm_connector *aconnector)
props.brightness = caps.dc_level;
} else
props.brightness = AMDGPU_MAX_BL_LEVEL;
+#else
+   props.brightness = AMDGPU_MAX_BL_LEVEL;
+#endif


Hey Leo,

Thanks for the patch!

As caps is initialized to {0} caps.caps_valid will be invalid.  So I see 
two other ways to solve this that are a little cleaner (IMO):


1)  Just block the one call:

#if defined(CONFIG_ACPI)
amdgpu_acpi_get_backlight_caps(&caps);
#endif

2) Add a stub inline no-op function for amdgpu_acpi_get_backlight_caps() 
to the header.


I personally think #2 is cleaner (less ifdef makes a lot more readable 
code).


  
  	props.max_brightness = AMDGPU_MAX_BL_LEVEL;

props.type = BACKLIGHT_RAW;


[PATCH] drm/amd/display: Set default brightness according to ACPI

2024-06-06 Thread Mario Limonciello
Currently, amdgpu will always set up the brightness at 100% when it
loads.  However this is jarring when the BIOS has it previously
programmed to a much lower value.

The ACPI ATIF method includes two members for "ac_level" and "dc_level".
These represent the default values that should be used if the system is
brought up in AC and DC respectively.

Use these values to set up the default brightness when the backlight
device is registered.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c  |  4 
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 +++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  8 
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 7099ff9cf8c5..f85ace0384d2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -383,6 +383,8 @@ static int amdgpu_atif_query_backlight_caps(struct 
amdgpu_atif *atif)
characteristics.min_input_signal;
atif->backlight_caps.max_input_signal =
characteristics.max_input_signal;
+   atif->backlight_caps.ac_level = characteristics.ac_level;
+   atif->backlight_caps.dc_level = characteristics.dc_level;
 out:
kfree(info);
return err;
@@ -1268,6 +1270,8 @@ void amdgpu_acpi_get_backlight_caps(struct 
amdgpu_dm_backlight_caps *caps)
caps->caps_valid = atif->backlight_caps.caps_valid;
caps->min_input_signal = atif->backlight_caps.min_input_signal;
caps->max_input_signal = atif->backlight_caps.max_input_signal;
+   caps->ac_level = atif->backlight_caps.ac_level;
+   caps->dc_level = atif->backlight_caps.dc_level;
 }
 
 /**
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 5fd7210b2479..71aa0c518951 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -77,6 +77,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -4321,6 +4322,7 @@ amdgpu_dm_register_backlight_device(struct 
amdgpu_dm_connector *aconnector)
struct drm_device *drm = aconnector->base.dev;
struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
struct backlight_properties props = { 0 };
+   struct amdgpu_dm_backlight_caps caps = { 0 };
char bl_name[16];
 
if (aconnector->bl_idx == -1)
@@ -4333,8 +4335,16 @@ amdgpu_dm_register_backlight_device(struct 
amdgpu_dm_connector *aconnector)
return;
}
 
+   amdgpu_acpi_get_backlight_caps(&caps);
+   if (caps.caps_valid) {
+   if (power_supply_is_system_supplied() > 0)
+   props.brightness = caps.ac_level;
+   else
+   props.brightness = caps.dc_level;
+   } else
+   props.brightness = AMDGPU_MAX_BL_LEVEL;
+
props.max_brightness = AMDGPU_MAX_BL_LEVEL;
-   props.brightness = AMDGPU_MAX_BL_LEVEL;
props.type = BACKLIGHT_RAW;
 
snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
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 b246e82f5b0d..df72cb71e95a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -173,6 +173,14 @@ struct amdgpu_dm_backlight_caps {
 * @aux_support: Describes if the display supports AUX backlight.
 */
bool aux_support;
+   /**
+* @ac_level: the default brightness if booted on AC
+*/
+   u8 ac_level;
+   /**
+* @dc_level: the default brightness if booted on DC
+*/
+   u8 dc_level;
 };
 
 /**
-- 
2.43.0



Re: [PATCH v2] drm/amdgpu: Fix the BO release clear memory warning

2024-06-06 Thread Mario Limonciello

On 6/6/2024 15:04, Arunpravin Paneer Selvam wrote:

This happens when the amdgpu_bo_release_notify running
before amdgpu_ttm_set_buffer_funcs_status set the buffer
funcs to enabled.

check the buffer funcs enablement before calling the fill
buffer memory.

v2:(Christian)
   - Apply it only for GEM buffers and since GEM buffers are only
 allocated/freed while the driver is loaded we never run into
 the issue to clear with buffer funcs disabled.

Log snip:
[6.036477] [drm:amdgpu_fill_buffer [amdgpu]] *ERROR* Trying to clear memory 
with ring turned off.
[6.036667] [ cut here ]
[6.036668] WARNING: CPU: 3 PID: 370 at 
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:1355 
amdgpu_bo_release_notify+0x201/0x220 [amdgpu]
[6.036767] Modules linked in: hid_generic amdgpu(+) amdxcp drm_exec 
gpu_sched drm_buddy i2c_algo_bit usbhid drm_suballoc_helper drm_display_helper 
hid sd_mod cec rc_core drm_ttm_helper ahci ttm nvme libahci drm_kms_helper 
nvme_core r8169 xhci_pci libata t10_pi xhci_hcd realtek crc32_pclmul 
crc64_rocksoft mdio_devres crc64 drm crc32c_intel scsi_mod usbcore thunderbolt 
crc_t10dif i2c_piix4 libphy crct10dif_generic crct10dif_pclmul crct10dif_common 
scsi_common usb_common video wmi gpio_amdpt gpio_generic button
[6.036793] CPU: 3 PID: 370 Comm: (udev-worker) Not tainted 6.8.7-dirty #1
[6.036795] Hardware name: ASRock X670E Taichi/X670E Taichi, BIOS 2.10 
03/26/2024
[6.036796] RIP: 0010:amdgpu_bo_release_notify+0x201/0x220 [amdgpu]
[6.036891] Code: 0b e9 af fe ff ff 48 ba ff ff ff ff ff ff ff 7f 31 f6 4c 89 e7 
e8 7f 2f 7a d8 eb 98 e8 18 28 7a d8 eb b2 0f 0b e9 58 fe ff ff <0f> 0b eb a7 be 
03 00 00 00 e8 e1 89 4e d8 eb 9b e8 aa 4d ad d8 66
[6.036892] RSP: 0018:bbe140d1f638 EFLAGS: 00010282
[6.036894] RAX: ffea RBX: 90cba9e4e858 RCX: 90dabde38c28
[6.036895] RDX:  RSI: dfff RDI: 0001
[6.036896] RBP: 90cba980ef40 R08:  R09: bbe140d1f3c0
[6.036896] R10: bbe140d1f3b8 R11: 0003 R12: 90cba9e4e800
[6.036897] R13: 90cba9e4e958 R14: 90cba980ef40 R15: 0258
[6.036898] FS:  7f2bd1679d00() GS:90da7e2c() 
knlGS:
[6.036899] CS:  0010 DS:  ES:  CR0: 80050033
[6.036900] CR2: 55a9b0f7299d CR3: 00011bb6e000 CR4: 00750ef0
[6.036901] PKRU: 5554
[6.036901] Call Trace:
[6.036903]  
[6.036904]  ? amdgpu_bo_release_notify+0x201/0x220 [amdgpu]
[6.036998]  ? __warn+0x81/0x130
[6.037002]  ? amdgpu_bo_release_notify+0x201/0x220 [amdgpu]
[6.037095]  ? report_bug+0x171/0x1a0
[6.037099]  ? handle_bug+0x3c/0x80
[6.037101]  ? exc_invalid_op+0x17/0x70
[6.037103]  ? asm_exc_invalid_op+0x1a/0x20
[6.037107]  ? amdgpu_bo_release_notify+0x201/0x220 [amdgpu]
[6.037199]  ? amdgpu_bo_release_notify+0x14a/0x220 [amdgpu]
[6.037292]  ttm_bo_release+0xff/0x2e0 [ttm]
[6.037297]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.037299]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.037301]  ? ttm_resource_move_to_lru_tail+0x140/0x1e0 [ttm]
[6.037306]  amdgpu_bo_free_kernel+0xcb/0x120 [amdgpu]
[6.037399]  dm_helpers_free_gpu_mem+0x41/0x80 [amdgpu]
[6.037544]  dcn315_clk_mgr_construct+0x198/0x7e0 [amdgpu]
[6.037692]  dc_clk_mgr_create+0x16e/0x5f0 [amdgpu]
[6.037826]  dc_create+0x28a/0x650 [amdgpu]
[6.037958]  amdgpu_dm_init.isra.0+0x2d5/0x1ec0 [amdgpu]
[6.038085]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038087]  ? prb_read_valid+0x1b/0x30
[6.038089]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038090]  ? console_unlock+0x78/0x120
[6.038092]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038094]  ? vprintk_emit+0x175/0x2c0
[6.038095]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038097]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038098]  ? dev_printk_emit+0xa5/0xd0
[6.038104]  dm_hw_init+0x12/0x30 [amdgpu]
[6.038209]  amdgpu_device_init+0x1e50/0x2500 [amdgpu]
[6.038308]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038310]  ? srso_alias_return_thunk+0x5/0xfbef5
[6.038313]  amdgpu_driver_load_kms+0x19/0x190 [amdgpu]
[6.038409]  amdgpu_pci_probe+0x18b/0x510 [amdgpu]
[6.038505]  local_pci_probe+0x42/0xa0
[6.038508]  pci_device_probe+0xc7/0x240
[6.038510]  really_probe+0x19b/0x3e0
[6.038513]  ? __pfx___driver_attach+0x10/0x10
[6.038514]  __driver_probe_device+0x78/0x160
[6.038516]  driver_probe_device+0x1f/0x90
[6.038517]  __driver_attach+0xd2/0x1c0
[6.038519]  bus_for_each_dev+0x85/0xd0
[6.038521]  bus_add_driver+0x116/0x220
[6.038523]  driver_register+0x59/0x100
[6.038525]  ? __pfx_amdgpu_init+0x10/0x10 [amdgpu]
[6.038618]  do_one_initcall+0x58/0x320
[6.038621]  do_init_module+0x60/0x230
[6.038624]  init_module_from_file+0x89/0xe0
[6.038628]  idempotent_init_module+0x120/0x2b0
[6.

Re: [syzbot] [mm?] general protection fault in dequeue_hugetlb_folio_nodemask

2024-06-06 Thread Mario Limonciello

On 6/6/2024 09:39, syzbot wrote:

Hello,

syzbot found the following issue on:

HEAD commit:0e1980c40b6e Add linux-next specific files for 20240531
git tree:   linux-next
console+strace: https://syzkaller.appspot.com/x/log.txt?x=166086f298
kernel config:  https://syzkaller.appspot.com/x/.config?x=d9c3ca4e54577b88
dashboard link: https://syzkaller.appspot.com/bug?extid=c019f68a83ef9b456444
compiler:   Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 
2.40
syz repro:  https://syzkaller.appspot.com/x/repro.syz?x=12f4094a98
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=15e1e43298

Downloadable assets:
disk image: 
https://storage.googleapis.com/syzbot-assets/44fb1d8b5978/disk-0e1980c4.raw.xz
vmlinux: 
https://storage.googleapis.com/syzbot-assets/a66ce5caf0b2/vmlinux-0e1980c4.xz
kernel image: 
https://storage.googleapis.com/syzbot-assets/8992fc8fe046/bzImage-0e1980c4.xz

The issue was bisected to:

commit cd94d1b182d2986378550c9087571991bfee01d4
Author: Mario Limonciello 
Date:   Thu May 2 18:32:17 2024 +

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

bisection log:  https://syzkaller.appspot.com/x/bisect.txt?x=176121c298
console output: https://syzkaller.appspot.com/x/log.txt?x=10e121c298

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+c019f68a83ef9b456...@syzkaller.appspotmail.com
Fixes: cd94d1b182d2 ("dm/amd/pm: Fix problems with reboot/shutdown for some SMU 
13.0.4/13.0.11 users")

Oops: general protection fault, probably for non-canonical address 
0xdc000489:  [#1] PREEMPT SMP KASAN PTI
KASAN: probably user-memory-access in range 
[0x2448-0x244f]
CPU: 1 PID: 5089 Comm: syz-executor257 Not tainted 
6.10.0-rc1-next-20240531-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 
04/02/2024
RIP: 0010:zonelist_zone_idx include/linux/mmzone.h:1613 [inline]
RIP: 0010:next_zones_zonelist include/linux/mmzone.h:1644 [inline]
RIP: 0010:first_zones_zonelist include/linux/mmzone.h:1670 [inline]
RIP: 0010:dequeue_hugetlb_folio_nodemask+0x193/0xe40 mm/hugetlb.c:1362
Code: 13 9b a0 ff c7 44 24 14 00 00 00 00 83 7c 24 40 00 0f 85 97 0c 00 00 48 83 7c 
24 20 00 0f 85 45 09 00 00 48 89 d8 48 c1 e8 03 <42> 0f b6 04 28 84 c0 0f 85 58 
09 00 00 44 8b 33 44 89 f7 8b 5c 24
RSP: 0018:c900035ef720 EFLAGS: 00010002
RAX: 0489 RBX: 2448 RCX: 888026ef
RDX:  RSI:  RDI: 
RBP: c900035ef858 R08: 81f5e070 R09: f520006bdee8
R10: dc00 R11: f520006bdee8 R12: 
R13: dc00 R14:  R15: 
FS:  64010380() GS:8880b950() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 005fdeb8 CR3: 7bd96000 CR4: 003506f0
DR0:  DR1:  DR2: 
DR3:  DR6: fffe0ff0 DR7: 0400
Call Trace:
  
  alloc_hugetlb_folio_nodemask+0xae/0x3f0 mm/hugetlb.c:2603
  memfd_alloc_folio+0x15e/0x390 mm/memfd.c:75
  memfd_pin_folios+0x1066/0x1720 mm/gup.c:3864
  udmabuf_create+0x658/0x11c0 drivers/dma-buf/udmabuf.c:353
  udmabuf_ioctl_create drivers/dma-buf/udmabuf.c:420 [inline]
  udmabuf_ioctl+0x304/0x4f0 drivers/dma-buf/udmabuf.c:451
  vfs_ioctl fs/ioctl.c:51 [inline]
  __do_sys_ioctl fs/ioctl.c:907 [inline]
  __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:893
  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
  do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
  entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f5151a7a369
Code: 48 83 c4 28 c3 e8 37 17 00 00 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 
48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 
c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:7ffd962ee9e8 EFLAGS: 0246 ORIG_RAX: 0010
RAX: ffda RBX: 7ffd962eebb8 RCX: 7f5151a7a369
RDX: 22c0 RSI: 40187542 RDI: 0003
RBP: 7f5151aed610 R08: 7ffd962eebb8 R09: 7ffd962eebb8
R10: 7ffd962eebb8 R11: 0246 R12: 0001
R13: 7ffd962eeba8 R14: 0001 R15: 0001
  
Modules linked in:
---[ end trace  ]---
RIP: 0010:zonelist_zone_idx include/linux/mmzone.h:1613 [inline]
RIP: 0010:next_zones_zonelist include/linux/mmzone.h:1644 [inline]
RIP: 0010:first_zones_zonelist include/linux/mmzone.h:1670 [inline]
RIP: 0010:dequeue_hugetlb_folio_nodemask+0x193/0xe40 mm/hugetlb.c:1362
Code: 13 9b a0 ff c7 44 24 14 00 00 00 00 83 7c 24 40 00 0f 85 97 0c 00 00 48 83 7c 
24 20 00 0f 85 45 09 00 00 48 89 d8 48 c1 e8 03 <42> 0f b6 04 28 84 c0 0f 85 58 
09 00 00 44 8b 33 44 89 f7 8b 5c 24
RSP: 0018:c900035ef720 EFLAGS: 00010002
RAX: 04

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

2024-06-05 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.

v2->v3:
 * Updates from Leo's comments (see individual patches)

The matching changes for the igt are here:
https://lore.kernel.org/dri-devel/2024050849.33343-1-mario.limoncie...@amd.com/

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 | 50 +--
 .../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, 111 insertions(+), 5 deletions(-)

-- 
2.43.0



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

2024-06-05 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 
---
v2->v3:
 * Use `disallow_edp_enter_psr` instead
 * Drop case in dm_update_crtc_state()
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  4 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 50 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 3 files changed, 51 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 f1d67c6f4b98..5fd7210b2479 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6436,6 +6436,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;
@@ -6478,6 +6485,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;
@@ -6504,9 +6518,12 @@ static ssize_t panel_power_savings_show(struct device 
*device,
u8 val;
 
drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
 
return sysfs_emit(buf, "%u\n", val);
@@ -6530,10 +6547,16 @@ static ssize_t panel_power_savings_store(struct device 
*device,
return -EINVAL;
 
drm_modeset_lock(&dev->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(&dev->mode_config.connection_mutex);
 
+   if (ret)
+   return ret;
+
drm_kms_helper_hotplug_event(dev);
 
return count;
@@ -7704,6 +7727,13 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_reques

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

2024-06-05 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.

Acked-by: Leo Li 
Signed-off-by: Mario Limonciello 
---
v2->v3:
* Add tag
---
 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 8de3c9a5f61b..eefcbf6c5377 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -969,6 +969,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 1ca

Re: [PATCH v2] drm/client: Detect when ACPI lid is closed during initialization

2024-05-29 Thread Mario Limonciello





If you don't hook into some lid notify event how is one supposed to get
the display back to life after opening the lid?


I guess in my mind it's a tangential to the "initial modeset".  The DRM
master can issue a modeset to enable the combination as desired.


This code is run whenever there's a hotplug/etc. Not sure why you're
only thinking about the initial modeset.


Got it; so in that case adding a notification chain for lid events to 
run it again should do the trick.






When I tested I did confirm that with mutter such an event is received
and it does the modeset to enable the eDP when lid is opened.


This code isn't relevant when you have a userspace drm master
calling the shots.


Right.





Let me ask this - what happens if no DRM master running and you hotplug
a DP cable?  Does a "new" clone configuration get done?


Yes, this code reprobes the displays and comes up with a new
config to suit the new situation.


Got it; in this case you're right we should have some notification 
chain.  Do you think it should be in the initial patch or a follow up?




The other potential issue here is whether acpi_lid_open() is actually
trustworthy. Some kms drivers have/had some lid handling in their own
code, and I'm pretty sure those have often needed quirks/modparams
to actually do sensible things on certain machines.

FWIW I ripped out all the lid crap from i915 long ago since it was
half backed, mostly broken, and ugly, and I'm not looking to add it
back there. But I do think handling that in drm_client does seem
somewhat sane, as that should more or less match what userspace
clients would do. Just a question of how bad the quirk situation
will get...



If the lid reporting is wrong it's not just drm_client that would 
falter.  There are other parts of the kernel that rely upon 
acpi_lid_open() being accurate and IMO it would be best to put any 
quirks to the effect in drivers/acpi/button.c.


If it can't be relied upon then it's best to just report -EINVAL or -ENODEV.



Also a direct acpi_lid_open() call seems a bit iffy. But I guess if
someone needs this to work on non-ACPI system they get to figure out
how to abstract it better. acpi_lid_open() does seem to return != 0
when ACPI is not supported, so at least it would err on the side
of enabling everything.



Yeah acpi_lid_open() seemed fine to me specifically because non ACPI 
hardcodes to open.


Re: [PATCH v2] drm/client: Detect when ACPI lid is closed during initialization

2024-05-29 Thread Mario Limonciello

On 5/29/2024 09:14, Ville Syrjälä wrote:

On Tue, May 28, 2024 at 04:03:19PM -0500, Mario Limonciello wrote:

If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the ACPI
lid status and if it's closed disable any eDP connectors.

Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
Cc: hughsi...@gmail.com
v1->v2:
  * Match LVDS as well
---
  drivers/gpu/drm/drm_client_modeset.c | 30 
  1 file changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 31af5cf37a09..0b0411086e76 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -8,6 +8,7 @@
   */
  
  #include "drm/drm_modeset_lock.h"

+#include 
  #include 
  #include 
  #include 
@@ -257,6 +258,34 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,
enabled[i] = drm_connector_enabled(connectors[i], false);
  }
  
+static void drm_client_match_edp_lid(struct drm_device *dev,

+struct drm_connector **connectors,
+unsigned int connector_count,
+bool *enabled)
+{
+   int i;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   if (!enabled[i])
+   continue;
+   break;
+   default:
+   continue;
+   }
+
+   if (!acpi_lid_open()) {
+   drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",
+   connector->base.id, connector->name);
+   enabled[i] = false;
+   }
+   }
+}


If you don't hook into some lid notify event how is one supposed to get
the display back to life after opening the lid?


I guess in my mind it's a tangential to the "initial modeset".  The DRM 
master can issue a modeset to enable the combination as desired.


When I tested I did confirm that with mutter such an event is received 
and it does the modeset to enable the eDP when lid is opened.


Let me ask this - what happens if no DRM master running and you hotplug 
a DP cable?  Does a "new" clone configuration get done?



+
  static bool drm_client_target_cloned(struct drm_device *dev,
 struct drm_connector **connectors,
 unsigned int connector_count,
@@ -844,6 +873,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, 
unsigned int width,
memset(crtcs, 0, connector_count * sizeof(*crtcs));
memset(offsets, 0, connector_count * sizeof(*offsets));
  
+		drm_client_match_edp_lid(dev, connectors, connector_count, enabled);

if (!drm_client_target_cloned(dev, connectors, connector_count, 
modes,
  offsets, enabled, width, height) 
&&
!drm_client_target_preferred(dev, connectors, 
connector_count, modes,
--
2.43.0






Re: [PATCH v2] drm/client: Detect when ACPI lid is closed during initialization

2024-05-29 Thread Mario Limonciello

On 5/29/2024 08:55, Alex Deucher wrote:

On Wed, May 29, 2024 at 9:51 AM Jani Nikula  wrote:


On Wed, 29 May 2024, Alex Deucher  wrote:

On Tue, May 28, 2024 at 5:03 PM Mario Limonciello
 wrote:


If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the ACPI
lid status and if it's closed disable any eDP connectors.

Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 


Reviewed-by: Alex Deucher 

Do you have drm-misc access or do you need someone to apply this for you?


I've bounced this to intel-gfx and intel-xe lists to get CI testing. I'd
appreciate holding off on merging until we have results.


Sure.


Thanks for the review and pushing it to CI testing infra.

I don't have any drm-misc access so if everything looks good then one of 
you guys please merge it for me.


Thanks!



Alex



Thanks,
Jani.



Alex


---
Cc: hughsi...@gmail.com
v1->v2:
  * Match LVDS as well
---
  drivers/gpu/drm/drm_client_modeset.c | 30 
  1 file changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 31af5cf37a09..0b0411086e76 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -8,6 +8,7 @@
   */

  #include "drm/drm_modeset_lock.h"
+#include 
  #include 
  #include 
  #include 
@@ -257,6 +258,34 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,
 enabled[i] = drm_connector_enabled(connectors[i], false);
  }

+static void drm_client_match_edp_lid(struct drm_device *dev,
+struct drm_connector **connectors,
+unsigned int connector_count,
+bool *enabled)
+{
+   int i;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   if (!enabled[i])
+   continue;
+   break;
+   default:
+   continue;
+   }
+
+   if (!acpi_lid_open()) {
+   drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",
+   connector->base.id, connector->name);
+   enabled[i] = false;
+   }
+   }
+}
+
  static bool drm_client_target_cloned(struct drm_device *dev,
  struct drm_connector **connectors,
  unsigned int connector_count,
@@ -844,6 +873,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, 
unsigned int width,
 memset(crtcs, 0, connector_count * sizeof(*crtcs));
 memset(offsets, 0, connector_count * sizeof(*offsets));

+   drm_client_match_edp_lid(dev, connectors, connector_count, 
enabled);
 if (!drm_client_target_cloned(dev, connectors, 
connector_count, modes,
   offsets, enabled, width, height) 
&&
 !drm_client_target_preferred(dev, connectors, 
connector_count, modes,
--
2.43.0



--
Jani Nikula, Intel




[PATCH v2] drm/client: Detect when ACPI lid is closed during initialization

2024-05-28 Thread Mario Limonciello
If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the ACPI
lid status and if it's closed disable any eDP connectors.

Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
Cc: hughsi...@gmail.com
v1->v2:
 * Match LVDS as well
---
 drivers/gpu/drm/drm_client_modeset.c | 30 
 1 file changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 31af5cf37a09..0b0411086e76 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -8,6 +8,7 @@
  */
 
 #include "drm/drm_modeset_lock.h"
+#include 
 #include 
 #include 
 #include 
@@ -257,6 +258,34 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,
enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
+static void drm_client_match_edp_lid(struct drm_device *dev,
+struct drm_connector **connectors,
+unsigned int connector_count,
+bool *enabled)
+{
+   int i;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   switch (connector->connector_type) {
+   case DRM_MODE_CONNECTOR_LVDS:
+   case DRM_MODE_CONNECTOR_eDP:
+   if (!enabled[i])
+   continue;
+   break;
+   default:
+   continue;
+   }
+
+   if (!acpi_lid_open()) {
+   drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",
+   connector->base.id, connector->name);
+   enabled[i] = false;
+   }
+   }
+}
+
 static bool drm_client_target_cloned(struct drm_device *dev,
 struct drm_connector **connectors,
 unsigned int connector_count,
@@ -844,6 +873,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, 
unsigned int width,
memset(crtcs, 0, connector_count * sizeof(*crtcs));
memset(offsets, 0, connector_count * sizeof(*offsets));
 
+   drm_client_match_edp_lid(dev, connectors, connector_count, 
enabled);
if (!drm_client_target_cloned(dev, connectors, connector_count, 
modes,
  offsets, enabled, width, height) 
&&
!drm_client_target_preferred(dev, connectors, 
connector_count, modes,
-- 
2.43.0



Re: [PATCH] drm/amd/amdgpu: Fix 'snprintf' output truncation warning

2024-05-28 Thread Mario Limonciello

On 5/28/2024 10:24, Pratap Nirujogi wrote:

snprintf can truncate the output fw filename if the isp ucode_prefix
exceeds 29 characters. Knowing ISP ucode_prefix is in the format
isp_x_x_x, limiting the size of ucode_prefix[] to 10 characters
to fix the warning.

Fixes the below warning:

drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c: In function 'isp_early_init':
drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c:192:58: warning: 'snprintf'
output may be truncated before the last format character
[-Wformat-truncation=]
  192 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", 
ucode_prefix);
  |  ^
In function 'isp_load_fw_by_psp',
inlined from 'isp_early_init' at 
drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c:218:8:
drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c:192:9: note: 'snprintf' output 
between 12 and 41 bytes into a destination of size 40
  192 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", 
ucode_prefix);
  | 
^

Signed-off-by: Pratap Nirujogi 


As the kernel robot reported this you should add a "Reported-by:" tag 
for it.


Otherwise LGTM (feel free to add that tag when committing).

Reviewed-by: Mario Limonciello 


---
  drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
index 240408486d6b..2a3f4668cb9b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -96,7 +96,7 @@ static int isp_resume(void *handle)
  static int isp_load_fw_by_psp(struct amdgpu_device *adev)
  {
const struct common_firmware_header *hdr;
-   char ucode_prefix[30];
+   char ucode_prefix[10];
char fw_name[40];
int r = 0;
  




[PATCH] drm/client: Detect when ACPI lid is closed during initialization

2024-05-27 Thread Mario Limonciello
If the lid on a laptop is closed when eDP connectors are populated
then it remains enabled when the initial framebuffer configuration
is built.

When creating the initial framebuffer configuration detect the ACPI
lid status and if it's closed disable any eDP connectors.

Suggested-by: Alex Deucher 
Reported-by: Chris Bainbridge 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3349
Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/drm_client_modeset.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 31af5cf37a09..b76438c31761 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -8,6 +8,7 @@
  */
 
 #include "drm/drm_modeset_lock.h"
+#include 
 #include 
 #include 
 #include 
@@ -257,6 +258,27 @@ static void drm_client_connectors_enabled(struct 
drm_connector **connectors,
enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
+static void drm_client_match_edp_lid(struct drm_device *dev,
+struct drm_connector **connectors,
+unsigned int connector_count,
+bool *enabled)
+{
+   int i;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   if (connector->connector_type != DRM_MODE_CONNECTOR_eDP || 
!enabled[i])
+   continue;
+
+   if (!acpi_lid_open()) {
+   drm_dbg_kms(dev, "[CONNECTOR:%d:%s] lid is closed, 
disabling\n",
+   connector->base.id, connector->name);
+   enabled[i] = false;
+   }
+   }
+}
+
 static bool drm_client_target_cloned(struct drm_device *dev,
 struct drm_connector **connectors,
 unsigned int connector_count,
@@ -844,6 +866,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, 
unsigned int width,
memset(crtcs, 0, connector_count * sizeof(*crtcs));
memset(offsets, 0, connector_count * sizeof(*offsets));
 
+   drm_client_match_edp_lid(dev, connectors, connector_count, 
enabled);
if (!drm_client_target_cloned(dev, connectors, connector_count, 
modes,
  offsets, enabled, width, height) 
&&
!drm_client_target_preferred(dev, connectors, 
connector_count, modes,
-- 
2.43.0



[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(&data->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(&data);
igt_subtest("abm_gradual")
abm_gradual(&data);
+   igt_subtest("abm_forbidden")
+   abm_forbidden(&data);
 
igt_fixture {
igt_display_fini(&data.display);
-- 
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(&max_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(&max_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(&data->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, &ref_fb);
+   igt_create_color_fb(data->fd, data->mode->hdisplay,
+   data->mode->vdisplay, DRM_FORMAT_XRGB, 
0, 0.0,
+   1.0, 0.0, &ref_fb2);
+
+   igt_plane_set_fb(data->primary, &ref_fb);
+
+   igt_display_commit_atomic(&data->display, 
DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+   for (i = 0; i < N_FLIPS; i++) {
+   if (i % 2 == 0)
+   flip_fb = &ref_fb2;
+   else
+   flip_fb = &ref_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, &ref_fb);
+   igt_remove_fb(data->fd, &ref_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(&data, 
true, .75);
+   igt_describe("Test whether PSR can be forbidden");
+   igt_subtest("psr_forbidden") psr_forbidden(&data);
 
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",
+   &prop_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



  1   2   3   4   5   6   7   8   9   >