[PATCH v2] drm/amd/pm: defer UCLK DPM enablement on Apple Navi 14
From: Ed Schofield
Date: Wed Sep 09 2026 - 09:07:52 EST
Apple Navi 14 boards 1002:7340/106b:0218 (revision 0x41) and
1002:7340/106b:0219 can time out when EnableAllSmuFeatures includes
UCLK DPM, leaving amdgpu without a DRM device.
Exclude only UCLK DPM from the initial allowed features and enable it
separately in the Navi post-init callback. On 0218, enabling UCLK just
after EnableAllSmuFeatures or at the start of default DPM table setup
still timed out. The earlier 0218-only patch passed ten warm boots with
UCLK enabled in post-init. The earliest safe point remains unknown.
Check the enabled firmware bit, update the supported-feature bit and
rebuild the memory DPM table and sustainable clock limits before the
UMC workaround and UMD clock setup. Validate the PPT memory states that
DCN20 consumes before post-init. Preserve both memory-voltage features
and honor PP_MCLK_DPM_MASK.
Combine Atharva Tiwari's delayed-UCLK proposal for 0219 with the Navi
post-init implementation for 0218. Retain the revision restriction for
0218 and the revision-independent 0219 match from Atharva's proposal.
The combined patch passed ten warm boots on 0218, with rendering and
H.264 video decoding checks on every boot. Testing on 0219 is still
pending.
Link: https://www.mail-archive.com/amd-gfx@xxxxxxxxxxxxxxxxxxxxx/msg149770.html
Link: https://github.com/t2linux/kernel/issues/19#issuecomment-5537823876
Assisted-by: Codex:GPT-6
Signed-off-by: Ed Schofield <ed@xxxxxxxxxxxxxx>
---
Changes since the 0218-only RFC:
- Add the 0219 board match from Atharva's proposal, without a revision
restriction. Keep the 0218 match limited to revision 0x41.
- Keep the Navi post-init implementation and clock-state updates from
the RFC. Atharva's proposal enabled UCLK at the end of smu_late_init().
- Record the failed tests at the start of default DPM table setup and
ten successful warm boots of the combined patch on 0218.
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index f8ca5eb9a..d7cc41a5d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -60,6 +60,19 @@
static int navi10_init_ppt_limits(struct smu_context *smu);
+static bool navi14_needs_late_uclk(struct amdgpu_device *adev)
+{
+ struct pci_dev *pdev = adev->pdev;
+
+ return pdev->vendor == PCI_VENDOR_ID_ATI &&
+ pdev->device == 0x7340 &&
+ pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
+ ((pdev->subsystem_device == 0x0218 &&
+ pdev->revision == 0x41) ||
+ pdev->subsystem_device == 0x0219) &&
+ (adev->pm.pp_feature & PP_MCLK_DPM_MASK);
+}
+
static const struct smu_feature_bits navi10_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
@@ -356,6 +369,11 @@ navi10_init_allowed_features(struct smu_context *smu)
smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_MVDD_SCALING_BIT);
}
+ /* These boards time out if EnableAllSmuFeatures includes UCLK DPM. */
+ if (navi14_needs_late_uclk(adev))
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED,
+ FEATURE_DPM_UCLK_BIT);
+
if (is_asic_secure(smu) &&
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) &&
(adev->rev_id == 0))
@@ -470,6 +488,25 @@ static int navi10_store_powerplay_table(struct smu_context *smu)
return 0;
}
+/* DCN20 consumes these PPT states before the post-init UCLK enable. */
+static int navi14_imac_check_uclk_states(struct smu_context *smu)
+{
+ PPTable_t *ppt = smu->smu_table.driver_pptable;
+ unsigned int count, i;
+
+ if (!navi14_needs_late_uclk(smu->adev))
+ return 0;
+
+ count = ppt->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels;
+ if (!count || count > ARRAY_SIZE(ppt->FreqTableUclk))
+ return -EINVAL;
+ for (i = 0; i < count; i++) {
+ if (!ppt->FreqTableUclk[i])
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int navi10_setup_pptable(struct smu_context *smu)
{
int ret = 0;
@@ -490,6 +527,10 @@ static int navi10_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
+ ret = navi14_imac_check_uclk_states(smu);
+ if (ret)
+ return ret;
+
return navi10_init_ppt_limits(smu);
}
@@ -3219,6 +3260,41 @@ static int navi10_enable_mgpu_fan_boost(struct smu_context *smu)
NULL);
}
+/* Rebuild memory clocks before the UMC workaround and UMD clock setup. */
+static int navi14_imac_late_uclk_enable(struct smu_context *smu)
+{
+ struct smu_11_0_dpm_context *dpm = smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *table = &dpm->dpm_tables.uclk_table;
+ PPTable_t *ppt = smu->smu_table.driver_pptable;
+ struct smu_feature_bits enabled;
+ int ret;
+
+ if (!navi14_needs_late_uclk(smu->adev))
+ return 0;
+
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT, true);
+ if (ret)
+ return ret;
+ ret = smu_cmn_get_enabled_mask(smu, &enabled);
+ if (ret)
+ return ret;
+ if (!smu_feature_bits_is_set(&enabled, FEATURE_DPM_UCLK_BIT))
+ return -EIO;
+
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_SUPPORTED,
+ FEATURE_DPM_UCLK_BIT);
+ table->clk_type = SMU_UCLK;
+ ret = smu_v11_0_set_single_dpm_table(smu, SMU_UCLK, table);
+ if (ret)
+ return ret;
+ if (!table->count)
+ return -EINVAL;
+ if (!ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete)
+ table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
+
+ return smu_v11_0_init_max_sustainable_clocks(smu);
+}
+
static int navi10_post_smu_init(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -3227,6 +3303,12 @@ static int navi10_post_smu_init(struct smu_context *smu)
if (amdgpu_sriov_vf(adev))
return 0;
+ ret = navi14_imac_late_uclk_enable(smu);
+ if (ret) {
+ dev_err(adev->dev, "Failed to enable late UCLK DPM: %d\n", ret);
+ return ret;
+ }
+
ret = navi10_run_umc_cdr_workaround(smu);
if (ret)
dev_err(adev->dev, "Failed to apply umc cdr workaround!\n");
base-commit: c22f9a61e288580824edbbc3ae5a29c9a338594f
--
2.55.0