diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2ddf8538cb47..44e2c0f5ec50 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -1063,6 +1063,300 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) | |||
1063 | intel_gvt_sanitize_options(dev_priv); | 1063 | intel_gvt_sanitize_options(dev_priv); |
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | static enum dram_rank skl_get_dimm_rank(u8 size, u32 rank) | ||
1067 | { | ||
1068 | if (size == 0) | ||
1069 | return I915_DRAM_RANK_INVALID; | ||
1070 | if (rank == SKL_DRAM_RANK_SINGLE) | ||
1071 | return I915_DRAM_RANK_SINGLE; | ||
1072 | else if (rank == SKL_DRAM_RANK_DUAL) | ||
1073 | return I915_DRAM_RANK_DUAL; | ||
1074 | |||
1075 | return I915_DRAM_RANK_INVALID; | ||
1076 | } | ||
1077 | |||
1078 | static bool | ||
1079 | skl_is_16gb_dimm(enum dram_rank rank, u8 size, u8 width) | ||
1080 | { | ||
1081 | if (rank == I915_DRAM_RANK_SINGLE && width == 8 && size == 16) | ||
1082 | return true; | ||
1083 | else if (rank == I915_DRAM_RANK_DUAL && width == 8 && size == 32) | ||
1084 | return true; | ||
1085 | else if (rank == SKL_DRAM_RANK_SINGLE && width == 16 && size == 8) | ||
1086 | return true; | ||
1087 | else if (rank == SKL_DRAM_RANK_DUAL && width == 16 && size == 16) | ||
1088 | return true; | ||
1089 | |||
1090 | return false; | ||
1091 | } | ||
1092 | |||
1093 | static int | ||
1094 | skl_dram_get_channel_info(struct dram_channel_info *ch, u32 val) | ||
1095 | { | ||
1096 | u32 tmp_l, tmp_s; | ||
1097 | u32 s_val = val >> SKL_DRAM_S_SHIFT; | ||
1098 | |||
1099 | if (!val) | ||
1100 | return -EINVAL; | ||
1101 | |||
1102 | tmp_l = val & SKL_DRAM_SIZE_MASK; | ||
1103 | tmp_s = s_val & SKL_DRAM_SIZE_MASK; | ||
1104 | |||
1105 | if (tmp_l == 0 && tmp_s == 0) | ||
1106 | return -EINVAL; | ||
1107 | |||
1108 | ch->l_info.size = tmp_l; | ||
1109 | ch->s_info.size = tmp_s; | ||
1110 | |||
1111 | tmp_l = (val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT; | ||
1112 | tmp_s = (s_val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT; | ||
1113 | ch->l_info.width = (1 << tmp_l) * 8; | ||
1114 | ch->s_info.width = (1 << tmp_s) * 8; | ||
1115 | |||
1116 | tmp_l = val & SKL_DRAM_RANK_MASK; | ||
1117 | tmp_s = s_val & SKL_DRAM_RANK_MASK; | ||
1118 | ch->l_info.rank = skl_get_dimm_rank(ch->l_info.size, tmp_l); | ||
1119 | ch->s_info.rank = skl_get_dimm_rank(ch->s_info.size, tmp_s); | ||
1120 | |||
1121 | if (ch->l_info.rank == I915_DRAM_RANK_DUAL || | ||
1122 | ch->s_info.rank == I915_DRAM_RANK_DUAL) | ||
1123 | ch->rank = I915_DRAM_RANK_DUAL; | ||
1124 | else if (ch->l_info.rank == I915_DRAM_RANK_SINGLE && | ||
1125 | ch->s_info.rank == I915_DRAM_RANK_SINGLE) | ||
1126 | ch->rank = I915_DRAM_RANK_DUAL; | ||
1127 | else | ||
1128 | ch->rank = I915_DRAM_RANK_SINGLE; | ||
1129 | |||
1130 | ch->is_16gb_dimm = skl_is_16gb_dimm(ch->l_info.rank, ch->l_info.size, | ||
1131 | ch->l_info.width) || | ||
1132 | skl_is_16gb_dimm(ch->s_info.rank, ch->s_info.size, | ||
1133 | ch->s_info.width); | ||
1134 | |||
1135 | DRM_DEBUG_KMS("(size:width:rank) L(%dGB:X%d:%s) S(%dGB:X%d:%s)\n", | ||
1136 | ch->l_info.size, ch->l_info.width, | ||
1137 | ch->l_info.rank ? "dual" : "single", | ||
1138 | ch->s_info.size, ch->s_info.width, | ||
1139 | ch->s_info.rank ? "dual" : "single"); | ||
1140 | |||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | static bool | ||
1145 | intel_is_dram_symmetric(u32 val_ch0, u32 val_ch1, | ||
1146 | struct dram_channel_info *ch0) | ||
1147 | { | ||
1148 | return (val_ch0 == val_ch1 && | ||
1149 | (ch0->s_info.size == 0 || | ||
1150 | (ch0->l_info.size == ch0->s_info.size && | ||
1151 | ch0->l_info.width == ch0->s_info.width && | ||
1152 | ch0->l_info.rank == ch0->s_info.rank))); | ||
1153 | } | ||
1154 | |||
1155 | static int | ||
1156 | skl_dram_get_channels_info(struct drm_i915_private *dev_priv) | ||
1157 | { | ||
1158 | struct dram_info *dram_info = &dev_priv->dram_info; | ||
1159 | struct dram_channel_info ch0, ch1; | ||
1160 | u32 val_ch0, val_ch1; | ||
1161 | int ret; | ||
1162 | |||
1163 | val_ch0 = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); | ||
1164 | ret = skl_dram_get_channel_info(&ch0, val_ch0); | ||
1165 | if (ret == 0) | ||
1166 | dram_info->num_channels++; | ||
1167 | |||
1168 | val_ch1 = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN); | ||
1169 | ret = skl_dram_get_channel_info(&ch1, val_ch1); | ||
1170 | if (ret == 0) | ||
1171 | dram_info->num_channels++; | ||
1172 | |||
1173 | if (dram_info->num_channels == 0) { | ||
1174 | DRM_INFO("Number of memory channels is zero\n"); | ||
1175 | return -EINVAL; | ||
1176 | } | ||
1177 | |||
1178 | dram_info->valid_dimm = true; | ||
1179 | |||
1180 | /* | ||
1181 | * If any of the channel is single rank channel, worst case output | ||
1182 | * will be same as if single rank memory, so consider single rank | ||
1183 | * memory. | ||
1184 | */ | ||
1185 | if (ch0.rank == I915_DRAM_RANK_SINGLE || | ||
1186 | ch1.rank == I915_DRAM_RANK_SINGLE) | ||
1187 | dram_info->rank = I915_DRAM_RANK_SINGLE; | ||
1188 | else | ||
1189 | dram_info->rank = max(ch0.rank, ch1.rank); | ||
1190 | |||
1191 | if (dram_info->rank == I915_DRAM_RANK_INVALID) { | ||
1192 | DRM_INFO("couldn't get memory rank information\n"); | ||
1193 | return -EINVAL; | ||
1194 | } | ||
1195 | |||
1196 | if (ch0.is_16gb_dimm || ch1.is_16gb_dimm) | ||
1197 | dram_info->is_16gb_dimm = true; | ||
1198 | |||
1199 | dev_priv->dram_info.symmetric_memory = intel_is_dram_symmetric(val_ch0, | ||
1200 | val_ch1, | ||
1201 | &ch0); | ||
1202 | |||
1203 | DRM_DEBUG_KMS("memory configuration is %sSymmetric memory\n", | ||
1204 | dev_priv->dram_info.symmetric_memory ? "" : "not "); | ||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static int | ||
1209 | skl_get_dram_info(struct drm_i915_private *dev_priv) | ||
1210 | { | ||
1211 | struct dram_info *dram_info = &dev_priv->dram_info; | ||
1212 | u32 mem_freq_khz, val; | ||
1213 | int ret; | ||
1214 | |||
1215 | ret = skl_dram_get_channels_info(dev_priv); | ||
1216 | if (ret) | ||
1217 | return ret; | ||
1218 | |||
1219 | val = I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); | ||
1220 | mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) * | ||
1221 | SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000); | ||
1222 | |||
1223 | dram_info->bandwidth_kbps = dram_info->num_channels * | ||
1224 | mem_freq_khz * 8; | ||
1225 | |||
1226 | if (dram_info->bandwidth_kbps == 0) { | ||
1227 | DRM_INFO("Couldn't get system memory bandwidth\n"); | ||
1228 | return -EINVAL; | ||
1229 | } | ||
1230 | |||
1231 | dram_info->valid = true; | ||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | static int | ||
1236 | bxt_get_dram_info(struct drm_i915_private *dev_priv) | ||
1237 | { | ||
1238 | struct dram_info *dram_info = &dev_priv->dram_info; | ||
1239 | u32 dram_channels; | ||
1240 | u32 mem_freq_khz, val; | ||
1241 | u8 num_active_channels; | ||
1242 | int i; | ||
1243 | |||
1244 | val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0); | ||
1245 | mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) * | ||
1246 | BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000); | ||
1247 | |||
1248 | dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK; | ||
1249 | num_active_channels = hweight32(dram_channels); | ||
1250 | |||
1251 | /* Each active bit represents 4-byte channel */ | ||
1252 | dram_info->bandwidth_kbps = (mem_freq_khz * num_active_channels * 4); | ||
1253 | |||
1254 | if (dram_info->bandwidth_kbps == 0) { | ||
1255 | DRM_INFO("Couldn't get system memory bandwidth\n"); | ||
1256 | return -EINVAL; | ||
1257 | } | ||
1258 | |||
1259 | /* | ||
1260 | * Now read each DUNIT8/9/10/11 to check the rank of each dimms. | ||
1261 | */ | ||
1262 | for (i = BXT_D_CR_DRP0_DUNIT_START; i <= BXT_D_CR_DRP0_DUNIT_END; i++) { | ||
1263 | u8 size, width; | ||
1264 | enum dram_rank rank; | ||
1265 | u32 tmp; | ||
1266 | |||
1267 | val = I915_READ(BXT_D_CR_DRP0_DUNIT(i)); | ||
1268 | if (val == 0xFFFFFFFF) | ||
1269 | continue; | ||
1270 | |||
1271 | dram_info->num_channels++; | ||
1272 | tmp = val & BXT_DRAM_RANK_MASK; | ||
1273 | |||
1274 | if (tmp == BXT_DRAM_RANK_SINGLE) | ||
1275 | rank = I915_DRAM_RANK_SINGLE; | ||
1276 | else if (tmp == BXT_DRAM_RANK_DUAL) | ||
1277 | rank = I915_DRAM_RANK_DUAL; | ||
1278 | else | ||
1279 | rank = I915_DRAM_RANK_INVALID; | ||
1280 | |||
1281 | tmp = val & BXT_DRAM_SIZE_MASK; | ||
1282 | if (tmp == BXT_DRAM_SIZE_4GB) | ||
1283 | size = 4; | ||
1284 | else if (tmp == BXT_DRAM_SIZE_6GB) | ||
1285 | size = 6; | ||
1286 | else if (tmp == BXT_DRAM_SIZE_8GB) | ||
1287 | size = 8; | ||
1288 | else if (tmp == BXT_DRAM_SIZE_12GB) | ||
1289 | size = 12; | ||
1290 | else if (tmp == BXT_DRAM_SIZE_16GB) | ||
1291 | size = 16; | ||
1292 | else | ||
1293 | size = 0; | ||
1294 | |||
1295 | tmp = (val & BXT_DRAM_WIDTH_MASK) >> BXT_DRAM_WIDTH_SHIFT; | ||
1296 | width = (1 << tmp) * 8; | ||
1297 | DRM_DEBUG_KMS("dram size:%dGB width:X%d rank:%s\n", size, | ||
1298 | width, rank == I915_DRAM_RANK_SINGLE ? "single" : | ||
1299 | rank == I915_DRAM_RANK_DUAL ? "dual" : "unknown"); | ||
1300 | |||
1301 | /* | ||
1302 | * If any of the channel is single rank channel, | ||
1303 | * worst case output will be same as if single rank | ||
1304 | * memory, so consider single rank memory. | ||
1305 | */ | ||
1306 | if (dram_info->rank == I915_DRAM_RANK_INVALID) | ||
1307 | dram_info->rank = rank; | ||
1308 | else if (rank == I915_DRAM_RANK_SINGLE) | ||
1309 | dram_info->rank = I915_DRAM_RANK_SINGLE; | ||
1310 | } | ||
1311 | |||
1312 | if (dram_info->rank == I915_DRAM_RANK_INVALID) { | ||
1313 | DRM_INFO("couldn't get memory rank information\n"); | ||
1314 | return -EINVAL; | ||
1315 | } | ||
1316 | |||
1317 | dram_info->valid_dimm = true; | ||
1318 | dram_info->valid = true; | ||
1319 | return 0; | ||
1320 | } | ||
1321 | |||
1322 | static void | ||
1323 | intel_get_dram_info(struct drm_i915_private *dev_priv) | ||
1324 | { | ||
1325 | struct dram_info *dram_info = &dev_priv->dram_info; | ||
1326 | char bandwidth_str[32]; | ||
1327 | int ret; | ||
1328 | |||
1329 | dram_info->valid = false; | ||
1330 | dram_info->valid_dimm = false; | ||
1331 | dram_info->is_16gb_dimm = false; | ||
1332 | dram_info->rank = I915_DRAM_RANK_INVALID; | ||
1333 | dram_info->bandwidth_kbps = 0; | ||
1334 | dram_info->num_channels = 0; | ||
1335 | |||
1336 | if (INTEL_GEN(dev_priv) < 9 || IS_GEMINILAKE(dev_priv)) | ||
1337 | return; | ||
1338 | |||
1339 | /* Need to calculate bandwidth only for Gen9 */ | ||
1340 | if (IS_BROXTON(dev_priv)) | ||
1341 | ret = bxt_get_dram_info(dev_priv); | ||
1342 | else if (INTEL_GEN(dev_priv) == 9) | ||
1343 | ret = skl_get_dram_info(dev_priv); | ||
1344 | else | ||
1345 | ret = skl_dram_get_channels_info(dev_priv); | ||
1346 | if (ret) | ||
1347 | return; | ||
1348 | |||
1349 | if (dram_info->bandwidth_kbps) | ||
1350 | sprintf(bandwidth_str, "%d KBps", dram_info->bandwidth_kbps); | ||
1351 | else | ||
1352 | sprintf(bandwidth_str, "unknown"); | ||
1353 | DRM_DEBUG_KMS("DRAM bandwidth:%s, total-channels: %u\n", | ||
1354 | bandwidth_str, dram_info->num_channels); | ||
1355 | DRM_DEBUG_KMS("DRAM rank: %s rank 16GB-dimm:%s\n", | ||
1356 | (dram_info->rank == I915_DRAM_RANK_DUAL) ? | ||
1357 | "dual" : "single", yesno(dram_info->is_16gb_dimm)); | ||
1358 | } | ||
1359 | |||
1066 | /** | 1360 | /** |
1067 | * i915_driver_init_hw - setup state requiring device access | 1361 | * i915_driver_init_hw - setup state requiring device access |
1068 | * @dev_priv: device private | 1362 | * @dev_priv: device private |
@@ -1180,6 +1474,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) | |||
1180 | goto err_msi; | 1474 | goto err_msi; |
1181 | 1475 | ||
1182 | intel_opregion_setup(dev_priv); | 1476 | intel_opregion_setup(dev_priv); |
1477 | /* | ||
1478 | * Fill the dram structure to get the system raw bandwidth and | ||
1479 | * dram info. This will be used for memory latency calculation. | ||
1480 | */ | ||
1481 | intel_get_dram_info(dev_priv); | ||
1482 | |||
1183 | 1483 | ||
1184 | return 0; | 1484 | return 0; |
1185 | 1485 | ||