Rev 6660 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 6660 | Rev 6937 | ||
---|---|---|---|
Line 22... | Line 22... | ||
22 | * |
22 | * |
23 | * Authors: |
23 | * Authors: |
24 | * Eric Anholt |
24 | * Eric Anholt |
25 | * |
25 | * |
26 | */ |
26 | */ |
27 | #include |
- | |
- | 27 | ||
28 | #include |
28 | #include |
29 | #include |
29 | #include |
30 | #include |
30 | #include |
31 | #include "i915_drv.h" |
31 | #include "i915_drv.h" |
32 | #include "intel_bios.h" |
32 | #include "intel_bios.h" |
Line 330... | Line 330... | ||
330 | 330 | ||
331 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
331 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
332 | drm_mode_debug_printmodeline(panel_fixed_mode); |
332 | drm_mode_debug_printmodeline(panel_fixed_mode); |
Line 333... | Line 333... | ||
333 | } |
333 | } |
334 | 334 | ||
335 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
335 | static int intel_bios_ssc_frequency(struct drm_i915_private *dev_priv, |
336 | bool alternate) |
336 | bool alternate) |
337 | { |
337 | { |
338 | switch (INTEL_INFO(dev)->gen) { |
338 | switch (INTEL_INFO(dev_priv)->gen) { |
339 | case 2: |
339 | case 2: |
340 | return alternate ? 66667 : 48000; |
340 | return alternate ? 66667 : 48000; |
341 | case 3: |
341 | case 3: |
Line 348... | Line 348... | ||
348 | 348 | ||
349 | static void |
349 | static void |
350 | parse_general_features(struct drm_i915_private *dev_priv, |
350 | parse_general_features(struct drm_i915_private *dev_priv, |
351 | const struct bdb_header *bdb) |
351 | const struct bdb_header *bdb) |
352 | { |
- | |
353 | struct drm_device *dev = dev_priv->dev; |
352 | { |
Line 354... | Line 353... | ||
354 | const struct bdb_general_features *general; |
353 | const struct bdb_general_features *general; |
355 | 354 | ||
- | 355 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
|
- | 356 | if (!general) |
|
356 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
357 | return; |
- | 358 | ||
- | 359 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
|
- | 360 | /* int_crt_support can't be trusted on earlier platforms */ |
|
357 | if (general) { |
361 | if (bdb->version >= 155 && |
358 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
362 | (HAS_DDI(dev_priv) || IS_VALLEYVIEW(dev_priv))) |
359 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
363 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
360 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
364 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
361 | dev_priv->vbt.lvds_ssc_freq = |
365 | dev_priv->vbt.lvds_ssc_freq = |
362 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
366 | intel_bios_ssc_frequency(dev_priv, general->ssc_freq); |
363 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
367 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
364 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
368 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
365 | DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", |
369 | DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", |
366 | dev_priv->vbt.int_tv_support, |
370 | dev_priv->vbt.int_tv_support, |
367 | dev_priv->vbt.int_crt_support, |
371 | dev_priv->vbt.int_crt_support, |
368 | dev_priv->vbt.lvds_use_ssc, |
372 | dev_priv->vbt.lvds_use_ssc, |
369 | dev_priv->vbt.lvds_ssc_freq, |
373 | dev_priv->vbt.lvds_ssc_freq, |
370 | dev_priv->vbt.display_clock_mode, |
374 | dev_priv->vbt.display_clock_mode, |
371 | dev_priv->vbt.fdi_rx_polarity_inverted); |
- | |
Line 372... | Line 375... | ||
372 | } |
375 | dev_priv->vbt.fdi_rx_polarity_inverted); |
373 | } |
376 | } |
374 | 377 | ||
375 | static void |
378 | static void |
Line 1052... | Line 1055... | ||
1052 | } |
1055 | } |
Line 1053... | Line 1056... | ||
1053 | 1056 | ||
1054 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
1057 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
1055 | const struct bdb_header *bdb) |
1058 | const struct bdb_header *bdb) |
1056 | { |
- | |
1057 | struct drm_device *dev = dev_priv->dev; |
1059 | { |
Line 1058... | Line 1060... | ||
1058 | enum port port; |
1060 | enum port port; |
1059 | 1061 | ||
Line 1060... | Line 1062... | ||
1060 | if (!HAS_DDI(dev)) |
1062 | if (!HAS_DDI(dev_priv)) |
1061 | return; |
1063 | return; |
Line 1168... | Line 1170... | ||
1168 | } |
1170 | } |
Line 1169... | Line 1171... | ||
1169 | 1171 | ||
1170 | static void |
1172 | static void |
1171 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
1173 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
1172 | { |
- | |
1173 | struct drm_device *dev = dev_priv->dev; |
1174 | { |
Line 1174... | Line 1175... | ||
1174 | enum port port; |
1175 | enum port port; |
Line 1175... | Line 1176... | ||
1175 | 1176 | ||
Line 1193... | Line 1194... | ||
1193 | dev_priv->vbt.lvds_use_ssc = 1; |
1194 | dev_priv->vbt.lvds_use_ssc = 1; |
1194 | /* |
1195 | /* |
1195 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
1196 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
1196 | * clock for LVDS. |
1197 | * clock for LVDS. |
1197 | */ |
1198 | */ |
1198 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, |
1199 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev_priv, |
1199 | !HAS_PCH_SPLIT(dev)); |
1200 | !HAS_PCH_SPLIT(dev_priv)); |
1200 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
1201 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
Line 1201... | Line 1202... | ||
1201 | 1202 | ||
1202 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
1203 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
1203 | struct ddi_vbt_port_info *info = |
1204 | struct ddi_vbt_port_info *info = |
Line 1209... | Line 1210... | ||
1209 | info->supports_hdmi = info->supports_dvi; |
1210 | info->supports_hdmi = info->supports_dvi; |
1210 | info->supports_dp = (port != PORT_E); |
1211 | info->supports_dp = (port != PORT_E); |
1211 | } |
1212 | } |
1212 | } |
1213 | } |
Line 1213... | Line 1214... | ||
1213 | 1214 | ||
1214 | static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id) |
1215 | static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt) |
1215 | { |
- | |
1216 | DRM_DEBUG_KMS("Falling back to manually reading VBT from " |
- | |
1217 | "VBIOS ROM for %s\n", |
1216 | { |
1218 | id->ident); |
- | |
1219 | return 1; |
- | |
1220 | } |
- | |
1221 | - | ||
1222 | static const struct dmi_system_id intel_no_opregion_vbt[] = { |
- | |
1223 | { |
- | |
1224 | .callback = intel_no_opregion_vbt_callback, |
- | |
1225 | .ident = "ThinkCentre A57", |
- | |
1226 | .matches = { |
- | |
1227 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
- | |
1228 | DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), |
- | |
1229 | }, |
- | |
1230 | }, |
- | |
1231 | { } |
- | |
Line -... | Line 1217... | ||
- | 1217 | const void *_vbt = vbt; |
|
- | 1218 | ||
- | 1219 | return _vbt + vbt->bdb_offset; |
|
- | 1220 | } |
|
1232 | }; |
1221 | |
- | 1222 | /** |
|
1233 | 1223 | * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT |
|
- | 1224 | * @buf: pointer to a buffer to validate |
|
1234 | static const struct bdb_header *validate_vbt(const void *base, |
1225 | * @size: size of the buffer |
- | 1226 | * |
|
1235 | size_t size, |
1227 | * Returns true on valid VBT. |
1236 | const void *_vbt, |
1228 | */ |
1237 | const char *source) |
- | |
1238 | { |
1229 | bool intel_bios_is_valid_vbt(const void *buf, size_t size) |
1239 | size_t offset = _vbt - base; |
1230 | { |
Line -... | Line 1231... | ||
- | 1231 | const struct vbt_header *vbt = buf; |
|
- | 1232 | const struct bdb_header *bdb; |
|
- | 1233 | ||
1240 | const struct vbt_header *vbt = _vbt; |
1234 | if (!vbt) |
1241 | const struct bdb_header *bdb; |
1235 | return false; |
1242 | 1236 | ||
1243 | if (offset + sizeof(struct vbt_header) > size) { |
1237 | if (sizeof(struct vbt_header) > size) { |
Line 1244... | Line 1238... | ||
1244 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
1238 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
1245 | return NULL; |
1239 | return false; |
1246 | } |
1240 | } |
1247 | 1241 | ||
Line 1248... | Line -... | ||
1248 | if (memcmp(vbt->signature, "$VBT", 4)) { |
- | |
1249 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
1242 | if (memcmp(vbt->signature, "$VBT", 4)) { |
1250 | return NULL; |
1243 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
1251 | } |
1244 | return false; |
1252 | 1245 | } |
|
Line 1253... | Line 1246... | ||
1253 | offset += vbt->bdb_offset; |
1246 | |
1254 | if (offset + sizeof(struct bdb_header) > size) { |
1247 | if (vbt->bdb_offset + sizeof(struct bdb_header) > size) { |
1255 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
1248 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
1256 | return NULL; |
1249 | return false; |
1257 | } |
1250 | } |
Line 1258... | Line -... | ||
1258 | - | ||
1259 | bdb = base + offset; |
- | |
1260 | if (offset + bdb->bdb_size > size) { |
1251 | |
1261 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
1252 | bdb = get_bdb_header(vbt); |
Line 1262... | Line 1253... | ||
1262 | return NULL; |
1253 | if (vbt->bdb_offset + bdb->bdb_size > size) { |
1263 | } |
1254 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
1264 | - | ||
1265 | DRM_DEBUG_KMS("Using VBT from %s: %20s\n", |
1255 | return false; |
Line 1266... | Line 1256... | ||
1266 | source, vbt->signature); |
1256 | } |
1267 | return bdb; |
1257 | |
- | 1258 | return vbt; |
|
- | 1259 | } |
|
1268 | } |
1260 | |
- | 1261 | static const struct vbt_header *find_vbt(void __iomem *bios, size_t size) |
|
- | 1262 | { |
|
1269 | 1263 | size_t i; |
|
1270 | static const struct bdb_header *find_vbt(void __iomem *bios, size_t size) |
1264 | |
1271 | { |
1265 | /* Scour memory looking for the VBT signature. */ |
1272 | const struct bdb_header *bdb = NULL; |
- | |
1273 | size_t i; |
- | |
1274 | 1266 | for (i = 0; i + 4 < size; i++) { |
|
1275 | /* Scour memory looking for the VBT signature. */ |
1267 | void *vbt; |
- | 1268 | ||
- | 1269 | if (ioread32(bios + i) != *((const u32 *) "$VBT")) |
|
Line 1276... | Line -... | ||
1276 | for (i = 0; i + 4 < size; i++) { |
- | |
1277 | if (ioread32(bios + i) == *((const u32 *) "$VBT")) { |
1270 | continue; |
1278 | /* |
1271 | |
1279 | * This is the one place where we explicitly discard the |
- | |
Line 1280... | Line 1272... | ||
1280 | * address space (__iomem) of the BIOS/VBT. From now on |
1272 | /* |
1281 | * everything is based on 'base', and treated as regular |
1273 | * This is the one place where we explicitly discard the address |
Line 1282... | Line 1274... | ||
1282 | * memory. |
1274 | * space (__iomem) of the BIOS/VBT. |
1283 | */ |
1275 | */ |
1284 | void *_bios = (void __force *) bios; |
1276 | vbt = (void __force *) bios + i; |
1285 | 1277 | if (intel_bios_is_valid_vbt(vbt, size - i)) |
|
1286 | bdb = validate_vbt(_bios, size, _bios + i, "PCI ROM"); |
1278 | return vbt; |
1287 | break; |
1279 | |
1288 | } |
1280 | break; |
1289 | } |
1281 | } |
1290 | 1282 | ||
1291 | return bdb; |
1283 | return NULL; |
1292 | } |
1284 | } |
1293 | 1285 | ||
1294 | /** |
1286 | /** |
1295 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
1287 | * intel_bios_init - find VBT and initialize settings from the BIOS |
1296 | * @dev: DRM device |
1288 | * @dev: DRM device |
1297 | * |
1289 | * |
Line 1298... | Line 1290... | ||
1298 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
1290 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
1299 | * to appropriate values. |
1291 | * to appropriate values. |
Line 1300... | Line 1292... | ||
1300 | * |
1292 | * |
Line 1301... | Line -... | ||
1301 | * Returns 0 on success, nonzero on failure. |
- | |
1302 | */ |
- | |
1303 | int |
- | |
1304 | intel_parse_bios(struct drm_device *dev) |
- | |
1305 | { |
- | |
1306 | struct drm_i915_private *dev_priv = dev->dev_private; |
1293 | * Returns 0 on success, nonzero on failure. |
1307 | struct pci_dev *pdev = dev->pdev; |
1294 | */ |
Line 1308... | Line 1295... | ||
1308 | const struct bdb_header *bdb = NULL; |
1295 | int |
1309 | u8 __iomem *bios = NULL; |
1296 | intel_bios_init(struct drm_i915_private *dev_priv) |
1310 | 1297 | { |
|
Line 1311... | Line 1298... | ||
1311 | if (HAS_PCH_NOP(dev)) |
1298 | struct pci_dev *pdev = dev_priv->dev->pdev; |
1312 | return -ENODEV; |
1299 | const struct vbt_header *vbt = dev_priv->opregion.vbt; |
1313 | 1300 | const struct bdb_header *bdb; |
|
1314 | init_vbt_defaults(dev_priv); |
1301 | u8 __iomem *bios = NULL; |
1315 | 1302 | ||
- | 1303 | if (HAS_PCH_NOP(dev_priv)) |
|
- | 1304 | return -ENODEV; |
|
1316 | /* XXX Should this validation be moved to intel_opregion.c? */ |
1305 | |
Line -... | Line 1306... | ||
- | 1306 | init_vbt_defaults(dev_priv); |
|
- | 1307 | ||
- | 1308 | if (!vbt) { |
|
- | 1309 | size_t size; |
|
- | 1310 | ||
1317 | if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) |
1311 | bios = pci_map_rom(pdev, &size); |
1318 | bdb = validate_vbt(dev_priv->opregion.header, OPREGION_SIZE, |
1312 | if (!bios) |
1319 | dev_priv->opregion.vbt, "OpRegion"); |
1313 | return -1; |
1320 | 1314 | ||
1321 | if (bdb == NULL) { |
1315 | vbt = find_vbt(bios, size); |
Line 1349... | Line 1343... | ||
1349 | if (bios) |
1343 | if (bios) |
1350 | pci_unmap_rom(pdev, bios); |
1344 | pci_unmap_rom(pdev, bios); |
Line 1351... | Line 1345... | ||
1351 | 1345 | ||
1352 | return 0; |
1346 | return 0; |
1353 | } |
- | |
1354 | - | ||
1355 | /** |
- | |
1356 | * intel_bios_is_port_present - is the specified digital port present |
- | |
1357 | * @dev_priv: i915 device instance |
- | |
1358 | * @port: port to check |
- | |
1359 | * |
- | |
1360 | * Return true if the device in %port is present. |
- | |
1361 | */ |
- | |
1362 | bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port) |
- | |
1363 | { |
- | |
1364 | static const struct { |
- | |
1365 | u16 dp, hdmi; |
- | |
1366 | } port_mapping[] = { |
- | |
1367 | [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, }, |
- | |
1368 | [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, |
- | |
1369 | [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, |
- | |
1370 | [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, |
- | |
1371 | }; |
- | |
1372 | int i; |
- | |
1373 | - | ||
1374 | /* FIXME maybe deal with port A as well? */ |
- | |
1375 | if (WARN_ON(port == PORT_A) || port >= ARRAY_SIZE(port_mapping)) |
- | |
1376 | return false; |
- | |
1377 | - | ||
1378 | if (!dev_priv->vbt.child_dev_num) |
- | |
1379 | return false; |
- | |
1380 | - | ||
1381 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
- | |
1382 | const union child_device_config *p_child = |
- | |
1383 | &dev_priv->vbt.child_dev[i]; |
- | |
1384 | if ((p_child->common.dvo_port == port_mapping[port].dp || |
- | |
1385 | p_child->common.dvo_port == port_mapping[port].hdmi) && |
- | |
1386 | (p_child->common.device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING | |
- | |
1387 | DEVICE_TYPE_DISPLAYPORT_OUTPUT))) |
- | |
1388 | return true; |
- | |
1389 | } |
- | |
1390 | - | ||
1391 | return false; |
- |