/** * DOC: Video BIOS Table (VBT) * * The Video BIOS Table, or VBT, provides platform and board specific * configuration information to the driver that is not discoverable or available * through other means. The configuration is mostly related to display * hardware. The VBT is available via the ACPI OpRegion or, on older systems, in * the PCI ROM. * * The VBT consists of a VBT Header (defined as &struct vbt_header), a BDB * Header (&struct bdb_header), and a number of BIOS Data Blocks (BDB) that * contain the actual configuration information. The VBT Header, and thus the * VBT, begins with "$VBT" signature. The VBT Header contains the offset of the * BDB Header. The data blocks are concatenated after the BDB Header. The data * blocks have a 1-byte Block ID, 2-byte Block Size, and Block Size bytes of * data. (Block 53, the MIPI Sequence Block is an exception.) * * The driver parses the VBT during load. The relevant information is stored in * driver private data for ease of use, and the actual VBT is not read after * that.
*/
/* Get BDB block size given a pointer to Block ID. */ static u32 _get_blocksize(const u8 *block_base)
{ /* The MIPI Sequence Block v3+ has a separate size field. */ if (*block_base == BDB_MIPI_SEQUENCE && *(block_base + 3) >= 3) return *((const u32 *)(block_base + 4)); else return *((const u16 *)(block_base + 1));
}
/* Get BDB block size give a pointer to data after Block ID and Block Size. */ static u32 get_blocksize(constvoid *block_data)
{ return _get_blocksize(block_data - 3);
}
/* skip to first section */
index += bdb->header_size;
total = bdb->bdb_size;
/* walk the sections looking for section_id */ while (index + 3 < total) {
current_id = *(base + index);
current_size = _get_blocksize(base + index);
index += 3;
if (index + current_size > total) return NULL;
if (current_id == section_id) return base + index;
index += current_size;
}
return NULL;
}
/* * Offset from the start of BDB to the start of the * block data (just past the block header).
*/ static u32 raw_block_offset(constvoid *bdb, enum bdb_block_id section_id)
{ constvoid *block;
block = find_raw_section(bdb, section_id); if (!block) return 0;
/* make sure the table entries have uniform size */ for (i = 1; i < 16; i++) { if (ptrs->ptr[i].fp_timing.table_size != fp_timing_size ||
ptrs->ptr[i].dvo_timing.table_size != dvo_timing_size ||
ptrs->ptr[i].panel_pnp_id.table_size != panel_pnp_id_size) returnfalse;
/* * Except for vlv/chv machines all real VBTs seem to have 6 * unaccounted bytes in the fp_timing table. And it doesn't * appear to be a really intentional hole as the fp_timing * 0xffff terminator is always within those 6 missing bytes.
*/ if (fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size == lfp_data_size)
fp_timing_size += 6;
if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size) returnfalse;
/* make sure the tables fit inside the data block */ for (i = 0; i < 16; i++) { if (ptrs->ptr[i].fp_timing.offset + fp_timing_size > data_block_size ||
ptrs->ptr[i].dvo_timing.offset + dvo_timing_size > data_block_size ||
ptrs->ptr[i].panel_pnp_id.offset + panel_pnp_id_size > data_block_size) returnfalse;
}
if (ptrs->panel_name.offset + 16 * panel_name_size > data_block_size) returnfalse;
/* make sure fp_timing terminators are present at expected locations */ for (i = 0; i < 16; i++) { const u16 *t = data_block + ptrs->ptr[i].fp_timing.offset +
fp_timing_size - 2;
if (*t != 0xffff) returnfalse;
}
returntrue;
}
/* make the data table offsets relative to the data block */ staticbool fixup_lfp_data_ptrs(constvoid *bdb, void *ptrs_block)
{ struct bdb_lfp_data_ptrs *ptrs = ptrs_block;
u32 offset; int i;
offset = raw_block_offset(bdb, BDB_LFP_DATA);
for (i = 0; i < 16; i++) { if (ptrs->ptr[i].fp_timing.offset < offset ||
ptrs->ptr[i].dvo_timing.offset < offset ||
ptrs->ptr[i].panel_pnp_id.offset < offset) returnfalse;
/* * The hardcoded fp_timing_size is only valid for * modernish VBTs. All older VBTs definitely should * include block 41 and thus we don't need to * generate one.
*/ if (display->vbt.version < 155) return NULL;
fp_timing_size = 38;
block = find_raw_section(bdb, BDB_LFP_DATA); if (!block) return NULL;
drm_dbg_kms(display->drm, "Generating LFP data table pointers\n");
if (ptrs->ptr[0].fp_timing.table_size)
ptrs->num_entries++; if (ptrs->ptr[0].dvo_timing.table_size)
ptrs->num_entries++; if (ptrs->ptr[0].panel_pnp_id.table_size)
ptrs->num_entries++;
/* Modern VBTs lack the LFP data table pointers block, make one up */ if (!block && section_id == BDB_LFP_DATA_PTRS) {
temp_block = generate_lfp_data_ptrs(display, bdb); if (temp_block)
block = temp_block + 3;
} if (!block) return;
drm_WARN(display->drm, min_size == 0, "Block %d min_size is zero\n", section_id);
block_size = get_blocksize(block);
/* * Version number and new block size are considered * part of the header for MIPI sequenece block v3+.
*/ if (section_id == BDB_MIPI_SEQUENCE && *(const u8 *)block >= 3)
block_size += 5;
staticconststruct drm_edid_product_id *
get_lfp_pnp_id(conststruct bdb_lfp_data *data, conststruct bdb_lfp_data_ptrs *ptrs, int index)
{ /* These two are supposed to have the same layout in memory. */
BUILD_BUG_ON(sizeof(struct bdb_edid_pnp_id) != sizeof(struct drm_edid_product_id));
p = drm_dbg_printer(display->drm, DRM_UT_KMS, "EDID");
drm_edid_print_product_id(&p, &product_id, true);
ptrs = bdb_find_section(display, BDB_LFP_DATA_PTRS); if (!ptrs) return -1;
data = bdb_find_section(display, BDB_LFP_DATA); if (!data) return -1;
for (i = 0; i < 16; i++) { conststruct drm_edid_product_id *vbt_id =
get_lfp_pnp_id(data, ptrs, i);
/* full match? */ if (!memcmp(vbt_id, &product_id, sizeof(*vbt_id))) return i;
/* * Accept a match w/o date if no full match is found, * and the VBT entry does not specify a date.
*/ if (best < 0 &&
!memcmp(vbt_id, &product_id_nodate, sizeof(*vbt_id)))
best = i;
}
/* * Empirical evidence indicates the block size can be * either 4,14,16,24+ bytes. For older VBTs no clear * relationship between the block size vs. BDB version.
*/ if (get_blocksize(lfp_options) < 16) return;
drrs_mode = panel_bits(lfp_options->dps_panel_type_bits,
panel_type, 2); /* * 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:
panel->vbt.drrs_type = DRRS_TYPE_STATIC;
drm_dbg_kms(display->drm, "DRRS supported mode is static\n"); break; case 2:
panel->vbt.drrs_type = DRRS_TYPE_SEAMLESS;
drm_dbg_kms(display->drm, "DRRS supported mode is seamless\n"); break; default:
panel->vbt.drrs_type = DRRS_TYPE_NONE;
drm_dbg_kms(display->drm, "DRRS not supported (VBT input)\n"); break;
}
}
/* check the resolution, just to be sure */ if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
fp_timing->y_res == panel_fixed_mode->vdisplay) {
panel->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
drm_dbg_kms(display->drm, "VBT initial LVDS value %x\n",
panel->vbt.bios_lvds_val);
}
}
/* * Older VBTs provided DTD information for internal displays through * the "LFP panel tables" block (42). As of VBT revision 229 the * DTD information should be provided via a newer "generic DTD" * block (58). Just to be safe, we'll try the new generic DTD block * first on VBT >= 229, but still fall back to trying the old LFP * block if that fails.
*/ if (display->vbt.version < 229) return;
generic_dtd = bdb_find_section(display, BDB_GENERIC_DTD); if (!generic_dtd) return;
if (generic_dtd->gdtd_size < sizeof(struct generic_dtd_entry)) {
drm_err(display->drm, "GDTD size %u is too small.\n",
generic_dtd->gdtd_size); return;
} elseif (generic_dtd->gdtd_size != sizeof(struct generic_dtd_entry)) {
drm_err(display->drm, "Unexpected GDTD size %u\n",
generic_dtd->gdtd_size); /* DTD has unknown fields, but keep going */
}
num_dtd = (get_blocksize(generic_dtd) - sizeof(struct bdb_generic_dtd)) / generic_dtd->gdtd_size; if (panel->vbt.panel_type >= num_dtd) {
drm_err(display->drm, "Panel type %d not found in table of %d DTD's\n",
panel->vbt.panel_type, num_dtd); return;
}
dtd = &generic_dtd->dtd[panel->vbt.panel_type];
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) return;
index = display->params.vbt_sdvo_panel_type; if (index == -2) {
drm_dbg_kms(display->drm, "Ignore SDVO LVDS mode from BIOS VBT tables.\n"); return;
}
if (index == -1) { conststruct bdb_sdvo_lvds_options *sdvo_lvds_options;
sdvo_lvds_options = bdb_find_section(display, BDB_SDVO_LVDS_OPTIONS); if (!sdvo_lvds_options) return;
index = sdvo_lvds_options->panel_type;
}
dtd = bdb_find_section(display, BDB_SDVO_LVDS_DTD); if (!dtd) return;
/* * This should not happen, as long as the panel_type * enumeration doesn't grow over 4 items. But if it does, it * could lead to hard-to-detect bugs, so better double-check * it here to be sure.
*/ if (index >= ARRAY_SIZE(dtd->dtd)) {
drm_err(display->drm, "index %d is larger than dtd->dtd[4] array\n",
index); return;
}
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) return;
/* * Only parse SDVO mappings on gens that could have SDVO. This isn't * accurate and doesn't have to be, as long as it's not too strict.
*/ if (!IS_DISPLAY_VER(display, 3, 7)) {
drm_dbg_kms(display->drm, "Skipping SDVO device mapping\n"); return;
}
if (child->target_addr != TARGET_ADDR1 &&
child->target_addr != TARGET_ADDR2) { /* * If the target address is neither 0x70 nor 0x72, * it is not a SDVO device. Skip it.
*/ continue;
} if (child->dvo_port != DEVICE_PORT_DVOB &&
child->dvo_port != DEVICE_PORT_DVOC) { /* skip the incorrect SDVO port */
drm_dbg_kms(display->drm, "Incorrect SDVO port. Skip it\n"); continue;
}
drm_dbg_kms(display->drm, "the SDVO device with target addr %2x is found on" " %s port\n",
child->target_addr,
(child->dvo_port == DEVICE_PORT_DVOB) ? "SDVOB" : "SDVOC");
mapping = &display->vbt.sdvo_mappings[child->dvo_port - 1]; if (!mapping->initialized) {
mapping->dvo_port = child->dvo_port;
mapping->target_addr = child->target_addr;
mapping->dvo_wiring = child->dvo_wiring;
mapping->ddc_pin = child->ddc_pin;
mapping->i2c_pin = child->i2c_pin;
mapping->initialized = 1;
drm_dbg_kms(display->drm, "SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
mapping->dvo_port, mapping->target_addr,
mapping->dvo_wiring, mapping->ddc_pin,
mapping->i2c_pin);
} else {
drm_dbg_kms(display->drm, "Maybe one SDVO port is shared by " "two SDVO device.\n");
} if (child->target2_addr) { /* Maybe this is a SDVO device with multiple inputs */ /* And the mapping info is not added */
drm_dbg_kms(display->drm, "there exists the target2_addr. Maybe this" " is a SDVO device with multiple inputs.\n");
}
count++;
}
if (!count) { /* No SDVO device info is found */
drm_dbg_kms(display->drm, "No SDVO device info is found in VBT\n");
}
}
driver = bdb_find_section(display, BDB_DRIVER_FEATURES); if (!driver) return;
if (DISPLAY_VER(display) >= 5) { /* * Note that we consider BDB_DRIVER_FEATURE_INT_SDVO_LVDS * to mean "eDP". The VBT spec doesn't agree with that * interpretation, but real world VBTs seem to.
*/ if (driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS)
display->vbt.int_lvds_support = 0;
} else { /* * FIXME it's not clear which BDB version has the LVDS config * bits defined. Revision history in the VBT spec says: * "0.92 | Add two definitions for VBT value of LVDS Active * Config (00b and 11b values defined) | 06/13/2005" * but does not the specify the BDB version. * * So far version 134 (on i945gm) is the oldest VBT observed * in the wild with the bits correctly populated. Version * 108 (on i85x) does not have the bits correctly populated.
*/ if (display->vbt.version >= 134 &&
driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS &&
driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS)
display->vbt.int_lvds_support = 0;
}
}
driver = bdb_find_section(display, BDB_DRIVER_FEATURES); if (!driver) return;
if (display->vbt.version < 228) {
drm_dbg_kms(display->drm, "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 && panel->vbt.drrs_type != DRRS_TYPE_NONE) { /* * FIXME Should DMRRS perhaps be treated as seamless * but without the automatic downclocking?
*/ if (driver->dmrrs_enabled)
panel->vbt.drrs_type = DRRS_TYPE_STATIC; else
panel->vbt.drrs_type = DRRS_TYPE_NONE;
}
/* * 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 * power->drrs & BIT(panel_type)=false
*/ if (!panel_bool(power->drrs, panel_type) && panel->vbt.drrs_type != DRRS_TYPE_NONE) { /* * FIXME Should DMRRS perhaps be treated as seamless * but without the automatic downclocking?
*/ if (panel_bool(power->dmrrs, panel_type))
panel->vbt.drrs_type = DRRS_TYPE_STATIC; else
panel->vbt.drrs_type = DRRS_TYPE_NONE;
}
if (display->vbt.version >= 232)
panel->vbt.edp.hobl = panel_bool(power->hobl, panel_type);
if (display->vbt.version >= 233)
panel->vbt.vrr = panel_bool(power->vrr_feature_enabled,
panel_type);
}
/* * New psr options 0=500us, 1=100us, 2=2500us, 3=0us * Old decimal value is wake up time in multiples of 100 us.
*/ if (display->vbt.version >= 205 &&
(DISPLAY_VER(display) >= 9 && !display->platform.broxton)) { switch (psr_table->tp1_wakeup_time) { case 0:
panel->vbt.psr.tp1_wakeup_time_us = 500; break; case 1:
panel->vbt.psr.tp1_wakeup_time_us = 100; break; case 3:
panel->vbt.psr.tp1_wakeup_time_us = 0; break; default:
drm_dbg_kms(display->drm, "VBT tp1 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
psr_table->tp1_wakeup_time);
fallthrough; case 2:
panel->vbt.psr.tp1_wakeup_time_us = 2500; break;
}
switch (psr_table->tp2_tp3_wakeup_time) { case 0:
panel->vbt.psr.tp2_tp3_wakeup_time_us = 500; break; case 1:
panel->vbt.psr.tp2_tp3_wakeup_time_us = 100; break; case 3:
panel->vbt.psr.tp2_tp3_wakeup_time_us = 0; break; default:
drm_dbg_kms(display->drm, "VBT tp2_tp3 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
psr_table->tp2_tp3_wakeup_time);
fallthrough; case 2:
panel->vbt.psr.tp2_tp3_wakeup_time_us = 2500; break;
}
} else {
panel->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100;
panel->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100;
}
if (display->vbt.version >= 226) {
u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time;
wakeup_time = panel_bits(wakeup_time, panel_type, 2); switch (wakeup_time) { case 0:
wakeup_time = 500; break; case 1:
wakeup_time = 100; break; case 3:
wakeup_time = 50; break; default: case 2:
wakeup_time = 2500; break;
}
panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time;
} else { /* Reusing PSR1 wakeup time for PSR2 in older VBTs */
panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = panel->vbt.psr.tp2_tp3_wakeup_time_us;
}
}
/* parse MIPI blocks only if LFP type is MIPI */ if (!intel_bios_is_dsi_present(display, &port)) return;
/* Initialize this to undefined indicating no generic MIPI support */
panel->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
start = bdb_find_section(display, BDB_MIPI_CONFIG); if (!start) {
drm_dbg_kms(display->drm, "No MIPI config BDB found"); return;
}
drm_dbg_kms(display->drm, "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 */
panel->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); if (!panel->vbt.dsi.config) return;
/* FIXME is the 90 vs. 270 correct? */ switch (config->rotation) { case ENABLE_ROTATION_0: /* * Most (all?) VBTs claim 0 degrees despite having * an upside down panel, thus we do not trust this.
*/
panel->vbt.dsi.orientation =
DRM_MODE_PANEL_ORIENTATION_UNKNOWN; break; case ENABLE_ROTATION_90:
panel->vbt.dsi.orientation =
DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; break; case ENABLE_ROTATION_180:
panel->vbt.dsi.orientation =
DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; break; case ENABLE_ROTATION_270:
panel->vbt.dsi.orientation =
DRM_MODE_PANEL_ORIENTATION_LEFT_UP; break;
}
/* We have mandatory mipi config blocks. Initialize as generic panel */
panel->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
}
/* Find the sequence block and size for the given panel. */ staticconst u8 *
find_panel_sequence_block(struct intel_display *display, conststruct bdb_mipi_sequence *sequence,
u16 panel_id, u32 *seq_size)
{
u32 total = get_blocksize(sequence); const u8 *data = &sequence->data[0];
u8 current_id;
u32 current_size; int header_size = sequence->version >= 3 ? 5 : 3; int index = 0; int i;
/* skip new block size */ if (sequence->version >= 3)
data += 4;
for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) { if (index + header_size > total) {
drm_err(display->drm, "Invalid sequence block (header)\n"); return NULL;
}
current_id = *(data + index); if (sequence->version >= 3)
current_size = *((const u32 *)(data + index + 1)); else
current_size = *((const u16 *)(data + index + 1));
if (current_id == panel_id) {
*seq_size = current_size; return data + index;
}
index += current_size;
}
drm_err(display->drm, "Sequence block detected but no valid configuration\n");
return NULL;
}
staticint goto_next_sequence(struct intel_display *display, const u8 *data, int index, int total)
{
u16 len;
/* Skip Sequence Byte. */ for (index = index + 1; index < total; index += len) {
u8 operation_byte = *(data + index);
index++;
switch (operation_byte) { case MIPI_SEQ_ELEM_END: return index; case MIPI_SEQ_ELEM_SEND_PKT: if (index + 4 > total) return 0;
len = *((const u16 *)(data + index + 2)) + 4; break; case MIPI_SEQ_ELEM_DELAY:
len = 4; break; case MIPI_SEQ_ELEM_GPIO:
len = 2; break; case MIPI_SEQ_ELEM_I2C: if (index + 7 > total) return 0;
len = *(data + index + 6) + 7; break; default:
drm_err(display->drm, "Unknown operation byte\n"); return 0;
}
}
return 0;
}
staticint goto_next_sequence_v3(struct intel_display *display, const u8 *data, int index, int total)
{ int seq_end;
u16 len;
u32 size_of_sequence;
/* * Could skip sequence based on Size of Sequence alone, but also do some * checking on the structure.
*/ if (total < 5) {
drm_err(display->drm, "Too small sequence size\n"); return 0;
}
/* Skip Sequence Byte. */
index++;
/* * Size of Sequence. Excludes the Sequence Byte and the size itself, * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END * byte.
*/
size_of_sequence = *((const u32 *)(data + index));
index += 4;
seq_end = index + size_of_sequence; if (seq_end > total) {
drm_err(display->drm, "Invalid sequence size\n"); return 0;
}
for (; index < total; index += len) {
u8 operation_byte = *(data + index);
index++;
if (operation_byte == MIPI_SEQ_ELEM_END) { if (index != seq_end) {
drm_err(display->drm, "Invalid element structure\n"); return 0;
} return index;
}
len = *(data + index);
index++;
/* * FIXME: Would be nice to check elements like for v1/v2 in * goto_next_sequence() above.
*/ switch (operation_byte) { case MIPI_SEQ_ELEM_SEND_PKT: case MIPI_SEQ_ELEM_DELAY: case MIPI_SEQ_ELEM_GPIO: case MIPI_SEQ_ELEM_I2C: case MIPI_SEQ_ELEM_SPI: case MIPI_SEQ_ELEM_PMIC: break; default:
drm_err(display->drm, "Unknown operation byte %u\n",
operation_byte); break;
}
}
return 0;
}
/* * Get len of pre-fixed deassert fragment from a v1 init OTP sequence, * skip all delay + gpio operands and stop at the first DSI packet op.
*/ staticint get_init_otp_deassert_fragment_len(struct intel_display *display, struct intel_panel *panel)
{ const u8 *data = panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; int index, len;
if (drm_WARN_ON(display->drm,
!data || panel->vbt.dsi.seq_version >= 3)) return 0;
/* index = 1 to skip sequence byte */ for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) { switch (data[index]) { case MIPI_SEQ_ELEM_SEND_PKT: return index == 1 ? 0 : index; case MIPI_SEQ_ELEM_DELAY:
len = 5; /* 1 byte for operand + uint32 */ break; case MIPI_SEQ_ELEM_GPIO:
len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */ break; default: return 0;
}
}
return 0;
}
/* * Some v1/v2 VBT MIPI sequences do the deassert in the init OTP sequence. * The deassert must be done before calling intel_dsi_device_ready, so for * these devices we split the init OTP sequence into a deassert sequence and * the actual init OTP part.
*/ staticvoid vlv_fixup_mipi_sequences(struct intel_display *display, struct intel_panel *panel)
{
u8 *init_otp; int len;
/* Limit this to v1/v2 vid-mode sequences */ if (panel->vbt.dsi.config->is_cmd_mode ||
panel->vbt.dsi.seq_version >= 3) return;
/* Only do this if there are otp and assert seqs and no deassert seq */ if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] ||
!panel->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] ||
panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) return;
/* The deassert-sequence ends at the first DSI packet */
len = get_init_otp_deassert_fragment_len(display, panel); if (!len) return;
drm_dbg_kms(display->drm, "Using init OTP fragment to deassert reset\n");
/* Copy the fragment, update seq byte and terminate it */
init_otp = (u8 *)panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
panel->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); if (!panel->vbt.dsi.deassert_seq) return;
panel->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET;
panel->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; /* Use the copy for deassert */
panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] =
panel->vbt.dsi.deassert_seq; /* Replace the last byte of the fragment with init OTP seq byte */
init_otp[len - 1] = MIPI_SEQ_INIT_OTP; /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */
panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1;
}
/* * Some machines (eg. Lenovo 82TQ) appear to have broken * VBT sequences: * - INIT_OTP is not present at all * - what should be in INIT_OTP is in DISPLAY_ON * - what should be in DISPLAY_ON is in BACKLIGHT_ON * (along with the actual backlight stuff) * * To make those work we simply swap DISPLAY_ON and INIT_OTP. * * TODO: Do we need to limit this to specific machines, * or examine the contents of the sequences to * avoid false positives?
*/ staticvoid icl_fixup_mipi_sequences(struct intel_display *display, struct intel_panel *panel)
{ if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] &&
panel->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON]) {
drm_dbg_kms(display->drm, "Broken VBT: Swapping INIT_OTP and DISPLAY_ON sequences\n");
if (val >= ARRAY_SIZE(mapping)) {
drm_dbg_kms(display->drm, "Unsupported I_boost value found in VBT (%d), display may not work properly\n", val); return 0;
} return mapping[val];
}
for (i = 0; i < n_entries; i++) { if (ddc_pin_map[i] == vbt_pin) return i;
}
drm_dbg_kms(display->drm, "Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n",
vbt_pin); return 0;
}
static u8 dvo_port_type(u8 dvo_port)
{ switch (dvo_port) { case DVO_PORT_HDMIA: case DVO_PORT_HDMIB: case DVO_PORT_HDMIC: case DVO_PORT_HDMID: case DVO_PORT_HDMIE: case DVO_PORT_HDMIF: case DVO_PORT_HDMIG: case DVO_PORT_HDMIH: case DVO_PORT_HDMII: return DVO_PORT_HDMIA; case DVO_PORT_DPA: case DVO_PORT_DPB: case DVO_PORT_DPC: case DVO_PORT_DPD: case DVO_PORT_DPE: case DVO_PORT_DPF: case DVO_PORT_DPG: case DVO_PORT_DPH: case DVO_PORT_DPI: return DVO_PORT_DPA; case DVO_PORT_MIPIA: case DVO_PORT_MIPIB: case DVO_PORT_MIPIC: case DVO_PORT_MIPID: return DVO_PORT_MIPIA; default: return dvo_port;
}
}
staticenum port __dvo_port_to_port(int n_ports, int n_dvo, constint port_mapping[][3], u8 dvo_port)
{ enum port port; int i;
for (port = PORT_A; port < n_ports; port++) { for (i = 0; i < n_dvo; i++) {
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.