mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
drm/i915/dram: Fix ICL DIMM_S decoding
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> Link: https://patch.msgid.link/20251029204215.12292-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com>
This commit is contained in:
parent
8c171a9b8c
commit
7e2d785354
2 changed files with 155 additions and 64 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -267,69 +267,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_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_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_ranks(u16 val)
|
||||
static int skl_get_dimm_l_width(u32 val)
|
||||
{
|
||||
if (skl_get_dimm_size(val) == 0)
|
||||
if (skl_get_dimm_l_size(val) == 0)
|
||||
return 0;
|
||||
|
||||
val = REG_FIELD_GET(SKL_DRAM_RANK_MASK, 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;
|
||||
}
|
||||
}
|
||||
|
||||
return val + 1;
|
||||
static int skl_get_dimm_s_ranks(u32 val)
|
||||
{
|
||||
if (skl_get_dimm_s_size(val) == 0)
|
||||
return 0;
|
||||
|
||||
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 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_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_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_ranks(u16 val)
|
||||
static int icl_get_dimm_l_width(u32 val)
|
||||
{
|
||||
if (icl_get_dimm_size(val) == 0)
|
||||
if (icl_get_dimm_l_size(val) == 0)
|
||||
return 0;
|
||||
|
||||
val = REG_FIELD_GET(ICL_DRAM_RANK_MASK, 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;
|
||||
}
|
||||
}
|
||||
|
||||
return val + 1;
|
||||
static int icl_get_dimm_s_ranks(u32 val)
|
||||
{
|
||||
if (icl_get_dimm_s_size(val) == 0)
|
||||
return 0;
|
||||
|
||||
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 REG_FIELD_GET(ICL_DIMM_L_RANK_MASK, val) + 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -340,35 +392,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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue