From: Ville Syrjälä <[email protected]>

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ä <[email protected]>
---
 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

Reply via email to