diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_bios.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_bios.c | 168 |
1 files changed, 81 insertions, 87 deletions
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index ce82f9c7df24..eba3e0f87181 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -24,7 +24,7 @@ * Eric Anholt <eric@anholt.net> * */ -#include <linux/dmi.h> + #include <drm/drm_dp_helper.h> #include <drm/drmP.h> #include <drm/i915_drm.h> @@ -332,10 +332,10 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, drm_mode_debug_printmodeline(panel_fixed_mode); } -static int intel_bios_ssc_frequency(struct drm_device *dev, +static int intel_bios_ssc_frequency(struct drm_i915_private *dev_priv, bool alternate) { - switch (INTEL_INFO(dev)->gen) { + switch (INTEL_INFO(dev_priv)->gen) { case 2: return alternate ? 66667 : 48000; case 3: @@ -350,26 +350,29 @@ static void parse_general_features(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) { - struct drm_device *dev = dev_priv->dev; const struct bdb_general_features *general; general = find_section(bdb, BDB_GENERAL_FEATURES); - if (general) { - dev_priv->vbt.int_tv_support = general->int_tv_support; + if (!general) + return; + + dev_priv->vbt.int_tv_support = general->int_tv_support; + /* int_crt_support can't be trusted on earlier platforms */ + if (bdb->version >= 155 && + (HAS_DDI(dev_priv) || IS_VALLEYVIEW(dev_priv))) dev_priv->vbt.int_crt_support = general->int_crt_support; - dev_priv->vbt.lvds_use_ssc = general->enable_ssc; - dev_priv->vbt.lvds_ssc_freq = - intel_bios_ssc_frequency(dev, general->ssc_freq); - dev_priv->vbt.display_clock_mode = general->display_clock_mode; - dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; - 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", - dev_priv->vbt.int_tv_support, - dev_priv->vbt.int_crt_support, - dev_priv->vbt.lvds_use_ssc, - dev_priv->vbt.lvds_ssc_freq, - dev_priv->vbt.display_clock_mode, - dev_priv->vbt.fdi_rx_polarity_inverted); - } + dev_priv->vbt.lvds_use_ssc = general->enable_ssc; + dev_priv->vbt.lvds_ssc_freq = + intel_bios_ssc_frequency(dev_priv, general->ssc_freq); + dev_priv->vbt.display_clock_mode = general->display_clock_mode; + dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + 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", + dev_priv->vbt.int_tv_support, + dev_priv->vbt.int_crt_support, + dev_priv->vbt.lvds_use_ssc, + dev_priv->vbt.lvds_ssc_freq, + dev_priv->vbt.display_clock_mode, + dev_priv->vbt.fdi_rx_polarity_inverted); } static void @@ -1054,10 +1057,9 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, static void parse_ddi_ports(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) { - struct drm_device *dev = dev_priv->dev; enum port port; - if (!HAS_DDI(dev)) + if (!HAS_DDI(dev_priv)) return; if (!dev_priv->vbt.child_dev_num) @@ -1170,7 +1172,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv, static void init_vbt_defaults(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; enum port port; dev_priv->vbt.crt_ddc_pin = GMBUS_PIN_VGADDC; @@ -1195,8 +1196,8 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) * Core/SandyBridge/IvyBridge use alternative (120MHz) reference * clock for LVDS. */ - dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, - !HAS_PCH_SPLIT(dev)); + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev_priv, + !HAS_PCH_SPLIT(dev_priv)); DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); for (port = PORT_A; port < I915_MAX_PORTS; port++) { @@ -1211,88 +1212,79 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) } } -static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id) +static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt) { - DRM_DEBUG_KMS("Falling back to manually reading VBT from " - "VBIOS ROM for %s\n", - id->ident); - return 1; + const void *_vbt = vbt; + + return _vbt + vbt->bdb_offset; } -static const struct dmi_system_id intel_no_opregion_vbt[] = { - { - .callback = intel_no_opregion_vbt_callback, - .ident = "ThinkCentre A57", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), - }, - }, - { } -}; - -static const struct bdb_header *validate_vbt(const void *base, - size_t size, - const void *_vbt, - const char *source) +/** + * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT + * @buf: pointer to a buffer to validate + * @size: size of the buffer + * + * Returns true on valid VBT. + */ +bool intel_bios_is_valid_vbt(const void *buf, size_t size) { - size_t offset = _vbt - base; - const struct vbt_header *vbt = _vbt; + const struct vbt_header *vbt = buf; const struct bdb_header *bdb; - if (offset + sizeof(struct vbt_header) > size) { + if (!vbt) + return false; + + if (sizeof(struct vbt_header) > size) { DRM_DEBUG_DRIVER("VBT header incomplete\n"); - return NULL; + return false; } if (memcmp(vbt->signature, "$VBT", 4)) { DRM_DEBUG_DRIVER("VBT invalid signature\n"); - return NULL; + return false; } - offset += vbt->bdb_offset; - if (offset + sizeof(struct bdb_header) > size) { + if (vbt->bdb_offset + sizeof(struct bdb_header) > size) { DRM_DEBUG_DRIVER("BDB header incomplete\n"); - return NULL; + return false; } - bdb = base + offset; - if (offset + bdb->bdb_size > size) { + bdb = get_bdb_header(vbt); + if (vbt->bdb_offset + bdb->bdb_size > size) { DRM_DEBUG_DRIVER("BDB incomplete\n"); - return NULL; + return false; } - DRM_DEBUG_KMS("Using VBT from %s: %20s\n", - source, vbt->signature); - return bdb; + return vbt; } -static const struct bdb_header *find_vbt(void __iomem *bios, size_t size) +static const struct vbt_header *find_vbt(void __iomem *bios, size_t size) { - const struct bdb_header *bdb = NULL; size_t i; /* Scour memory looking for the VBT signature. */ for (i = 0; i + 4 < size; i++) { - if (ioread32(bios + i) == *((const u32 *) "$VBT")) { - /* - * This is the one place where we explicitly discard the - * address space (__iomem) of the BIOS/VBT. From now on - * everything is based on 'base', and treated as regular - * memory. - */ - void *_bios = (void __force *) bios; + void *vbt; - bdb = validate_vbt(_bios, size, _bios + i, "PCI ROM"); - break; - } + if (ioread32(bios + i) != *((const u32 *) "$VBT")) + continue; + + /* + * This is the one place where we explicitly discard the address + * space (__iomem) of the BIOS/VBT. + */ + vbt = (void __force *) bios + i; + if (intel_bios_is_valid_vbt(vbt, size - i)) + return vbt; + + break; } - return bdb; + return NULL; } /** - * intel_parse_bios - find VBT and initialize settings from the BIOS + * intel_bios_init - find VBT and initialize settings from the BIOS * @dev: DRM device * * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers @@ -1301,37 +1293,39 @@ static const struct bdb_header *find_vbt(void __iomem *bios, size_t size) * Returns 0 on success, nonzero on failure. */ int -intel_parse_bios(struct drm_device *dev) +intel_bios_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct pci_dev *pdev = dev->pdev; - const struct bdb_header *bdb = NULL; + struct pci_dev *pdev = dev_priv->dev->pdev; + const struct vbt_header *vbt = dev_priv->opregion.vbt; + const struct bdb_header *bdb; u8 __iomem *bios = NULL; - if (HAS_PCH_NOP(dev)) + if (HAS_PCH_NOP(dev_priv)) return -ENODEV; init_vbt_defaults(dev_priv); - /* XXX Should this validation be moved to intel_opregion.c? */ - if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) - bdb = validate_vbt(dev_priv->opregion.header, OPREGION_SIZE, - dev_priv->opregion.vbt, "OpRegion"); - - if (bdb == NULL) { + if (!vbt) { size_t size; bios = pci_map_rom(pdev, &size); if (!bios) return -1; - bdb = find_vbt(bios, size); - if (!bdb) { + vbt = find_vbt(bios, size); + if (!vbt) { pci_unmap_rom(pdev, bios); return -1; } + + DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n"); } + bdb = get_bdb_header(vbt); + + DRM_DEBUG_KMS("VBT signature \"%.*s\", BDB version %d\n", + (int)sizeof(vbt->signature), vbt->signature, bdb->version); + /* Grab useful general definitions */ parse_general_features(dev_priv, bdb); parse_general_definitions(dev_priv, bdb); |