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 |
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,16 → 350,20 |
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) { |
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); |
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", |
370,7 → 374,6 |
dev_priv->vbt.display_clock_mode, |
dev_priv->vbt.fdi_rx_polarity_inverted); |
} |
} |
|
static void |
parse_general_definitions(struct drm_i915_private *dev_priv, |
1054,10 → 1057,9 |
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 |
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 |
* 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 |
} |
} |
|
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[] = { |
/** |
* 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) |
{ |
.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) |
{ |
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")) { |
void *vbt; |
|
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. From now on |
* everything is based on 'base', and treated as regular |
* memory. |
* This is the one place where we explicitly discard the address |
* space (__iomem) of the BIOS/VBT. |
*/ |
void *_bios = (void __force *) bios; |
vbt = (void __force *) bios + i; |
if (intel_bios_is_valid_vbt(vbt, size - i)) |
return vbt; |
|
bdb = validate_vbt(_bios, size, _bios + i, "PCI ROM"); |
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,24 → 1293,19 |
* 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); |
1325,13 → 1312,20 |
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); |
1351,42 → 1345,3 |
|
return 0; |
} |
|
/** |
* intel_bios_is_port_present - is the specified digital port present |
* @dev_priv: i915 device instance |
* @port: port to check |
* |
* Return true if the device in %port is present. |
*/ |
bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port) |
{ |
static const struct { |
u16 dp, hdmi; |
} port_mapping[] = { |
[PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, }, |
[PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, |
[PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, |
[PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, |
}; |
int i; |
|
/* FIXME maybe deal with port A as well? */ |
if (WARN_ON(port == PORT_A) || port >= ARRAY_SIZE(port_mapping)) |
return false; |
|
if (!dev_priv->vbt.child_dev_num) |
return false; |
|
for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
const union child_device_config *p_child = |
&dev_priv->vbt.child_dev[i]; |
if ((p_child->common.dvo_port == port_mapping[port].dp || |
p_child->common.dvo_port == port_mapping[port].hdmi) && |
(p_child->common.device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING | |
DEVICE_TYPE_DISPLAYPORT_OUTPUT))) |
return true; |
} |
|
return false; |
} |