Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5059 → Rev 5060

/drivers/video/drm/i915/intel_bios.c
24,8 → 24,8
* Eric Anholt <eric@anholt.net>
*
*/
#include <drm/drmP.h>
#include <drm/drm_dp_helper.h>
#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "intel_bios.h"
48,13 → 48,19
total = bdb->bdb_size;
 
/* walk the sections looking for section_id */
while (index < total) {
while (index + 3 < total) {
current_id = *(base + index);
index++;
 
current_size = *((u16 *)(base + index));
index += 2;
 
if (index + current_size > total)
return NULL;
 
if (current_id == section_id)
return base + index;
 
index += current_size;
}
 
205,7 → 211,7
const struct lvds_dvo_timing *panel_dvo_timing;
const struct lvds_fp_timing *fp_timing;
struct drm_display_mode *panel_fixed_mode;
int i, downclock;
int i, downclock, drrs_mode;
 
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
if (!lvds_options)
217,6 → 223,28
 
panel_type = lvds_options->panel_type;
 
drrs_mode = (lvds_options->dps_panel_type_bits
>> (panel_type * 2)) & MODE_MASK;
/*
* VBT has static DRRS = 0 and seamless DRRS = 2.
* The below piece of code is required to adjust vbt.drrs_type
* to match the enum drrs_support_type.
*/
switch (drrs_mode) {
case 0:
dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT;
DRM_DEBUG_KMS("DRRS supported mode is static\n");
break;
case 2:
dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT;
DRM_DEBUG_KMS("DRRS supported mode is seamless\n");
break;
default:
dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED;
DRM_DEBUG_KMS("DRRS not supported (VBT input)\n");
break;
}
 
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
return;
258,7 → 286,7
downclock = dvo_timing->clock;
}
 
if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) {
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = downclock * 10;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
298,13 → 326,21
 
entry = &backlight_data->data[panel_type];
 
dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM;
if (!dev_priv->vbt.backlight.present) {
DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n",
entry->type);
return;
}
 
dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, "
"active %s, min brightness %u, level %u\n",
dev_priv->vbt.backlight.pwm_freq_hz,
dev_priv->vbt.backlight.active_low_pwm ? "low" : "high",
entry->min_brightness,
dev_priv->vbt.backlight.min_brightness,
backlight_data->level[panel_type]);
}
 
317,7 → 353,7
struct drm_display_mode *panel_fixed_mode;
int index;
 
index = i915_vbt_sdvo_panel_type;
index = i915.vbt_sdvo_panel_type;
if (index == -2) {
DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n");
return;
515,6 → 551,16
 
if (driver->dual_frequency)
dev_priv->render_reclock_avail = true;
 
DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled);
/*
* If DRRS is not supported, drrs_type has to be set to 0.
* This is because, VBT is configured in such a way that
* static DRRS is 0 and DRRS not supported is represented by
* driver->drrs_enabled=false
*/
if (!driver->drrs_enabled)
dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED;
}
 
static void
549,65 → 595,291
 
dev_priv->vbt.edp_pps = *edp_pps;
 
dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
DP_LINK_BW_1_62;
switch (edp_link_params->rate) {
case EDP_RATE_1_62:
dev_priv->vbt.edp_rate = DP_LINK_BW_1_62;
break;
case EDP_RATE_2_7:
dev_priv->vbt.edp_rate = DP_LINK_BW_2_7;
break;
default:
DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n",
edp_link_params->rate);
break;
}
 
switch (edp_link_params->lanes) {
case 0:
case EDP_LANE_1:
dev_priv->vbt.edp_lanes = 1;
break;
case 1:
case EDP_LANE_2:
dev_priv->vbt.edp_lanes = 2;
break;
case 3:
default:
case EDP_LANE_4:
dev_priv->vbt.edp_lanes = 4;
break;
default:
DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n",
edp_link_params->lanes);
break;
}
 
switch (edp_link_params->preemphasis) {
case 0:
case EDP_PREEMPHASIS_NONE:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
break;
case 1:
case EDP_PREEMPHASIS_3_5dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
break;
case 2:
case EDP_PREEMPHASIS_6dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
break;
case 3:
case EDP_PREEMPHASIS_9_5dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
break;
default:
DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n",
edp_link_params->preemphasis);
break;
}
 
switch (edp_link_params->vswing) {
case 0:
case EDP_VSWING_0_4V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400;
break;
case 1:
case EDP_VSWING_0_6V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600;
break;
case 2:
case EDP_VSWING_0_8V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800;
break;
case 3:
case EDP_VSWING_1_2V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200;
break;
default:
DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n",
edp_link_params->vswing);
break;
}
}
 
static u8 *goto_next_sequence(u8 *data, int *size)
{
u16 len;
int tmp = *size;
 
if (--tmp < 0)
return NULL;
 
/* goto first element */
data++;
while (1) {
switch (*data) {
case MIPI_SEQ_ELEM_SEND_PKT:
/*
* skip by this element payload size
* skip elem id, command flag and data type
*/
tmp -= 5;
if (tmp < 0)
return NULL;
 
data += 3;
len = *((u16 *)data);
 
tmp -= len;
if (tmp < 0)
return NULL;
 
/* skip by len */
data = data + 2 + len;
break;
case MIPI_SEQ_ELEM_DELAY:
/* skip by elem id, and delay is 4 bytes */
tmp -= 5;
if (tmp < 0)
return NULL;
 
data += 5;
break;
case MIPI_SEQ_ELEM_GPIO:
tmp -= 3;
if (tmp < 0)
return NULL;
 
data += 3;
break;
default:
DRM_ERROR("Unknown element\n");
return NULL;
}
 
/* end of sequence ? */
if (*data == 0)
break;
}
 
/* goto next sequence or end of block byte */
if (--tmp < 0)
return NULL;
 
data++;
 
/* update amount of data left for the sequence block to be parsed */
*size = tmp;
return data;
}
 
static void
parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
{
struct bdb_mipi *mipi;
struct bdb_mipi_config *start;
struct bdb_mipi_sequence *sequence;
struct mipi_config *config;
struct mipi_pps_data *pps;
u8 *data, *seq_data;
int i, panel_id, seq_size;
u16 block_size;
 
mipi = find_section(bdb, BDB_MIPI);
if (!mipi) {
DRM_DEBUG_KMS("No MIPI BDB found");
/* parse MIPI blocks only if LFP type is MIPI */
if (!dev_priv->vbt.has_mipi)
return;
 
/* Initialize this to undefined indicating no generic MIPI support */
dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
 
/* Block #40 is already parsed and panel_fixed_mode is
* stored in dev_priv->lfp_lvds_vbt_mode
* resuse this when needed
*/
 
/* Parse #52 for panel index used from panel_type already
* parsed
*/
start = find_section(bdb, BDB_MIPI_CONFIG);
if (!start) {
DRM_DEBUG_KMS("No MIPI config BDB found");
return;
}
 
/* XXX: add more info */
dev_priv->vbt.dsi.panel_id = mipi->panel_id;
DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n",
panel_type);
 
/*
* get hold of the correct configuration block and pps data as per
* the panel_type as index
*/
config = &start->config[panel_type];
pps = &start->pps[panel_type];
 
/* store as of now full data. Trim when we realise all is not needed */
dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL);
if (!dev_priv->vbt.dsi.config)
return;
 
dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL);
if (!dev_priv->vbt.dsi.pps) {
kfree(dev_priv->vbt.dsi.config);
return;
}
 
/* We have mandatory mipi config blocks. Initialize as generic panel */
dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
 
/* Check if we have sequence block as well */
sequence = find_section(bdb, BDB_MIPI_SEQUENCE);
if (!sequence) {
DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n");
return;
}
 
DRM_DEBUG_DRIVER("Found MIPI sequence block\n");
 
block_size = get_blocksize(sequence);
 
/*
* parse the sequence block for individual sequences
*/
dev_priv->vbt.dsi.seq_version = sequence->version;
 
seq_data = &sequence->data[0];
 
/*
* sequence block is variable length and hence we need to parse and
* get the sequence data for specific panel id
*/
for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
panel_id = *seq_data;
seq_size = *((u16 *) (seq_data + 1));
if (panel_id == panel_type)
break;
 
/* skip the sequence including seq header of 3 bytes */
seq_data = seq_data + 3 + seq_size;
if ((seq_data - &sequence->data[0]) > block_size) {
DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
return;
}
}
 
if (i == MAX_MIPI_CONFIGURATIONS) {
DRM_ERROR("Sequence block detected but no valid configuration\n");
return;
}
 
/* check if found sequence is completely within the sequence block
* just being paranoid */
if (seq_size > block_size) {
DRM_ERROR("Corrupted sequence/size, bailing out\n");
return;
}
 
/* skip the panel id(1 byte) and seq size(2 bytes) */
dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
if (!dev_priv->vbt.dsi.data)
return;
 
/*
* loop into the sequence data and split into multiple sequneces
* There are only 5 types of sequences as of now
*/
data = dev_priv->vbt.dsi.data;
dev_priv->vbt.dsi.size = seq_size;
 
/* two consecutive 0x00 indicate end of all sequences */
while (1) {
int seq_id = *data;
if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) {
dev_priv->vbt.dsi.sequence[seq_id] = data;
DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id);
} else {
DRM_ERROR("undefined sequence\n");
goto err;
}
 
/* partial parsing to skip elements */
data = goto_next_sequence(data, &seq_size);
 
if (data == NULL) {
DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n");
goto err;
}
 
if (*data == 0)
break; /* end of sequence reached */
}
 
DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n");
return;
err:
kfree(dev_priv->vbt.dsi.data);
dev_priv->vbt.dsi.data = NULL;
 
/* error during parsing so set all pointers to null
* because of partial parsing */
memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence));
}
 
static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
struct bdb_header *bdb)
{
788,6 → 1060,15
/* skip the device block if device type is invalid */
continue;
}
 
if (p_child->common.dvo_port >= DVO_PORT_MIPIA
&& p_child->common.dvo_port <= DVO_PORT_MIPID
&&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) {
DRM_DEBUG_KMS("Found MIPI as LFP\n");
dev_priv->vbt.has_mipi = 1;
dev_priv->vbt.dsi.port = p_child->common.dvo_port;
}
 
child_dev_ptr = dev_priv->vbt.child_dev + count;
count++;
memcpy((void *)child_dev_ptr, (void *)p_child,
804,6 → 1085,9
 
dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC;
 
/* Default to having backlight */
dev_priv->vbt.backlight.present = true;
 
/* LFP panel data */
dev_priv->vbt.lvds_dither = 1;
dev_priv->vbt.lvds_vbt = 0;
838,7 → 1122,46
}
}
 
static struct bdb_header *validate_vbt(char *base, size_t size,
struct vbt_header *vbt,
const char *source)
{
size_t offset;
struct bdb_header *bdb;
 
if (vbt == NULL) {
DRM_DEBUG_DRIVER("VBT signature missing\n");
return NULL;
}
 
offset = (char *)vbt - base;
if (offset + sizeof(struct vbt_header) > size) {
DRM_DEBUG_DRIVER("VBT header incomplete\n");
return NULL;
}
 
if (memcmp(vbt->signature, "$VBT", 4)) {
DRM_DEBUG_DRIVER("VBT invalid signature\n");
return NULL;
}
 
offset += vbt->bdb_offset;
if (offset + sizeof(struct bdb_header) > size) {
DRM_DEBUG_DRIVER("BDB header incomplete\n");
return NULL;
}
 
bdb = (struct bdb_header *)(base + offset);
if (offset + bdb->bdb_size > size) {
DRM_DEBUG_DRIVER("BDB incomplete\n");
return NULL;
}
 
DRM_DEBUG_KMS("Using VBT from %s: %20s\n",
source, vbt->signature);
return bdb;
}
 
/**
* intel_parse_bios - find VBT and initialize settings from the BIOS
* @dev: DRM device
862,20 → 1185,13
init_vbt_defaults(dev_priv);
 
/* XXX Should this validation be moved to intel_opregion.c? */
if (dev_priv->opregion.vbt) {
struct vbt_header *vbt = dev_priv->opregion.vbt;
if (memcmp(vbt->signature, "$VBT", 4) == 0) {
DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
vbt->signature);
bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
} else
dev_priv->opregion.vbt = NULL;
}
if (dev_priv->opregion.vbt)
bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE,
(struct vbt_header *)dev_priv->opregion.vbt,
"OpRegion");
 
if (bdb == NULL) {
struct vbt_header *vbt = NULL;
size_t size;
int i;
size_t i, size;
 
bios = pci_map_rom(pdev, &size);
if (!bios)
883,19 → 1199,18
 
/* Scour memory looking for the VBT signature */
for (i = 0; i + 4 < size; i++) {
if (!memcmp(bios + i, "$VBT", 4)) {
vbt = (struct vbt_header *)(bios + i);
if (memcmp(bios + i, "$VBT", 4) == 0) {
bdb = validate_vbt(bios, size,
(struct vbt_header *)(bios + i),
"PCI ROM");
break;
}
}
 
if (!vbt) {
DRM_DEBUG_DRIVER("VBT signature missing\n");
if (!bdb) {
pci_unmap_rom(pdev, bios);
return -1;
}
 
bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
}
 
/* Grab useful general definitions */