From: Ville Syrjala <ville.syrjala@linux.intel.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 3/3] drm/i915/dram: Fix ICL DIMM_S decoding
Date: Wed, 29 Oct 2025 22:42:15 +0200 [thread overview]
Message-ID: <20251029204215.12292-4-ville.syrjala@linux.intel.com> (raw)
In-Reply-To: <20251029204215.12292-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Unfortunately the MAD_DIMM DIMM_S and DIMM_L bits on ICL are
not idential, so we are currently decoding DIMM_S incorrectly.
Fix the problem by defining the DIMM_S and DIMM_L bits separately.
And for consistency do that same for SKL, even though there the
bits do match between the two DIMMs. The result is rather
repetitive in places, but I didn't feel like obfuscatign things
with cpp macros/etc.
Broken decoding on Dell XPS 13 7390 2-in-1:
CH0 DIMM L size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH0 DIMM S size: 32 Gb, width: X32, ranks: 3, 16Gb+ DIMMs: no
CH0 ranks: 2, 16Gb+ DIMMs: no
CH1 DIMM L size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH1 DIMM S size: 32 Gb, width: X32, ranks: 3, 16Gb+ DIMMs: no
CH1 ranks: 2, 16Gb+ DIMMs: no
Memory configuration is symmetric? no
Fixed decoding on Dell XPS 13 7390 2-in-1:
CH0 DIMM L size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH0 DIMM S size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH0 ranks: 2, 16Gb+ DIMMs: no
CH1 DIMM L size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH1 DIMM S size: 32 Gb, width: X16, ranks: 2, 16Gb+ DIMMs: no
CH1 ranks: 2, 16Gb+ DIMMs: no
Memory configuration is symmetric? yes
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_mchbar_regs.h | 53 +++++---
drivers/gpu/drm/i915/soc/intel_dram.c | 166 +++++++++++++++++------
2 files changed, 155 insertions(+), 64 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h
index a46a45b9d2e1..614d4017b57b 100644
--- a/drivers/gpu/drm/i915/intel_mchbar_regs.h
+++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h
@@ -160,25 +160,40 @@
#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010)
-#define SKL_DRAM_S_SHIFT 16
-#define SKL_DRAM_RANK_MASK REG_GENMASK(10, 10)
-#define SKL_DRAM_RANK_1 REG_FIELD_PREP(SKL_DRAM_RANK_MASK, 0)
-#define SKL_DRAM_RANK_2 REG_FIELD_PREP(SKL_DRAM_RANK_MASK, 1)
-#define SKL_DRAM_WIDTH_MASK REG_GENMASK(9, 8)
-#define SKL_DRAM_WIDTH_X8 REG_FIELD_PREP(SKL_DRAM_WIDTH_MASK, 0)
-#define SKL_DRAM_WIDTH_X16 REG_FIELD_PREP(SKL_DRAM_WIDTH_MASK, 1)
-#define SKL_DRAM_WIDTH_X32 REG_FIELD_PREP(SKL_DRAM_WIDTH_MASK, 2)
-#define SKL_DRAM_SIZE_MASK REG_GENMASK(5, 0)
-#define ICL_DRAM_RANK_MASK REG_GENMASK(10, 9)
-#define ICL_DRAM_RANK_1 REG_FIELD_PREP(ICL_DRAM_RANK_MASK, 0)
-#define ICL_DRAM_RANK_2 REG_FIELD_PREP(ICL_DRAM_RANK_MASK, 1)
-#define ICL_DRAM_RANK_3 REG_FIELD_PREP(ICL_DRAM_RANK_MASK, 2)
-#define ICL_DRAM_RANK_4 REG_FIELD_PREP(ICL_DRAM_RANK_MASK, 3)
-#define ICL_DRAM_WIDTH_MASK REG_GENMASK(8, 7)
-#define ICL_DRAM_WIDTH_X8 REG_FIELD_PREP(ICL_DRAM_WIDTH_MASK, 0)
-#define ICL_DRAM_WIDTH_X16 REG_FIELD_PREP(ICL_DRAM_WIDTH_MASK, 1)
-#define ICL_DRAM_WIDTH_X32 REG_FIELD_PREP(ICL_DRAM_WIDTH_MASK, 2)
-#define ICL_DRAM_SIZE_MASK REG_GENMASK(6, 0)
+#define SKL_DIMM_S_RANK_MASK REG_GENMASK(26, 26)
+#define SKL_DIMM_S_RANK_1 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 0)
+#define SKL_DIMM_S_RANK_2 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 1)
+#define SKL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24)
+#define SKL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 0)
+#define SKL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 1)
+#define SKL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 2)
+#define SKL_DIMM_S_SIZE_MASK REG_GENMASK(21, 16)
+#define SKL_DIMM_L_RANK_MASK REG_GENMASK(10, 10)
+#define SKL_DIMM_L_RANK_1 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 0)
+#define SKL_DIMM_L_RANK_2 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 1)
+#define SKL_DIMM_L_WIDTH_MASK REG_GENMASK(9, 8)
+#define SKL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 0)
+#define SKL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 1)
+#define SKL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 2)
+#define SKL_DIMM_L_SIZE_MASK REG_GENMASK(5, 0)
+#define ICL_DIMM_S_RANK_MASK REG_GENMASK(27, 26)
+#define ICL_DIMM_S_RANK_1 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 0)
+#define ICL_DIMM_S_RANK_2 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 1)
+#define ICL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24)
+#define ICL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 0)
+#define ICL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 1)
+#define ICL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 2)
+#define ICL_DIMM_S_SIZE_MASK REG_GENMASK(22, 16)
+#define ICL_DIMM_L_RANK_MASK REG_GENMASK(10, 9)
+#define ICL_DIMM_L_RANK_1 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 0)
+#define ICL_DIMM_L_RANK_2 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 1)
+#define ICL_DIMM_L_RANK_3 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 2)
+#define ICL_DIMM_L_RANK_4 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 3)
+#define ICL_DIMM_L_WIDTH_MASK REG_GENMASK(8, 7)
+#define ICL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 0)
+#define ICL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 1)
+#define ICL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 2)
+#define ICL_DIMM_L_SIZE_MASK REG_GENMASK(6, 0)
#define SA_PERF_STATUS_0_0_0_MCHBAR_PC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5918)
#define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2)
diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c
index 768bede992bc..d8afc6963a48 100644
--- a/drivers/gpu/drm/i915/soc/intel_dram.c
+++ b/drivers/gpu/drm/i915/soc/intel_dram.c
@@ -266,69 +266,121 @@ static int intel_dimm_num_devices(const struct dram_dimm_info *dimm)
}
/* Returns total Gb for the whole DIMM */
-static int skl_get_dimm_size(u16 val)
+static int skl_get_dimm_s_size(u32 val)
{
- return REG_FIELD_GET(SKL_DRAM_SIZE_MASK, val) * 8;
+ return REG_FIELD_GET(SKL_DIMM_S_SIZE_MASK, val) * 8;
}
-static int skl_get_dimm_width(u16 val)
+static int skl_get_dimm_l_size(u32 val)
{
- if (skl_get_dimm_size(val) == 0)
+ return REG_FIELD_GET(SKL_DIMM_L_SIZE_MASK, val) * 8;
+}
+
+static int skl_get_dimm_s_width(u32 val)
+{
+ if (skl_get_dimm_s_size(val) == 0)
+ return 0;
+
+ switch (val & SKL_DIMM_S_WIDTH_MASK) {
+ case SKL_DIMM_S_WIDTH_X8:
+ case SKL_DIMM_S_WIDTH_X16:
+ case SKL_DIMM_S_WIDTH_X32:
+ return 8 << REG_FIELD_GET(SKL_DIMM_S_WIDTH_MASK, val);
+ default:
+ MISSING_CASE(val);
+ return 0;
+ }
+}
+
+static int skl_get_dimm_l_width(u32 val)
+{
+ if (skl_get_dimm_l_size(val) == 0)
return 0;
- switch (val & SKL_DRAM_WIDTH_MASK) {
- case SKL_DRAM_WIDTH_X8:
- case SKL_DRAM_WIDTH_X16:
- case SKL_DRAM_WIDTH_X32:
- val = REG_FIELD_GET(SKL_DRAM_WIDTH_MASK, val);
- return 8 << val;
+ switch (val & SKL_DIMM_L_WIDTH_MASK) {
+ case SKL_DIMM_L_WIDTH_X8:
+ case SKL_DIMM_L_WIDTH_X16:
+ case SKL_DIMM_L_WIDTH_X32:
+ return 8 << REG_FIELD_GET(SKL_DIMM_L_WIDTH_MASK, val);
default:
MISSING_CASE(val);
return 0;
}
}
-static int skl_get_dimm_ranks(u16 val)
+static int skl_get_dimm_s_ranks(u32 val)
{
- if (skl_get_dimm_size(val) == 0)
+ if (skl_get_dimm_s_size(val) == 0)
return 0;
- val = REG_FIELD_GET(SKL_DRAM_RANK_MASK, val);
+ return REG_FIELD_GET(SKL_DIMM_S_RANK_MASK, val) + 1;
+}
+
+static int skl_get_dimm_l_ranks(u32 val)
+{
+ if (skl_get_dimm_l_size(val) == 0)
+ return 0;
- return val + 1;
+ return REG_FIELD_GET(SKL_DIMM_L_RANK_MASK, val) + 1;
}
/* Returns total Gb for the whole DIMM */
-static int icl_get_dimm_size(u16 val)
+static int icl_get_dimm_s_size(u32 val)
{
- return REG_FIELD_GET(ICL_DRAM_SIZE_MASK, val) * 8 / 2;
+ return REG_FIELD_GET(ICL_DIMM_S_SIZE_MASK, val) * 8 / 2;
}
-static int icl_get_dimm_width(u16 val)
+static int icl_get_dimm_l_size(u32 val)
{
- if (icl_get_dimm_size(val) == 0)
+ return REG_FIELD_GET(ICL_DIMM_L_SIZE_MASK, val) * 8 / 2;
+}
+
+static int icl_get_dimm_s_width(u32 val)
+{
+ if (icl_get_dimm_s_size(val) == 0)
+ return 0;
+
+ switch (val & ICL_DIMM_S_WIDTH_MASK) {
+ case ICL_DIMM_S_WIDTH_X8:
+ case ICL_DIMM_S_WIDTH_X16:
+ case ICL_DIMM_S_WIDTH_X32:
+ return 8 << REG_FIELD_GET(ICL_DIMM_S_WIDTH_MASK, val);
+ default:
+ MISSING_CASE(val);
+ return 0;
+ }
+}
+
+static int icl_get_dimm_l_width(u32 val)
+{
+ if (icl_get_dimm_l_size(val) == 0)
return 0;
- switch (val & ICL_DRAM_WIDTH_MASK) {
- case ICL_DRAM_WIDTH_X8:
- case ICL_DRAM_WIDTH_X16:
- case ICL_DRAM_WIDTH_X32:
- val = REG_FIELD_GET(ICL_DRAM_WIDTH_MASK, val);
- return 8 << val;
+ switch (val & ICL_DIMM_L_WIDTH_MASK) {
+ case ICL_DIMM_L_WIDTH_X8:
+ case ICL_DIMM_L_WIDTH_X16:
+ case ICL_DIMM_L_WIDTH_X32:
+ return 8 << REG_FIELD_GET(ICL_DIMM_L_WIDTH_MASK, val);
default:
MISSING_CASE(val);
return 0;
}
}
-static int icl_get_dimm_ranks(u16 val)
+static int icl_get_dimm_s_ranks(u32 val)
{
- if (icl_get_dimm_size(val) == 0)
+ if (icl_get_dimm_s_size(val) == 0)
return 0;
- val = REG_FIELD_GET(ICL_DRAM_RANK_MASK, val);
+ return REG_FIELD_GET(ICL_DIMM_S_RANK_MASK, val) + 1;
+}
+
+static int icl_get_dimm_l_ranks(u32 val)
+{
+ if (icl_get_dimm_l_size(val) == 0)
+ return 0;
- return val + 1;
+ return REG_FIELD_GET(ICL_DIMM_L_RANK_MASK, val) + 1;
}
static bool
@@ -339,35 +391,59 @@ skl_is_16gb_dimm(const struct dram_dimm_info *dimm)
}
static void
-skl_dram_get_dimm_info(struct drm_i915_private *i915,
- struct dram_dimm_info *dimm,
- int channel, char dimm_name, u16 val)
+skl_dram_print_dimm_info(struct drm_i915_private *i915,
+ struct dram_dimm_info *dimm,
+ int channel, char dimm_name)
{
- if (GRAPHICS_VER(i915) >= 11) {
- dimm->size = icl_get_dimm_size(val);
- dimm->width = icl_get_dimm_width(val);
- dimm->ranks = icl_get_dimm_ranks(val);
- } else {
- dimm->size = skl_get_dimm_size(val);
- dimm->width = skl_get_dimm_width(val);
- dimm->ranks = skl_get_dimm_ranks(val);
- }
-
drm_dbg_kms(&i915->drm,
"CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb+ DIMMs: %s\n",
channel, dimm_name, dimm->size, dimm->width, dimm->ranks,
str_yes_no(skl_is_16gb_dimm(dimm)));
}
+static void
+skl_dram_get_dimm_l_info(struct drm_i915_private *i915,
+ struct dram_dimm_info *dimm,
+ int channel, u32 val)
+{
+ if (GRAPHICS_VER(i915) >= 11) {
+ dimm->size = icl_get_dimm_l_size(val);
+ dimm->width = icl_get_dimm_l_width(val);
+ dimm->ranks = icl_get_dimm_l_ranks(val);
+ } else {
+ dimm->size = skl_get_dimm_l_size(val);
+ dimm->width = skl_get_dimm_l_width(val);
+ dimm->ranks = skl_get_dimm_l_ranks(val);
+ }
+
+ skl_dram_print_dimm_info(i915, dimm, channel, 'L');
+}
+
+static void
+skl_dram_get_dimm_s_info(struct drm_i915_private *i915,
+ struct dram_dimm_info *dimm,
+ int channel, u32 val)
+{
+ if (GRAPHICS_VER(i915) >= 11) {
+ dimm->size = icl_get_dimm_s_size(val);
+ dimm->width = icl_get_dimm_s_width(val);
+ dimm->ranks = icl_get_dimm_s_ranks(val);
+ } else {
+ dimm->size = skl_get_dimm_s_size(val);
+ dimm->width = skl_get_dimm_s_width(val);
+ dimm->ranks = skl_get_dimm_s_ranks(val);
+ }
+
+ skl_dram_print_dimm_info(i915, dimm, channel, 'S');
+}
+
static int
skl_dram_get_channel_info(struct drm_i915_private *i915,
struct dram_channel_info *ch,
int channel, u32 val)
{
- skl_dram_get_dimm_info(i915, &ch->dimm_l,
- channel, 'L', val & 0xffff);
- skl_dram_get_dimm_info(i915, &ch->dimm_s,
- channel, 'S', val >> 16);
+ skl_dram_get_dimm_l_info(i915, &ch->dimm_l, channel, val);
+ skl_dram_get_dimm_s_info(i915, &ch->dimm_s, channel, val);
if (ch->dimm_l.size == 0 && ch->dimm_s.size == 0) {
drm_dbg_kms(&i915->drm, "CH%u not populated\n", channel);
--
2.49.1
next prev parent reply other threads:[~2025-10-29 20:42 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-29 20:42 [PATCH 0/3] drm/1915/dram: Fix DIMM_S decoding on ICL Ville Syrjala
2025-10-29 20:42 ` [PATCH 1/3] drm/i915/dram: Use REG_GENMASK() & co. for the SKL+ DIMM regs Ville Syrjala
2025-11-05 20:45 ` Lucas De Marchi
2025-10-29 20:42 ` [PATCH 2/3] drm/i915/dram: Sort SKL+ DIMM register bits Ville Syrjala
2025-11-05 20:48 ` Lucas De Marchi
2025-10-29 20:42 ` Ville Syrjala [this message]
2025-11-05 22:25 ` [PATCH 3/3] drm/i915/dram: Fix ICL DIMM_S decoding Lucas De Marchi
2025-11-07 13:37 ` Ville Syrjälä
2025-11-19 8:05 ` Jani Nikula
2025-10-30 22:43 ` ✓ i915.CI.BAT: success for drm/1915/dram: Fix DIMM_S decoding on ICL Patchwork
2025-10-31 11:53 ` ✓ i915.CI.Full: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251029204215.12292-4-ville.syrjala@linux.intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox