diff options
Diffstat (limited to 'drivers/gpu/drm/i915/soc/intel_dram.c')
-rw-r--r-- | drivers/gpu/drm/i915/soc/intel_dram.c | 173 |
1 files changed, 103 insertions, 70 deletions
diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c index eee5c4f45a43..edffaed8f9a7 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.c +++ b/drivers/gpu/drm/i915/soc/intel_dram.c @@ -5,12 +5,18 @@ #include <linux/string_helpers.h> +#include <drm/drm_managed.h> + +#include "../display/intel_display_core.h" /* FIXME */ + #include "i915_drv.h" #include "i915_reg.h" +#include "i915_utils.h" #include "intel_dram.h" #include "intel_mchbar_regs.h" #include "intel_pcode.h" -#include "vlv_sideband.h" +#include "intel_uncore.h" +#include "vlv_iosf_sb.h" struct dram_dimm_info { u16 size; @@ -25,10 +31,11 @@ struct dram_channel_info { #define DRAM_TYPE_STR(type) [INTEL_DRAM_ ## type] = #type -static const char *intel_dram_type_str(enum intel_dram_type type) +const char *intel_dram_type_str(enum intel_dram_type type) { static const char * const str[] = { DRAM_TYPE_STR(UNKNOWN), + DRAM_TYPE_STR(DDR2), DRAM_TYPE_STR(DDR3), DRAM_TYPE_STR(DDR4), DRAM_TYPE_STR(LPDDR3), @@ -49,9 +56,10 @@ static const char *intel_dram_type_str(enum intel_dram_type type) #undef DRAM_TYPE_STR -static bool pnv_is_ddr3(struct drm_i915_private *i915) +static enum intel_dram_type pnv_dram_type(struct drm_i915_private *i915) { - return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3; + return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ? + INTEL_DRAM_DDR3 : INTEL_DRAM_DDR2; } static unsigned int pnv_mem_freq(struct drm_i915_private *dev_priv) @@ -97,9 +105,9 @@ static unsigned int chv_mem_freq(struct drm_i915_private *i915) { u32 val; - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_CCK)); - val = vlv_cck_read(i915, CCK_FUSE_REG); - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_CCK)); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_CCK)); + val = vlv_iosf_sb_read(&i915->drm, VLV_IOSF_SB_CCK, CCK_FUSE_REG); + vlv_iosf_sb_put(&i915->drm, BIT(VLV_IOSF_SB_CCK)); switch ((val >> 2) & 0x7) { case 3: @@ -113,9 +121,9 @@ static unsigned int vlv_mem_freq(struct drm_i915_private *i915) { u32 val; - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_PUNIT)); - val = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_PUNIT)); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT)); + val = vlv_iosf_sb_read(&i915->drm, VLV_IOSF_SB_PUNIT, PUNIT_REG_GPU_FREQ_STS); + vlv_iosf_sb_put(&i915->drm, BIT(VLV_IOSF_SB_PUNIT)); switch ((val >> 6) & 3) { case 0: @@ -130,25 +138,21 @@ static unsigned int vlv_mem_freq(struct drm_i915_private *i915) return 0; } -static void detect_mem_freq(struct drm_i915_private *i915) +unsigned int intel_mem_freq(struct drm_i915_private *i915) { if (IS_PINEVIEW(i915)) - i915->mem_freq = pnv_mem_freq(i915); + return pnv_mem_freq(i915); else if (GRAPHICS_VER(i915) == 5) - i915->mem_freq = ilk_mem_freq(i915); + return ilk_mem_freq(i915); else if (IS_CHERRYVIEW(i915)) - i915->mem_freq = chv_mem_freq(i915); + return chv_mem_freq(i915); else if (IS_VALLEYVIEW(i915)) - i915->mem_freq = vlv_mem_freq(i915); - - if (IS_PINEVIEW(i915)) - i915->is_ddr3 = pnv_is_ddr3(i915); - - if (i915->mem_freq) - drm_dbg(&i915->drm, "DDR speed: %d kHz\n", i915->mem_freq); + return vlv_mem_freq(i915); + else + return 0; } -unsigned int i9xx_fsb_freq(struct drm_i915_private *i915) +static unsigned int i9xx_fsb_freq(struct drm_i915_private *i915) { u32 fsb; @@ -230,15 +234,30 @@ static unsigned int ilk_fsb_freq(struct drm_i915_private *dev_priv) } } -static void detect_fsb_freq(struct drm_i915_private *i915) +unsigned int intel_fsb_freq(struct drm_i915_private *i915) { if (GRAPHICS_VER(i915) == 5) - i915->fsb_freq = ilk_fsb_freq(i915); + return ilk_fsb_freq(i915); else if (GRAPHICS_VER(i915) == 3 || GRAPHICS_VER(i915) == 4) - i915->fsb_freq = i9xx_fsb_freq(i915); + return i9xx_fsb_freq(i915); + else + return 0; +} + +static int i915_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) +{ + dram_info->fsb_freq = intel_fsb_freq(i915); + if (dram_info->fsb_freq) + drm_dbg(&i915->drm, "FSB frequency: %d kHz\n", dram_info->fsb_freq); - if (i915->fsb_freq) - drm_dbg(&i915->drm, "FSB frequency: %d kHz\n", i915->fsb_freq); + dram_info->mem_freq = intel_mem_freq(i915); + if (dram_info->mem_freq) + drm_dbg(&i915->drm, "DDR speed: %d kHz\n", dram_info->mem_freq); + + if (IS_PINEVIEW(i915)) + dram_info->type = pnv_dram_type(i915); + + return 0; } static int intel_dimm_num_devices(const struct dram_dimm_info *dimm) @@ -381,13 +400,15 @@ intel_is_dram_symmetric(const struct dram_channel_info *ch0, } static int -skl_dram_get_channels_info(struct drm_i915_private *i915) +skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - struct dram_info *dram_info = &i915->dram_info; struct dram_channel_info ch0 = {}, ch1 = {}; u32 val; int ret; + /* Assume 16Gb DIMMs are present until proven otherwise */ + dram_info->has_16gb_dimms = true; + val = intel_uncore_read(&i915->uncore, SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); ret = skl_dram_get_channel_info(i915, &ch0, 0, val); @@ -410,13 +431,16 @@ skl_dram_get_channels_info(struct drm_i915_private *i915) return -EINVAL; } - dram_info->wm_lv_0_adjust_needed = ch0.is_16gb_dimm || ch1.is_16gb_dimm; + dram_info->has_16gb_dimms = ch0.is_16gb_dimm || ch1.is_16gb_dimm; dram_info->symmetric_memory = intel_is_dram_symmetric(&ch0, &ch1); drm_dbg_kms(&i915->drm, "Memory configuration is symmetric? %s\n", str_yes_no(dram_info->symmetric_memory)); + drm_dbg_kms(&i915->drm, "16Gb DIMMs: %s\n", + str_yes_no(dram_info->has_16gb_dimms)); + return 0; } @@ -444,14 +468,13 @@ skl_get_dram_type(struct drm_i915_private *i915) } static int -skl_get_dram_info(struct drm_i915_private *i915) +skl_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - struct dram_info *dram_info = &i915->dram_info; int ret; dram_info->type = skl_get_dram_type(i915); - ret = skl_dram_get_channels_info(i915); + ret = skl_dram_get_channels_info(i915, dram_info); if (ret) return ret; @@ -536,9 +559,8 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val) dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm); } -static int bxt_get_dram_info(struct drm_i915_private *i915) +static int bxt_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - struct dram_info *dram_info = &i915->dram_info; u32 val; u8 valid_ranks = 0; int i; @@ -583,14 +605,14 @@ static int bxt_get_dram_info(struct drm_i915_private *i915) return 0; } -static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv) +static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv, + struct dram_info *dram_info) { - struct dram_info *dram_info = &dev_priv->dram_info; u32 val = 0; int ret; - ret = snb_pcode_read(&dev_priv->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | - ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, &val, NULL); + ret = intel_pcode_read(&dev_priv->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO | + ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, &val, NULL); if (ret) return ret; @@ -645,27 +667,25 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv) return 0; } -static int gen11_get_dram_info(struct drm_i915_private *i915) +static int gen11_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - int ret = skl_get_dram_info(i915); + int ret; + ret = skl_dram_get_channels_info(i915, dram_info); if (ret) return ret; - return icl_pcode_read_mem_global_info(i915); + return icl_pcode_read_mem_global_info(i915, dram_info); } -static int gen12_get_dram_info(struct drm_i915_private *i915) +static int gen12_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { - i915->dram_info.wm_lv_0_adjust_needed = false; - - return icl_pcode_read_mem_global_info(i915); + return icl_pcode_read_mem_global_info(i915, dram_info); } -static int xelpdp_get_dram_info(struct drm_i915_private *i915) +static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { u32 val = intel_uncore_read(&i915->uncore, MTL_MEM_SS_INFO_GLOBAL); - struct dram_info *dram_info = &i915->dram_info; switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) { case 0: @@ -706,46 +726,59 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915) return 0; } -void intel_dram_detect(struct drm_i915_private *i915) +int intel_dram_detect(struct drm_i915_private *i915) { - struct dram_info *dram_info = &i915->dram_info; + struct intel_display *display = i915->display; + struct dram_info *dram_info; int ret; - detect_fsb_freq(i915); - detect_mem_freq(i915); + if (IS_DG2(i915) || !intel_display_device_present(display)) + return 0; - if (GRAPHICS_VER(i915) < 9 || IS_DG2(i915) || !HAS_DISPLAY(i915)) - return; + dram_info = drmm_kzalloc(&i915->drm, sizeof(*dram_info), GFP_KERNEL); + if (!dram_info) + return -ENOMEM; - /* - * Assume level 0 watermark latency adjustment is needed until proven - * otherwise, this w/a is not needed by bxt/glk. - */ - dram_info->wm_lv_0_adjust_needed = !IS_BROXTON(i915) && !IS_GEMINILAKE(i915); + i915->dram_info = dram_info; - if (DISPLAY_VER(i915) >= 14) - ret = xelpdp_get_dram_info(i915); + if (DISPLAY_VER(display) >= 14) + ret = xelpdp_get_dram_info(i915, dram_info); else if (GRAPHICS_VER(i915) >= 12) - ret = gen12_get_dram_info(i915); + ret = gen12_get_dram_info(i915, dram_info); else if (GRAPHICS_VER(i915) >= 11) - ret = gen11_get_dram_info(i915); + ret = gen11_get_dram_info(i915, dram_info); else if (IS_BROXTON(i915) || IS_GEMINILAKE(i915)) - ret = bxt_get_dram_info(i915); + ret = bxt_get_dram_info(i915, dram_info); + else if (GRAPHICS_VER(i915) >= 9) + ret = skl_get_dram_info(i915, dram_info); else - ret = skl_get_dram_info(i915); + ret = i915_get_dram_info(i915, dram_info); drm_dbg_kms(&i915->drm, "DRAM type: %s\n", intel_dram_type_str(dram_info->type)); + drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels); + + drm_dbg_kms(&i915->drm, "Num QGV points %u\n", dram_info->num_qgv_points); + drm_dbg_kms(&i915->drm, "Num PSF GV points %u\n", dram_info->num_psf_gv_points); + + /* TODO: Do we want to abort probe on dram detection failures? */ if (ret) - return; + return 0; - drm_dbg_kms(&i915->drm, "Num qgv points %u\n", dram_info->num_qgv_points); + return 0; +} - drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels); +/* + * Returns NULL for platforms that don't have dram info. Avoid overzealous NULL + * checks, and prefer not dereferencing on platforms that shouldn't look at dram + * info, to catch accidental and incorrect dram info checks. + */ +const struct dram_info *intel_dram_info(struct drm_device *drm) +{ + struct drm_i915_private *i915 = to_i915(drm); - drm_dbg_kms(&i915->drm, "Watermark level 0 adjustment needed: %s\n", - str_yes_no(dram_info->wm_lv_0_adjust_needed)); + return i915->dram_info; } static u32 gen9_edram_size_mb(struct drm_i915_private *i915, u32 cap) |