diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5dd7fc582e6fd9d4975f9ed2f5968d247d27e892..52befc1e0912b17a44553e549a210a005d370a25 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1063,6 +1063,117 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) intel_gvt_sanitize_options(dev_priv); } +static int +bxt_get_dram_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + u32 dram_channels; + u32 mem_freq_khz, val; + u8 num_active_channels; + int i; + + val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0); + mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) * + BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000); + + dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK; + num_active_channels = hweight32(dram_channels); + + /* Each active bit represents 4-byte channel */ + dram_info->bandwidth_kbps = (mem_freq_khz * num_active_channels * 4); + + if (dram_info->bandwidth_kbps == 0) { + DRM_INFO("Couldn't get system memory bandwidth\n"); + return -EINVAL; + } + + /* + * Now read each DUNIT8/9/10/11 to check the rank of each dimms. + */ + for (i = BXT_D_CR_DRP0_DUNIT_START; i <= BXT_D_CR_DRP0_DUNIT_END; i++) { + u8 size, width; + enum dram_rank rank; + u32 tmp; + + val = I915_READ(BXT_D_CR_DRP0_DUNIT(i)); + if (val == 0xFFFFFFFF) + continue; + + dram_info->num_channels++; + tmp = val & BXT_DRAM_RANK_MASK; + + if (tmp == BXT_DRAM_RANK_SINGLE) + rank = I915_DRAM_RANK_SINGLE; + else if (tmp == BXT_DRAM_RANK_DUAL) + rank = I915_DRAM_RANK_DUAL; + else + rank = I915_DRAM_RANK_INVALID; + + tmp = val & BXT_DRAM_SIZE_MASK; + if (tmp == BXT_DRAM_SIZE_4GB) + size = 4; + else if (tmp == BXT_DRAM_SIZE_6GB) + size = 6; + else if (tmp == BXT_DRAM_SIZE_8GB) + size = 8; + else if (tmp == BXT_DRAM_SIZE_12GB) + size = 12; + else if (tmp == BXT_DRAM_SIZE_16GB) + size = 16; + else + size = 0; + + tmp = (val & BXT_DRAM_WIDTH_MASK) >> BXT_DRAM_WIDTH_SHIFT; + width = (1 << tmp) * 8; + DRM_DEBUG_KMS("dram size:%dGB width:X%d rank:%s\n", size, + width, rank == I915_DRAM_RANK_SINGLE ? "single" : + rank == I915_DRAM_RANK_DUAL ? "dual" : "unknown"); + + /* + * If any of the channel is single rank channel, + * worst case output will be same as if single rank + * memory, so consider single rank memory. + */ + if (dram_info->rank == I915_DRAM_RANK_INVALID) + dram_info->rank = rank; + else if (rank == I915_DRAM_RANK_SINGLE) + dram_info->rank = I915_DRAM_RANK_SINGLE; + } + + if (dram_info->rank == I915_DRAM_RANK_INVALID) { + DRM_INFO("couldn't get memory rank information\n"); + return -EINVAL; + } + + dram_info->valid = true; + return 0; +} + +static void +intel_get_dram_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + int ret; + + dram_info->valid = false; + dram_info->rank = I915_DRAM_RANK_INVALID; + dram_info->bandwidth_kbps = 0; + dram_info->num_channels = 0; + + if (!IS_BROXTON(dev_priv)) + return; + + ret = bxt_get_dram_info(dev_priv); + if (ret) + return; + + DRM_DEBUG_KMS("DRAM bandwidth:%d KBps, total-channels: %u\n", + dram_info->bandwidth_kbps, dram_info->num_channels); + DRM_DEBUG_KMS("DRAM rank: %s rank\n", + (dram_info->rank == I915_DRAM_RANK_DUAL) ? + "dual" : "single"); +} + /** * i915_driver_init_hw - setup state requiring device access * @dev_priv: device private @@ -1180,6 +1291,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) goto err_msi; intel_opregion_setup(dev_priv); + /* + * Fill the dram structure to get the system raw bandwidth and + * dram info. This will be used for memory latency calculation. + */ + intel_get_dram_info(dev_priv); + return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5ee283811b57cba9f10e8ccb32302a6f62376fe4..bf88006fa2126e411bd02731398412c22a0fd497 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1945,6 +1945,17 @@ struct drm_i915_private { bool distrust_bios_wm; } wm; + struct dram_info { + bool valid; + u8 num_channels; + enum dram_rank { + I915_DRAM_RANK_INVALID = 0, + I915_DRAM_RANK_SINGLE, + I915_DRAM_RANK_DUAL + } rank; + u32 bandwidth_kbps; + } dram_info; + struct i915_runtime_pm runtime_pm; struct { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c80e56959e21b88a6f9fdb034315eba9fd8efce7..a2bf669c1c341e755dd114da5109ac653924a347 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9583,6 +9583,36 @@ enum skl_power_gate { #define DC_STATE_DEBUG_MASK_CORES (1 << 0) #define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1) +#define BXT_P_CR_MC_BIOS_REQ_0_0_0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114) +#define BXT_REQ_DATA_MASK 0x3F +#define BXT_DRAM_CHANNEL_ACTIVE_SHIFT 12 +#define BXT_DRAM_CHANNEL_ACTIVE_MASK (0xF << 12) +#define BXT_MEMORY_FREQ_MULTIPLIER_HZ 133333333 + +#define BXT_D_CR_DRP0_DUNIT8 0x1000 +#define BXT_D_CR_DRP0_DUNIT9 0x1200 +#define BXT_D_CR_DRP0_DUNIT_START 8 +#define BXT_D_CR_DRP0_DUNIT_END 11 +#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \ + _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\ + BXT_D_CR_DRP0_DUNIT9)) +#define BXT_DRAM_RANK_MASK 0x3 +#define BXT_DRAM_RANK_SINGLE 0x1 +#define BXT_DRAM_RANK_DUAL 0x3 +#define BXT_DRAM_WIDTH_MASK (0x3 << 4) +#define BXT_DRAM_WIDTH_SHIFT 4 +#define BXT_DRAM_WIDTH_X8 (0x0 << 4) +#define BXT_DRAM_WIDTH_X16 (0x1 << 4) +#define BXT_DRAM_WIDTH_X32 (0x2 << 4) +#define BXT_DRAM_WIDTH_X64 (0x3 << 4) +#define BXT_DRAM_SIZE_MASK (0x7 << 6) +#define BXT_DRAM_SIZE_SHIFT 6 +#define BXT_DRAM_SIZE_4GB (0x0 << 6) +#define BXT_DRAM_SIZE_6GB (0x1 << 6) +#define BXT_DRAM_SIZE_8GB (0x2 << 6) +#define BXT_DRAM_SIZE_12GB (0x3 << 6) +#define BXT_DRAM_SIZE_16GB (0x4 << 6) + /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, * since on HSW we can't write to it using I915_WRITE. */ #define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)