1c349dbc7Sjsg /*
2c349dbc7Sjsg * Copyright © 2006 Intel Corporation
3c349dbc7Sjsg *
4c349dbc7Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg *
11c349dbc7Sjsg * The above copyright notice and this permission notice (including the next
12c349dbc7Sjsg * paragraph) shall be included in all copies or substantial portions of the
13c349dbc7Sjsg * Software.
14c349dbc7Sjsg *
15c349dbc7Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18c349dbc7Sjsg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20c349dbc7Sjsg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21c349dbc7Sjsg * SOFTWARE.
22c349dbc7Sjsg *
23c349dbc7Sjsg * Authors:
24c349dbc7Sjsg * Eric Anholt <eric@anholt.net>
25c349dbc7Sjsg *
26c349dbc7Sjsg */
27c349dbc7Sjsg
281bb76ff1Sjsg #include <drm/display/drm_dp_helper.h>
291bb76ff1Sjsg #include <drm/display/drm_dsc_helper.h>
30f005ef32Sjsg #include <drm/drm_edid.h>
31c349dbc7Sjsg
32c349dbc7Sjsg #include "i915_drv.h"
331bb76ff1Sjsg #include "i915_reg.h"
34f005ef32Sjsg #include "intel_display.h"
35f005ef32Sjsg #include "intel_display_types.h"
36f005ef32Sjsg #include "intel_gmbus.h"
37c349dbc7Sjsg
38c349dbc7Sjsg #define _INTEL_BIOS_PRIVATE
39c349dbc7Sjsg #include "intel_vbt_defs.h"
40c349dbc7Sjsg
41c349dbc7Sjsg /**
42c349dbc7Sjsg * DOC: Video BIOS Table (VBT)
43c349dbc7Sjsg *
44c349dbc7Sjsg * The Video BIOS Table, or VBT, provides platform and board specific
45c349dbc7Sjsg * configuration information to the driver that is not discoverable or available
46c349dbc7Sjsg * through other means. The configuration is mostly related to display
47c349dbc7Sjsg * hardware. The VBT is available via the ACPI OpRegion or, on older systems, in
48c349dbc7Sjsg * the PCI ROM.
49c349dbc7Sjsg *
50c349dbc7Sjsg * The VBT consists of a VBT Header (defined as &struct vbt_header), a BDB
51c349dbc7Sjsg * Header (&struct bdb_header), and a number of BIOS Data Blocks (BDB) that
52c349dbc7Sjsg * contain the actual configuration information. The VBT Header, and thus the
53c349dbc7Sjsg * VBT, begins with "$VBT" signature. The VBT Header contains the offset of the
54c349dbc7Sjsg * BDB Header. The data blocks are concatenated after the BDB Header. The data
55c349dbc7Sjsg * blocks have a 1-byte Block ID, 2-byte Block Size, and Block Size bytes of
56c349dbc7Sjsg * data. (Block 53, the MIPI Sequence Block is an exception.)
57c349dbc7Sjsg *
58c349dbc7Sjsg * The driver parses the VBT during load. The relevant information is stored in
59c349dbc7Sjsg * driver private data for ease of use, and the actual VBT is not read after
60c349dbc7Sjsg * that.
61c349dbc7Sjsg */
62c349dbc7Sjsg
63c349dbc7Sjsg /* Wrapper for VBT child device config */
645ca02815Sjsg struct intel_bios_encoder_data {
655ca02815Sjsg struct drm_i915_private *i915;
665ca02815Sjsg
67c349dbc7Sjsg struct child_device_config child;
68c349dbc7Sjsg struct dsc_compression_parameters_entry *dsc;
69c349dbc7Sjsg struct list_head node;
70c349dbc7Sjsg };
71c349dbc7Sjsg
72c349dbc7Sjsg #define SLAVE_ADDR1 0x70
73c349dbc7Sjsg #define SLAVE_ADDR2 0x72
74c349dbc7Sjsg
75c349dbc7Sjsg /* Get BDB block size given a pointer to Block ID. */
_get_blocksize(const u8 * block_base)76c349dbc7Sjsg static u32 _get_blocksize(const u8 *block_base)
77c349dbc7Sjsg {
78c349dbc7Sjsg /* The MIPI Sequence Block v3+ has a separate size field. */
79c349dbc7Sjsg if (*block_base == BDB_MIPI_SEQUENCE && *(block_base + 3) >= 3)
80c349dbc7Sjsg return *((const u32 *)(block_base + 4));
81c349dbc7Sjsg else
82c349dbc7Sjsg return *((const u16 *)(block_base + 1));
83c349dbc7Sjsg }
84c349dbc7Sjsg
85c349dbc7Sjsg /* Get BDB block size give a pointer to data after Block ID and Block Size. */
get_blocksize(const void * block_data)86c349dbc7Sjsg static u32 get_blocksize(const void *block_data)
87c349dbc7Sjsg {
88c349dbc7Sjsg return _get_blocksize(block_data - 3);
89c349dbc7Sjsg }
90c349dbc7Sjsg
91c349dbc7Sjsg static const void *
find_raw_section(const void * _bdb,enum bdb_block_id section_id)921bb76ff1Sjsg find_raw_section(const void *_bdb, enum bdb_block_id section_id)
93c349dbc7Sjsg {
94c349dbc7Sjsg const struct bdb_header *bdb = _bdb;
95c349dbc7Sjsg const u8 *base = _bdb;
96c349dbc7Sjsg int index = 0;
97c349dbc7Sjsg u32 total, current_size;
98c349dbc7Sjsg enum bdb_block_id current_id;
99c349dbc7Sjsg
100c349dbc7Sjsg /* skip to first section */
101c349dbc7Sjsg index += bdb->header_size;
102c349dbc7Sjsg total = bdb->bdb_size;
103c349dbc7Sjsg
104c349dbc7Sjsg /* walk the sections looking for section_id */
105c349dbc7Sjsg while (index + 3 < total) {
106c349dbc7Sjsg current_id = *(base + index);
107c349dbc7Sjsg current_size = _get_blocksize(base + index);
108c349dbc7Sjsg index += 3;
109c349dbc7Sjsg
110c349dbc7Sjsg if (index + current_size > total)
111c349dbc7Sjsg return NULL;
112c349dbc7Sjsg
113c349dbc7Sjsg if (current_id == section_id)
114c349dbc7Sjsg return base + index;
115c349dbc7Sjsg
116c349dbc7Sjsg index += current_size;
117c349dbc7Sjsg }
118c349dbc7Sjsg
119c349dbc7Sjsg return NULL;
120c349dbc7Sjsg }
121c349dbc7Sjsg
1221bb76ff1Sjsg /*
1231bb76ff1Sjsg * Offset from the start of BDB to the start of the
1241bb76ff1Sjsg * block data (just past the block header).
1251bb76ff1Sjsg */
raw_block_offset(const void * bdb,enum bdb_block_id section_id)1261bb76ff1Sjsg static u32 raw_block_offset(const void *bdb, enum bdb_block_id section_id)
1271bb76ff1Sjsg {
1281bb76ff1Sjsg const void *block;
1291bb76ff1Sjsg
1301bb76ff1Sjsg block = find_raw_section(bdb, section_id);
1311bb76ff1Sjsg if (!block)
1321bb76ff1Sjsg return 0;
1331bb76ff1Sjsg
1341bb76ff1Sjsg return block - bdb;
1351bb76ff1Sjsg }
1361bb76ff1Sjsg
1371bb76ff1Sjsg struct bdb_block_entry {
1381bb76ff1Sjsg struct list_head node;
1391bb76ff1Sjsg enum bdb_block_id section_id;
1401bb76ff1Sjsg u8 data[];
1411bb76ff1Sjsg };
1421bb76ff1Sjsg
1431bb76ff1Sjsg static const void *
bdb_find_section(struct drm_i915_private * i915,enum bdb_block_id section_id)144f005ef32Sjsg bdb_find_section(struct drm_i915_private *i915,
1451bb76ff1Sjsg enum bdb_block_id section_id)
1461bb76ff1Sjsg {
1471bb76ff1Sjsg struct bdb_block_entry *entry;
1481bb76ff1Sjsg
1491bb76ff1Sjsg list_for_each_entry(entry, &i915->display.vbt.bdb_blocks, node) {
1501bb76ff1Sjsg if (entry->section_id == section_id)
1511bb76ff1Sjsg return entry->data + 3;
1521bb76ff1Sjsg }
1531bb76ff1Sjsg
1541bb76ff1Sjsg return NULL;
1551bb76ff1Sjsg }
1561bb76ff1Sjsg
1571bb76ff1Sjsg static const struct {
1581bb76ff1Sjsg enum bdb_block_id section_id;
1591bb76ff1Sjsg size_t min_size;
1601bb76ff1Sjsg } bdb_blocks[] = {
1611bb76ff1Sjsg { .section_id = BDB_GENERAL_FEATURES,
1621bb76ff1Sjsg .min_size = sizeof(struct bdb_general_features), },
1631bb76ff1Sjsg { .section_id = BDB_GENERAL_DEFINITIONS,
1641bb76ff1Sjsg .min_size = sizeof(struct bdb_general_definitions), },
1651bb76ff1Sjsg { .section_id = BDB_PSR,
1661bb76ff1Sjsg .min_size = sizeof(struct bdb_psr), },
1671bb76ff1Sjsg { .section_id = BDB_DRIVER_FEATURES,
1681bb76ff1Sjsg .min_size = sizeof(struct bdb_driver_features), },
1691bb76ff1Sjsg { .section_id = BDB_SDVO_LVDS_OPTIONS,
1701bb76ff1Sjsg .min_size = sizeof(struct bdb_sdvo_lvds_options), },
1711bb76ff1Sjsg { .section_id = BDB_SDVO_PANEL_DTDS,
1721bb76ff1Sjsg .min_size = sizeof(struct bdb_sdvo_panel_dtds), },
1731bb76ff1Sjsg { .section_id = BDB_EDP,
1741bb76ff1Sjsg .min_size = sizeof(struct bdb_edp), },
1751bb76ff1Sjsg { .section_id = BDB_LVDS_OPTIONS,
1761bb76ff1Sjsg .min_size = sizeof(struct bdb_lvds_options), },
1771bb76ff1Sjsg /*
1781bb76ff1Sjsg * BDB_LVDS_LFP_DATA depends on BDB_LVDS_LFP_DATA_PTRS,
1791bb76ff1Sjsg * so keep the two ordered.
1801bb76ff1Sjsg */
1811bb76ff1Sjsg { .section_id = BDB_LVDS_LFP_DATA_PTRS,
1821bb76ff1Sjsg .min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), },
1831bb76ff1Sjsg { .section_id = BDB_LVDS_LFP_DATA,
1841bb76ff1Sjsg .min_size = 0, /* special case */ },
1851bb76ff1Sjsg { .section_id = BDB_LVDS_BACKLIGHT,
1861bb76ff1Sjsg .min_size = sizeof(struct bdb_lfp_backlight_data), },
1871bb76ff1Sjsg { .section_id = BDB_LFP_POWER,
1881bb76ff1Sjsg .min_size = sizeof(struct bdb_lfp_power), },
1891bb76ff1Sjsg { .section_id = BDB_MIPI_CONFIG,
1901bb76ff1Sjsg .min_size = sizeof(struct bdb_mipi_config), },
1911bb76ff1Sjsg { .section_id = BDB_MIPI_SEQUENCE,
1921bb76ff1Sjsg .min_size = sizeof(struct bdb_mipi_sequence) },
1931bb76ff1Sjsg { .section_id = BDB_COMPRESSION_PARAMETERS,
1941bb76ff1Sjsg .min_size = sizeof(struct bdb_compression_parameters), },
1951bb76ff1Sjsg { .section_id = BDB_GENERIC_DTD,
1961bb76ff1Sjsg .min_size = sizeof(struct bdb_generic_dtd), },
1971bb76ff1Sjsg };
1981bb76ff1Sjsg
lfp_data_min_size(struct drm_i915_private * i915)1991bb76ff1Sjsg static size_t lfp_data_min_size(struct drm_i915_private *i915)
2001bb76ff1Sjsg {
2011bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs;
2021bb76ff1Sjsg size_t size;
2031bb76ff1Sjsg
204f005ef32Sjsg ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
2051bb76ff1Sjsg if (!ptrs)
2061bb76ff1Sjsg return 0;
2071bb76ff1Sjsg
2081bb76ff1Sjsg size = sizeof(struct bdb_lvds_lfp_data);
2091bb76ff1Sjsg if (ptrs->panel_name.table_size)
2101bb76ff1Sjsg size = max(size, ptrs->panel_name.offset +
2111bb76ff1Sjsg sizeof(struct bdb_lvds_lfp_data_tail));
2121bb76ff1Sjsg
2131bb76ff1Sjsg return size;
2141bb76ff1Sjsg }
2151bb76ff1Sjsg
validate_lfp_data_ptrs(const void * bdb,const struct bdb_lvds_lfp_data_ptrs * ptrs)2161bb76ff1Sjsg static bool validate_lfp_data_ptrs(const void *bdb,
2171bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs)
2181bb76ff1Sjsg {
2191bb76ff1Sjsg int fp_timing_size, dvo_timing_size, panel_pnp_id_size, panel_name_size;
2201bb76ff1Sjsg int data_block_size, lfp_data_size;
2211bb76ff1Sjsg const void *data_block;
2221bb76ff1Sjsg int i;
2231bb76ff1Sjsg
2241bb76ff1Sjsg data_block = find_raw_section(bdb, BDB_LVDS_LFP_DATA);
2251bb76ff1Sjsg if (!data_block)
2261bb76ff1Sjsg return false;
2271bb76ff1Sjsg
2281bb76ff1Sjsg data_block_size = get_blocksize(data_block);
2291bb76ff1Sjsg if (data_block_size == 0)
2301bb76ff1Sjsg return false;
2311bb76ff1Sjsg
2321bb76ff1Sjsg /* always 3 indicating the presence of fp_timing+dvo_timing+panel_pnp_id */
2331bb76ff1Sjsg if (ptrs->lvds_entries != 3)
2341bb76ff1Sjsg return false;
2351bb76ff1Sjsg
2361bb76ff1Sjsg fp_timing_size = ptrs->ptr[0].fp_timing.table_size;
2371bb76ff1Sjsg dvo_timing_size = ptrs->ptr[0].dvo_timing.table_size;
2381bb76ff1Sjsg panel_pnp_id_size = ptrs->ptr[0].panel_pnp_id.table_size;
2391bb76ff1Sjsg panel_name_size = ptrs->panel_name.table_size;
2401bb76ff1Sjsg
2411bb76ff1Sjsg /* fp_timing has variable size */
2421bb76ff1Sjsg if (fp_timing_size < 32 ||
2431bb76ff1Sjsg dvo_timing_size != sizeof(struct lvds_dvo_timing) ||
2441bb76ff1Sjsg panel_pnp_id_size != sizeof(struct lvds_pnp_id))
2451bb76ff1Sjsg return false;
2461bb76ff1Sjsg
2471bb76ff1Sjsg /* panel_name is not present in old VBTs */
2481bb76ff1Sjsg if (panel_name_size != 0 &&
2491bb76ff1Sjsg panel_name_size != sizeof(struct lvds_lfp_panel_name))
2501bb76ff1Sjsg return false;
2511bb76ff1Sjsg
2521bb76ff1Sjsg lfp_data_size = ptrs->ptr[1].fp_timing.offset - ptrs->ptr[0].fp_timing.offset;
2531bb76ff1Sjsg if (16 * lfp_data_size > data_block_size)
2541bb76ff1Sjsg return false;
2551bb76ff1Sjsg
2561bb76ff1Sjsg /* make sure the table entries have uniform size */
2571bb76ff1Sjsg for (i = 1; i < 16; i++) {
2581bb76ff1Sjsg if (ptrs->ptr[i].fp_timing.table_size != fp_timing_size ||
2591bb76ff1Sjsg ptrs->ptr[i].dvo_timing.table_size != dvo_timing_size ||
2601bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.table_size != panel_pnp_id_size)
2611bb76ff1Sjsg return false;
2621bb76ff1Sjsg
2631bb76ff1Sjsg if (ptrs->ptr[i].fp_timing.offset - ptrs->ptr[i-1].fp_timing.offset != lfp_data_size ||
2641bb76ff1Sjsg ptrs->ptr[i].dvo_timing.offset - ptrs->ptr[i-1].dvo_timing.offset != lfp_data_size ||
2651bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.offset - ptrs->ptr[i-1].panel_pnp_id.offset != lfp_data_size)
2661bb76ff1Sjsg return false;
2671bb76ff1Sjsg }
2681bb76ff1Sjsg
2691bb76ff1Sjsg /*
2701bb76ff1Sjsg * Except for vlv/chv machines all real VBTs seem to have 6
2711bb76ff1Sjsg * unaccounted bytes in the fp_timing table. And it doesn't
2721bb76ff1Sjsg * appear to be a really intentional hole as the fp_timing
2731bb76ff1Sjsg * 0xffff terminator is always within those 6 missing bytes.
2741bb76ff1Sjsg */
2751bb76ff1Sjsg if (fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size == lfp_data_size)
2761bb76ff1Sjsg fp_timing_size += 6;
2771bb76ff1Sjsg
2781bb76ff1Sjsg if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size)
2791bb76ff1Sjsg return false;
2801bb76ff1Sjsg
2811bb76ff1Sjsg if (ptrs->ptr[0].fp_timing.offset + fp_timing_size != ptrs->ptr[0].dvo_timing.offset ||
2821bb76ff1Sjsg ptrs->ptr[0].dvo_timing.offset + dvo_timing_size != ptrs->ptr[0].panel_pnp_id.offset ||
2831bb76ff1Sjsg ptrs->ptr[0].panel_pnp_id.offset + panel_pnp_id_size != lfp_data_size)
2841bb76ff1Sjsg return false;
2851bb76ff1Sjsg
2861bb76ff1Sjsg /* make sure the tables fit inside the data block */
2871bb76ff1Sjsg for (i = 0; i < 16; i++) {
2881bb76ff1Sjsg if (ptrs->ptr[i].fp_timing.offset + fp_timing_size > data_block_size ||
2891bb76ff1Sjsg ptrs->ptr[i].dvo_timing.offset + dvo_timing_size > data_block_size ||
2901bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.offset + panel_pnp_id_size > data_block_size)
2911bb76ff1Sjsg return false;
2921bb76ff1Sjsg }
2931bb76ff1Sjsg
2941bb76ff1Sjsg if (ptrs->panel_name.offset + 16 * panel_name_size > data_block_size)
2951bb76ff1Sjsg return false;
2961bb76ff1Sjsg
2971bb76ff1Sjsg /* make sure fp_timing terminators are present at expected locations */
2981bb76ff1Sjsg for (i = 0; i < 16; i++) {
2991bb76ff1Sjsg const u16 *t = data_block + ptrs->ptr[i].fp_timing.offset +
3001bb76ff1Sjsg fp_timing_size - 2;
3011bb76ff1Sjsg
3021bb76ff1Sjsg if (*t != 0xffff)
3031bb76ff1Sjsg return false;
3041bb76ff1Sjsg }
3051bb76ff1Sjsg
3061bb76ff1Sjsg return true;
3071bb76ff1Sjsg }
3081bb76ff1Sjsg
3091bb76ff1Sjsg /* make the data table offsets relative to the data block */
fixup_lfp_data_ptrs(const void * bdb,void * ptrs_block)3101bb76ff1Sjsg static bool fixup_lfp_data_ptrs(const void *bdb, void *ptrs_block)
3111bb76ff1Sjsg {
3121bb76ff1Sjsg struct bdb_lvds_lfp_data_ptrs *ptrs = ptrs_block;
3131bb76ff1Sjsg u32 offset;
3141bb76ff1Sjsg int i;
3151bb76ff1Sjsg
3161bb76ff1Sjsg offset = raw_block_offset(bdb, BDB_LVDS_LFP_DATA);
3171bb76ff1Sjsg
3181bb76ff1Sjsg for (i = 0; i < 16; i++) {
3191bb76ff1Sjsg if (ptrs->ptr[i].fp_timing.offset < offset ||
3201bb76ff1Sjsg ptrs->ptr[i].dvo_timing.offset < offset ||
3211bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.offset < offset)
3221bb76ff1Sjsg return false;
3231bb76ff1Sjsg
3241bb76ff1Sjsg ptrs->ptr[i].fp_timing.offset -= offset;
3251bb76ff1Sjsg ptrs->ptr[i].dvo_timing.offset -= offset;
3261bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.offset -= offset;
3271bb76ff1Sjsg }
3281bb76ff1Sjsg
3291bb76ff1Sjsg if (ptrs->panel_name.table_size) {
3301bb76ff1Sjsg if (ptrs->panel_name.offset < offset)
3311bb76ff1Sjsg return false;
3321bb76ff1Sjsg
3331bb76ff1Sjsg ptrs->panel_name.offset -= offset;
3341bb76ff1Sjsg }
3351bb76ff1Sjsg
3361bb76ff1Sjsg return validate_lfp_data_ptrs(bdb, ptrs);
3371bb76ff1Sjsg }
3381bb76ff1Sjsg
make_lfp_data_ptr(struct lvds_lfp_data_ptr_table * table,int table_size,int total_size)3391bb76ff1Sjsg static int make_lfp_data_ptr(struct lvds_lfp_data_ptr_table *table,
3401bb76ff1Sjsg int table_size, int total_size)
3411bb76ff1Sjsg {
3421bb76ff1Sjsg if (total_size < table_size)
3431bb76ff1Sjsg return total_size;
3441bb76ff1Sjsg
3451bb76ff1Sjsg table->table_size = table_size;
3461bb76ff1Sjsg table->offset = total_size - table_size;
3471bb76ff1Sjsg
3481bb76ff1Sjsg return total_size - table_size;
3491bb76ff1Sjsg }
3501bb76ff1Sjsg
next_lfp_data_ptr(struct lvds_lfp_data_ptr_table * next,const struct lvds_lfp_data_ptr_table * prev,int size)3511bb76ff1Sjsg static void next_lfp_data_ptr(struct lvds_lfp_data_ptr_table *next,
3521bb76ff1Sjsg const struct lvds_lfp_data_ptr_table *prev,
3531bb76ff1Sjsg int size)
3541bb76ff1Sjsg {
3551bb76ff1Sjsg next->table_size = prev->table_size;
3561bb76ff1Sjsg next->offset = prev->offset + size;
3571bb76ff1Sjsg }
3581bb76ff1Sjsg
generate_lfp_data_ptrs(struct drm_i915_private * i915,const void * bdb)3591bb76ff1Sjsg static void *generate_lfp_data_ptrs(struct drm_i915_private *i915,
3601bb76ff1Sjsg const void *bdb)
3611bb76ff1Sjsg {
3621bb76ff1Sjsg int i, size, table_size, block_size, offset, fp_timing_size;
3631bb76ff1Sjsg struct bdb_lvds_lfp_data_ptrs *ptrs;
3641bb76ff1Sjsg const void *block;
3651bb76ff1Sjsg void *ptrs_block;
3661bb76ff1Sjsg
3671bb76ff1Sjsg /*
3681bb76ff1Sjsg * The hardcoded fp_timing_size is only valid for
3691bb76ff1Sjsg * modernish VBTs. All older VBTs definitely should
3701bb76ff1Sjsg * include block 41 and thus we don't need to
3711bb76ff1Sjsg * generate one.
3721bb76ff1Sjsg */
3731bb76ff1Sjsg if (i915->display.vbt.version < 155)
3741bb76ff1Sjsg return NULL;
3751bb76ff1Sjsg
3761bb76ff1Sjsg fp_timing_size = 38;
3771bb76ff1Sjsg
3781bb76ff1Sjsg block = find_raw_section(bdb, BDB_LVDS_LFP_DATA);
3791bb76ff1Sjsg if (!block)
3801bb76ff1Sjsg return NULL;
3811bb76ff1Sjsg
3821bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Generating LFP data table pointers\n");
3831bb76ff1Sjsg
3841bb76ff1Sjsg block_size = get_blocksize(block);
3851bb76ff1Sjsg
3861bb76ff1Sjsg size = fp_timing_size + sizeof(struct lvds_dvo_timing) +
3871bb76ff1Sjsg sizeof(struct lvds_pnp_id);
3881bb76ff1Sjsg if (size * 16 > block_size)
3891bb76ff1Sjsg return NULL;
3901bb76ff1Sjsg
3911bb76ff1Sjsg ptrs_block = kzalloc(sizeof(*ptrs) + 3, GFP_KERNEL);
3921bb76ff1Sjsg if (!ptrs_block)
3931bb76ff1Sjsg return NULL;
3941bb76ff1Sjsg
3951bb76ff1Sjsg *(u8 *)(ptrs_block + 0) = BDB_LVDS_LFP_DATA_PTRS;
3961bb76ff1Sjsg *(u16 *)(ptrs_block + 1) = sizeof(*ptrs);
3971bb76ff1Sjsg ptrs = ptrs_block + 3;
3981bb76ff1Sjsg
3991bb76ff1Sjsg table_size = sizeof(struct lvds_pnp_id);
4001bb76ff1Sjsg size = make_lfp_data_ptr(&ptrs->ptr[0].panel_pnp_id, table_size, size);
4011bb76ff1Sjsg
4021bb76ff1Sjsg table_size = sizeof(struct lvds_dvo_timing);
4031bb76ff1Sjsg size = make_lfp_data_ptr(&ptrs->ptr[0].dvo_timing, table_size, size);
4041bb76ff1Sjsg
4051bb76ff1Sjsg table_size = fp_timing_size;
4061bb76ff1Sjsg size = make_lfp_data_ptr(&ptrs->ptr[0].fp_timing, table_size, size);
4071bb76ff1Sjsg
4081bb76ff1Sjsg if (ptrs->ptr[0].fp_timing.table_size)
4091bb76ff1Sjsg ptrs->lvds_entries++;
4101bb76ff1Sjsg if (ptrs->ptr[0].dvo_timing.table_size)
4111bb76ff1Sjsg ptrs->lvds_entries++;
4121bb76ff1Sjsg if (ptrs->ptr[0].panel_pnp_id.table_size)
4131bb76ff1Sjsg ptrs->lvds_entries++;
4141bb76ff1Sjsg
4151bb76ff1Sjsg if (size != 0 || ptrs->lvds_entries != 3) {
4161bb76ff1Sjsg kfree(ptrs_block);
4171bb76ff1Sjsg return NULL;
4181bb76ff1Sjsg }
4191bb76ff1Sjsg
4201bb76ff1Sjsg size = fp_timing_size + sizeof(struct lvds_dvo_timing) +
4211bb76ff1Sjsg sizeof(struct lvds_pnp_id);
4221bb76ff1Sjsg for (i = 1; i < 16; i++) {
4231bb76ff1Sjsg next_lfp_data_ptr(&ptrs->ptr[i].fp_timing, &ptrs->ptr[i-1].fp_timing, size);
4241bb76ff1Sjsg next_lfp_data_ptr(&ptrs->ptr[i].dvo_timing, &ptrs->ptr[i-1].dvo_timing, size);
4251bb76ff1Sjsg next_lfp_data_ptr(&ptrs->ptr[i].panel_pnp_id, &ptrs->ptr[i-1].panel_pnp_id, size);
4261bb76ff1Sjsg }
4271bb76ff1Sjsg
4281bb76ff1Sjsg table_size = sizeof(struct lvds_lfp_panel_name);
4291bb76ff1Sjsg
4301bb76ff1Sjsg if (16 * (size + table_size) <= block_size) {
4311bb76ff1Sjsg ptrs->panel_name.table_size = table_size;
4321bb76ff1Sjsg ptrs->panel_name.offset = size * 16;
4331bb76ff1Sjsg }
4341bb76ff1Sjsg
4351bb76ff1Sjsg offset = block - bdb;
4361bb76ff1Sjsg
4371bb76ff1Sjsg for (i = 0; i < 16; i++) {
4381bb76ff1Sjsg ptrs->ptr[i].fp_timing.offset += offset;
4391bb76ff1Sjsg ptrs->ptr[i].dvo_timing.offset += offset;
4401bb76ff1Sjsg ptrs->ptr[i].panel_pnp_id.offset += offset;
4411bb76ff1Sjsg }
4421bb76ff1Sjsg
4431bb76ff1Sjsg if (ptrs->panel_name.table_size)
4441bb76ff1Sjsg ptrs->panel_name.offset += offset;
4451bb76ff1Sjsg
4461bb76ff1Sjsg return ptrs_block;
4471bb76ff1Sjsg }
4481bb76ff1Sjsg
4491bb76ff1Sjsg static void
init_bdb_block(struct drm_i915_private * i915,const void * bdb,enum bdb_block_id section_id,size_t min_size)4501bb76ff1Sjsg init_bdb_block(struct drm_i915_private *i915,
4511bb76ff1Sjsg const void *bdb, enum bdb_block_id section_id,
4521bb76ff1Sjsg size_t min_size)
4531bb76ff1Sjsg {
4541bb76ff1Sjsg struct bdb_block_entry *entry;
4551bb76ff1Sjsg void *temp_block = NULL;
4561bb76ff1Sjsg const void *block;
4571bb76ff1Sjsg size_t block_size;
4581bb76ff1Sjsg
4591bb76ff1Sjsg block = find_raw_section(bdb, section_id);
4601bb76ff1Sjsg
4611bb76ff1Sjsg /* Modern VBTs lack the LFP data table pointers block, make one up */
4621bb76ff1Sjsg if (!block && section_id == BDB_LVDS_LFP_DATA_PTRS) {
4631bb76ff1Sjsg temp_block = generate_lfp_data_ptrs(i915, bdb);
4641bb76ff1Sjsg if (temp_block)
4651bb76ff1Sjsg block = temp_block + 3;
4661bb76ff1Sjsg }
4671bb76ff1Sjsg if (!block)
4681bb76ff1Sjsg return;
4691bb76ff1Sjsg
4701bb76ff1Sjsg drm_WARN(&i915->drm, min_size == 0,
4711bb76ff1Sjsg "Block %d min_size is zero\n", section_id);
4721bb76ff1Sjsg
4731bb76ff1Sjsg block_size = get_blocksize(block);
4741bb76ff1Sjsg
4751bb76ff1Sjsg /*
4761bb76ff1Sjsg * Version number and new block size are considered
4771bb76ff1Sjsg * part of the header for MIPI sequenece block v3+.
4781bb76ff1Sjsg */
4791bb76ff1Sjsg if (section_id == BDB_MIPI_SEQUENCE && *(const u8 *)block >= 3)
4801bb76ff1Sjsg block_size += 5;
4811bb76ff1Sjsg
4821bb76ff1Sjsg entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
4831bb76ff1Sjsg GFP_KERNEL);
4841bb76ff1Sjsg if (!entry) {
4851bb76ff1Sjsg kfree(temp_block);
4861bb76ff1Sjsg return;
4871bb76ff1Sjsg }
4881bb76ff1Sjsg
4891bb76ff1Sjsg entry->section_id = section_id;
4901bb76ff1Sjsg memcpy(entry->data, block - 3, block_size + 3);
4911bb76ff1Sjsg
4921bb76ff1Sjsg kfree(temp_block);
4931bb76ff1Sjsg
4941bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n",
4951bb76ff1Sjsg section_id, block_size, min_size);
4961bb76ff1Sjsg
4971bb76ff1Sjsg if (section_id == BDB_LVDS_LFP_DATA_PTRS &&
4981bb76ff1Sjsg !fixup_lfp_data_ptrs(bdb, entry->data + 3)) {
4991bb76ff1Sjsg drm_err(&i915->drm, "VBT has malformed LFP data table pointers\n");
5001bb76ff1Sjsg kfree(entry);
5011bb76ff1Sjsg return;
5021bb76ff1Sjsg }
5031bb76ff1Sjsg
5041bb76ff1Sjsg list_add_tail(&entry->node, &i915->display.vbt.bdb_blocks);
5051bb76ff1Sjsg }
5061bb76ff1Sjsg
init_bdb_blocks(struct drm_i915_private * i915,const void * bdb)5071bb76ff1Sjsg static void init_bdb_blocks(struct drm_i915_private *i915,
5081bb76ff1Sjsg const void *bdb)
5091bb76ff1Sjsg {
5101bb76ff1Sjsg int i;
5111bb76ff1Sjsg
5121bb76ff1Sjsg for (i = 0; i < ARRAY_SIZE(bdb_blocks); i++) {
5131bb76ff1Sjsg enum bdb_block_id section_id = bdb_blocks[i].section_id;
5141bb76ff1Sjsg size_t min_size = bdb_blocks[i].min_size;
5151bb76ff1Sjsg
5161bb76ff1Sjsg if (section_id == BDB_LVDS_LFP_DATA)
5171bb76ff1Sjsg min_size = lfp_data_min_size(i915);
5181bb76ff1Sjsg
5191bb76ff1Sjsg init_bdb_block(i915, bdb, section_id, min_size);
5201bb76ff1Sjsg }
5211bb76ff1Sjsg }
5221bb76ff1Sjsg
523c349dbc7Sjsg static void
fill_detail_timing_data(struct drm_display_mode * panel_fixed_mode,const struct lvds_dvo_timing * dvo_timing)524c349dbc7Sjsg fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
525c349dbc7Sjsg const struct lvds_dvo_timing *dvo_timing)
526c349dbc7Sjsg {
527c349dbc7Sjsg panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
528c349dbc7Sjsg dvo_timing->hactive_lo;
529c349dbc7Sjsg panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
530c349dbc7Sjsg ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
531c349dbc7Sjsg panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
532c349dbc7Sjsg ((dvo_timing->hsync_pulse_width_hi << 8) |
533c349dbc7Sjsg dvo_timing->hsync_pulse_width_lo);
534c349dbc7Sjsg panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
535c349dbc7Sjsg ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
536c349dbc7Sjsg
537c349dbc7Sjsg panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
538c349dbc7Sjsg dvo_timing->vactive_lo;
539c349dbc7Sjsg panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
540c349dbc7Sjsg ((dvo_timing->vsync_off_hi << 4) | dvo_timing->vsync_off_lo);
541c349dbc7Sjsg panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
542c349dbc7Sjsg ((dvo_timing->vsync_pulse_width_hi << 4) |
543c349dbc7Sjsg dvo_timing->vsync_pulse_width_lo);
544c349dbc7Sjsg panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
545c349dbc7Sjsg ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
546c349dbc7Sjsg panel_fixed_mode->clock = dvo_timing->clock * 10;
547c349dbc7Sjsg panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
548c349dbc7Sjsg
549c349dbc7Sjsg if (dvo_timing->hsync_positive)
550c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
551c349dbc7Sjsg else
552c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
553c349dbc7Sjsg
554c349dbc7Sjsg if (dvo_timing->vsync_positive)
555c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
556c349dbc7Sjsg else
557c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
558c349dbc7Sjsg
559c349dbc7Sjsg panel_fixed_mode->width_mm = (dvo_timing->himage_hi << 8) |
560c349dbc7Sjsg dvo_timing->himage_lo;
561c349dbc7Sjsg panel_fixed_mode->height_mm = (dvo_timing->vimage_hi << 8) |
562c349dbc7Sjsg dvo_timing->vimage_lo;
563c349dbc7Sjsg
564c349dbc7Sjsg /* Some VBTs have bogus h/vtotal values */
565c349dbc7Sjsg if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
566c349dbc7Sjsg panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
567c349dbc7Sjsg if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
568c349dbc7Sjsg panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
569c349dbc7Sjsg
570c349dbc7Sjsg drm_mode_set_name(panel_fixed_mode);
571c349dbc7Sjsg }
572c349dbc7Sjsg
573c349dbc7Sjsg static const struct lvds_dvo_timing *
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data * data,const struct bdb_lvds_lfp_data_ptrs * ptrs,int index)5741bb76ff1Sjsg get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *data,
575c349dbc7Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs,
576c349dbc7Sjsg int index)
577c349dbc7Sjsg {
5781bb76ff1Sjsg return (const void *)data + ptrs->ptr[index].dvo_timing.offset;
5791bb76ff1Sjsg }
580c349dbc7Sjsg
5811bb76ff1Sjsg static const struct lvds_fp_timing *
get_lvds_fp_timing(const struct bdb_lvds_lfp_data * data,const struct bdb_lvds_lfp_data_ptrs * ptrs,int index)5821bb76ff1Sjsg get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data,
5831bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs,
5841bb76ff1Sjsg int index)
5851bb76ff1Sjsg {
5861bb76ff1Sjsg return (const void *)data + ptrs->ptr[index].fp_timing.offset;
5871bb76ff1Sjsg }
5881bb76ff1Sjsg
5891bb76ff1Sjsg static const struct lvds_pnp_id *
get_lvds_pnp_id(const struct bdb_lvds_lfp_data * data,const struct bdb_lvds_lfp_data_ptrs * ptrs,int index)5901bb76ff1Sjsg get_lvds_pnp_id(const struct bdb_lvds_lfp_data *data,
5911bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs,
5921bb76ff1Sjsg int index)
5931bb76ff1Sjsg {
5941bb76ff1Sjsg return (const void *)data + ptrs->ptr[index].panel_pnp_id.offset;
5951bb76ff1Sjsg }
5961bb76ff1Sjsg
5971bb76ff1Sjsg static const struct bdb_lvds_lfp_data_tail *
get_lfp_data_tail(const struct bdb_lvds_lfp_data * data,const struct bdb_lvds_lfp_data_ptrs * ptrs)5981bb76ff1Sjsg get_lfp_data_tail(const struct bdb_lvds_lfp_data *data,
5991bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs)
6001bb76ff1Sjsg {
6011bb76ff1Sjsg if (ptrs->panel_name.table_size)
6021bb76ff1Sjsg return (const void *)data + ptrs->panel_name.offset;
6031bb76ff1Sjsg else
604c349dbc7Sjsg return NULL;
6051bb76ff1Sjsg }
6061bb76ff1Sjsg
dump_pnp_id(struct drm_i915_private * i915,const struct lvds_pnp_id * pnp_id,const char * name)6071bb76ff1Sjsg static void dump_pnp_id(struct drm_i915_private *i915,
6081bb76ff1Sjsg const struct lvds_pnp_id *pnp_id,
6091bb76ff1Sjsg const char *name)
6101bb76ff1Sjsg {
6111bb76ff1Sjsg u16 mfg_name = be16_to_cpu((__force __be16)pnp_id->mfg_name);
6121bb76ff1Sjsg char vend[4];
6131bb76ff1Sjsg
6141bb76ff1Sjsg drm_dbg_kms(&i915->drm, "%s PNPID mfg: %s (0x%x), prod: %u, serial: %u, week: %d, year: %d\n",
6151bb76ff1Sjsg name, drm_edid_decode_mfg_id(mfg_name, vend),
6161bb76ff1Sjsg pnp_id->mfg_name, pnp_id->product_code, pnp_id->serial,
6171bb76ff1Sjsg pnp_id->mfg_week, pnp_id->mfg_year + 1990);
6181bb76ff1Sjsg }
6191bb76ff1Sjsg
opregion_get_panel_type(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)6201bb76ff1Sjsg static int opregion_get_panel_type(struct drm_i915_private *i915,
6211bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
622f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback)
6231bb76ff1Sjsg {
6241bb76ff1Sjsg return intel_opregion_get_panel_type(i915);
6251bb76ff1Sjsg }
6261bb76ff1Sjsg
vbt_get_panel_type(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)6271bb76ff1Sjsg static int vbt_get_panel_type(struct drm_i915_private *i915,
6281bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
629f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback)
6301bb76ff1Sjsg {
6311bb76ff1Sjsg const struct bdb_lvds_options *lvds_options;
6321bb76ff1Sjsg
633f005ef32Sjsg lvds_options = bdb_find_section(i915, BDB_LVDS_OPTIONS);
6341bb76ff1Sjsg if (!lvds_options)
6351bb76ff1Sjsg return -1;
6361bb76ff1Sjsg
6371bb76ff1Sjsg if (lvds_options->panel_type > 0xf &&
6381bb76ff1Sjsg lvds_options->panel_type != 0xff) {
6391bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Invalid VBT panel type 0x%x\n",
6401bb76ff1Sjsg lvds_options->panel_type);
6411bb76ff1Sjsg return -1;
6421bb76ff1Sjsg }
6431bb76ff1Sjsg
6441bb76ff1Sjsg if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2)
6451bb76ff1Sjsg return lvds_options->panel_type2;
6461bb76ff1Sjsg
6471bb76ff1Sjsg drm_WARN_ON(&i915->drm, devdata && devdata->child.handle != DEVICE_HANDLE_LFP1);
6481bb76ff1Sjsg
6491bb76ff1Sjsg return lvds_options->panel_type;
6501bb76ff1Sjsg }
6511bb76ff1Sjsg
pnpid_get_panel_type(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)6521bb76ff1Sjsg static int pnpid_get_panel_type(struct drm_i915_private *i915,
6531bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
654f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback)
6551bb76ff1Sjsg {
6561bb76ff1Sjsg const struct bdb_lvds_lfp_data *data;
6571bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs;
6581bb76ff1Sjsg const struct lvds_pnp_id *edid_id;
6591bb76ff1Sjsg struct lvds_pnp_id edid_id_nodate;
660f005ef32Sjsg const struct edid *edid = drm_edid_raw(drm_edid); /* FIXME */
6611bb76ff1Sjsg int i, best = -1;
6621bb76ff1Sjsg
6631bb76ff1Sjsg if (!edid)
6641bb76ff1Sjsg return -1;
6651bb76ff1Sjsg
6661bb76ff1Sjsg edid_id = (const void *)&edid->mfg_id[0];
6671bb76ff1Sjsg
6681bb76ff1Sjsg edid_id_nodate = *edid_id;
6691bb76ff1Sjsg edid_id_nodate.mfg_week = 0;
6701bb76ff1Sjsg edid_id_nodate.mfg_year = 0;
6711bb76ff1Sjsg
6721bb76ff1Sjsg dump_pnp_id(i915, edid_id, "EDID");
6731bb76ff1Sjsg
674f005ef32Sjsg ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
6751bb76ff1Sjsg if (!ptrs)
6761bb76ff1Sjsg return -1;
6771bb76ff1Sjsg
678f005ef32Sjsg data = bdb_find_section(i915, BDB_LVDS_LFP_DATA);
6791bb76ff1Sjsg if (!data)
6801bb76ff1Sjsg return -1;
6811bb76ff1Sjsg
6821bb76ff1Sjsg for (i = 0; i < 16; i++) {
6831bb76ff1Sjsg const struct lvds_pnp_id *vbt_id =
6841bb76ff1Sjsg get_lvds_pnp_id(data, ptrs, i);
6851bb76ff1Sjsg
6861bb76ff1Sjsg /* full match? */
6871bb76ff1Sjsg if (!memcmp(vbt_id, edid_id, sizeof(*vbt_id)))
6881bb76ff1Sjsg return i;
6891bb76ff1Sjsg
6901bb76ff1Sjsg /*
6911bb76ff1Sjsg * Accept a match w/o date if no full match is found,
6921bb76ff1Sjsg * and the VBT entry does not specify a date.
6931bb76ff1Sjsg */
6941bb76ff1Sjsg if (best < 0 &&
6951bb76ff1Sjsg !memcmp(vbt_id, &edid_id_nodate, sizeof(*vbt_id)))
6961bb76ff1Sjsg best = i;
6971bb76ff1Sjsg }
6981bb76ff1Sjsg
6991bb76ff1Sjsg return best;
7001bb76ff1Sjsg }
7011bb76ff1Sjsg
fallback_get_panel_type(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)7021bb76ff1Sjsg static int fallback_get_panel_type(struct drm_i915_private *i915,
7031bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
704f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback)
7051bb76ff1Sjsg {
70626d05183Sjsg return use_fallback ? 0 : -1;
7071bb76ff1Sjsg }
7081bb76ff1Sjsg
7091bb76ff1Sjsg enum panel_type {
7101bb76ff1Sjsg PANEL_TYPE_OPREGION,
7111bb76ff1Sjsg PANEL_TYPE_VBT,
7121bb76ff1Sjsg PANEL_TYPE_PNPID,
7131bb76ff1Sjsg PANEL_TYPE_FALLBACK,
7141bb76ff1Sjsg };
7151bb76ff1Sjsg
get_panel_type(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)7161bb76ff1Sjsg static int get_panel_type(struct drm_i915_private *i915,
7171bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
718f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback)
7191bb76ff1Sjsg {
7201bb76ff1Sjsg struct {
7211bb76ff1Sjsg const char *name;
7221bb76ff1Sjsg int (*get_panel_type)(struct drm_i915_private *i915,
7231bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
724f005ef32Sjsg const struct drm_edid *drm_edid, bool use_fallback);
7251bb76ff1Sjsg int panel_type;
7261bb76ff1Sjsg } panel_types[] = {
7271bb76ff1Sjsg [PANEL_TYPE_OPREGION] = {
7281bb76ff1Sjsg .name = "OpRegion",
7291bb76ff1Sjsg .get_panel_type = opregion_get_panel_type,
7301bb76ff1Sjsg },
7311bb76ff1Sjsg [PANEL_TYPE_VBT] = {
7321bb76ff1Sjsg .name = "VBT",
7331bb76ff1Sjsg .get_panel_type = vbt_get_panel_type,
7341bb76ff1Sjsg },
7351bb76ff1Sjsg [PANEL_TYPE_PNPID] = {
7361bb76ff1Sjsg .name = "PNPID",
7371bb76ff1Sjsg .get_panel_type = pnpid_get_panel_type,
7381bb76ff1Sjsg },
7391bb76ff1Sjsg [PANEL_TYPE_FALLBACK] = {
7401bb76ff1Sjsg .name = "fallback",
7411bb76ff1Sjsg .get_panel_type = fallback_get_panel_type,
7421bb76ff1Sjsg },
7431bb76ff1Sjsg };
7441bb76ff1Sjsg int i;
7451bb76ff1Sjsg
7461bb76ff1Sjsg for (i = 0; i < ARRAY_SIZE(panel_types); i++) {
74726d05183Sjsg panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata,
748f005ef32Sjsg drm_edid, use_fallback);
7491bb76ff1Sjsg
7501bb76ff1Sjsg drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf &&
7511bb76ff1Sjsg panel_types[i].panel_type != 0xff);
7521bb76ff1Sjsg
7531bb76ff1Sjsg if (panel_types[i].panel_type >= 0)
7541bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Panel type (%s): %d\n",
7551bb76ff1Sjsg panel_types[i].name, panel_types[i].panel_type);
7561bb76ff1Sjsg }
7571bb76ff1Sjsg
7581bb76ff1Sjsg if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0)
7591bb76ff1Sjsg i = PANEL_TYPE_OPREGION;
7601bb76ff1Sjsg else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff &&
7611bb76ff1Sjsg panel_types[PANEL_TYPE_PNPID].panel_type >= 0)
7621bb76ff1Sjsg i = PANEL_TYPE_PNPID;
7631bb76ff1Sjsg else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff &&
7641bb76ff1Sjsg panel_types[PANEL_TYPE_VBT].panel_type >= 0)
7651bb76ff1Sjsg i = PANEL_TYPE_VBT;
7661bb76ff1Sjsg else
7671bb76ff1Sjsg i = PANEL_TYPE_FALLBACK;
7681bb76ff1Sjsg
7691bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Selected panel type (%s): %d\n",
7701bb76ff1Sjsg panel_types[i].name, panel_types[i].panel_type);
7711bb76ff1Sjsg
7721bb76ff1Sjsg return panel_types[i].panel_type;
7731bb76ff1Sjsg }
7741bb76ff1Sjsg
panel_bits(unsigned int value,int panel_type,int num_bits)7751bb76ff1Sjsg static unsigned int panel_bits(unsigned int value, int panel_type, int num_bits)
7761bb76ff1Sjsg {
7771bb76ff1Sjsg return (value >> (panel_type * num_bits)) & (BIT(num_bits) - 1);
7781bb76ff1Sjsg }
7791bb76ff1Sjsg
panel_bool(unsigned int value,int panel_type)7801bb76ff1Sjsg static bool panel_bool(unsigned int value, int panel_type)
7811bb76ff1Sjsg {
7821bb76ff1Sjsg return panel_bits(value, panel_type, 1);
783c349dbc7Sjsg }
784c349dbc7Sjsg
785c349dbc7Sjsg /* Parse general panel options */
786c349dbc7Sjsg static void
parse_panel_options(struct drm_i915_private * i915,struct intel_panel * panel)7875ca02815Sjsg parse_panel_options(struct drm_i915_private *i915,
7881bb76ff1Sjsg struct intel_panel *panel)
789c349dbc7Sjsg {
790c349dbc7Sjsg const struct bdb_lvds_options *lvds_options;
7911bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
792c349dbc7Sjsg int drrs_mode;
793c349dbc7Sjsg
794f005ef32Sjsg lvds_options = bdb_find_section(i915, BDB_LVDS_OPTIONS);
795c349dbc7Sjsg if (!lvds_options)
796c349dbc7Sjsg return;
797c349dbc7Sjsg
7981bb76ff1Sjsg panel->vbt.lvds_dither = lvds_options->pixel_dither;
799c349dbc7Sjsg
8001bb76ff1Sjsg /*
8011bb76ff1Sjsg * Empirical evidence indicates the block size can be
8021bb76ff1Sjsg * either 4,14,16,24+ bytes. For older VBTs no clear
8031bb76ff1Sjsg * relationship between the block size vs. BDB version.
8041bb76ff1Sjsg */
8051bb76ff1Sjsg if (get_blocksize(lvds_options) < 16)
806c349dbc7Sjsg return;
807c349dbc7Sjsg
8081bb76ff1Sjsg drrs_mode = panel_bits(lvds_options->dps_panel_type_bits,
8091bb76ff1Sjsg panel_type, 2);
810c349dbc7Sjsg /*
811c349dbc7Sjsg * VBT has static DRRS = 0 and seamless DRRS = 2.
812c349dbc7Sjsg * The below piece of code is required to adjust vbt.drrs_type
813c349dbc7Sjsg * to match the enum drrs_support_type.
814c349dbc7Sjsg */
815c349dbc7Sjsg switch (drrs_mode) {
816c349dbc7Sjsg case 0:
8171bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_STATIC;
8185ca02815Sjsg drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n");
819c349dbc7Sjsg break;
820c349dbc7Sjsg case 2:
8211bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_SEAMLESS;
8225ca02815Sjsg drm_dbg_kms(&i915->drm,
823c349dbc7Sjsg "DRRS supported mode is seamless\n");
824c349dbc7Sjsg break;
825c349dbc7Sjsg default:
8261bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_NONE;
8275ca02815Sjsg drm_dbg_kms(&i915->drm,
828c349dbc7Sjsg "DRRS not supported (VBT input)\n");
829c349dbc7Sjsg break;
830c349dbc7Sjsg }
831c349dbc7Sjsg }
832c349dbc7Sjsg
833c349dbc7Sjsg static void
parse_lfp_panel_dtd(struct drm_i915_private * i915,struct intel_panel * panel,const struct bdb_lvds_lfp_data * lvds_lfp_data,const struct bdb_lvds_lfp_data_ptrs * lvds_lfp_data_ptrs)8345ca02815Sjsg parse_lfp_panel_dtd(struct drm_i915_private *i915,
8351bb76ff1Sjsg struct intel_panel *panel,
8361bb76ff1Sjsg const struct bdb_lvds_lfp_data *lvds_lfp_data,
8371bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs)
838c349dbc7Sjsg {
839c349dbc7Sjsg const struct lvds_dvo_timing *panel_dvo_timing;
840c349dbc7Sjsg const struct lvds_fp_timing *fp_timing;
841c349dbc7Sjsg struct drm_display_mode *panel_fixed_mode;
8421bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
843c349dbc7Sjsg
844c349dbc7Sjsg panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
845c349dbc7Sjsg lvds_lfp_data_ptrs,
846c349dbc7Sjsg panel_type);
847c349dbc7Sjsg
848c349dbc7Sjsg panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
849c349dbc7Sjsg if (!panel_fixed_mode)
850c349dbc7Sjsg return;
851c349dbc7Sjsg
852c349dbc7Sjsg fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
853c349dbc7Sjsg
8541bb76ff1Sjsg panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
855c349dbc7Sjsg
8565ca02815Sjsg drm_dbg_kms(&i915->drm,
8571bb76ff1Sjsg "Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n",
8581bb76ff1Sjsg DRM_MODE_ARG(panel_fixed_mode));
859c349dbc7Sjsg
8601bb76ff1Sjsg fp_timing = get_lvds_fp_timing(lvds_lfp_data,
861c349dbc7Sjsg lvds_lfp_data_ptrs,
862c349dbc7Sjsg panel_type);
8631bb76ff1Sjsg
864c349dbc7Sjsg /* check the resolution, just to be sure */
865c349dbc7Sjsg if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
866c349dbc7Sjsg fp_timing->y_res == panel_fixed_mode->vdisplay) {
8671bb76ff1Sjsg panel->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
8685ca02815Sjsg drm_dbg_kms(&i915->drm,
869c349dbc7Sjsg "VBT initial LVDS value %x\n",
8701bb76ff1Sjsg panel->vbt.bios_lvds_val);
871c349dbc7Sjsg }
872c349dbc7Sjsg }
8731bb76ff1Sjsg
8741bb76ff1Sjsg static void
parse_lfp_data(struct drm_i915_private * i915,struct intel_panel * panel)8751bb76ff1Sjsg parse_lfp_data(struct drm_i915_private *i915,
8761bb76ff1Sjsg struct intel_panel *panel)
8771bb76ff1Sjsg {
8781bb76ff1Sjsg const struct bdb_lvds_lfp_data *data;
8791bb76ff1Sjsg const struct bdb_lvds_lfp_data_tail *tail;
8801bb76ff1Sjsg const struct bdb_lvds_lfp_data_ptrs *ptrs;
8811bb76ff1Sjsg const struct lvds_pnp_id *pnp_id;
8821bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
8831bb76ff1Sjsg
884f005ef32Sjsg ptrs = bdb_find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
8851bb76ff1Sjsg if (!ptrs)
8861bb76ff1Sjsg return;
8871bb76ff1Sjsg
888f005ef32Sjsg data = bdb_find_section(i915, BDB_LVDS_LFP_DATA);
8891bb76ff1Sjsg if (!data)
8901bb76ff1Sjsg return;
8911bb76ff1Sjsg
8921bb76ff1Sjsg if (!panel->vbt.lfp_lvds_vbt_mode)
8931bb76ff1Sjsg parse_lfp_panel_dtd(i915, panel, data, ptrs);
8941bb76ff1Sjsg
8951bb76ff1Sjsg pnp_id = get_lvds_pnp_id(data, ptrs, panel_type);
8961bb76ff1Sjsg dump_pnp_id(i915, pnp_id, "Panel");
8971bb76ff1Sjsg
8981bb76ff1Sjsg tail = get_lfp_data_tail(data, ptrs);
8991bb76ff1Sjsg if (!tail)
9001bb76ff1Sjsg return;
9011bb76ff1Sjsg
9021bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Panel name: %.*s\n",
9031bb76ff1Sjsg (int)sizeof(tail->panel_name[0].name),
9041bb76ff1Sjsg tail->panel_name[panel_type].name);
9051bb76ff1Sjsg
9061bb76ff1Sjsg if (i915->display.vbt.version >= 188) {
9071bb76ff1Sjsg panel->vbt.seamless_drrs_min_refresh_rate =
9081bb76ff1Sjsg tail->seamless_drrs_min_refresh_rate[panel_type];
9091bb76ff1Sjsg drm_dbg_kms(&i915->drm,
9101bb76ff1Sjsg "Seamless DRRS min refresh rate: %d Hz\n",
9111bb76ff1Sjsg panel->vbt.seamless_drrs_min_refresh_rate);
9121bb76ff1Sjsg }
913c349dbc7Sjsg }
914c349dbc7Sjsg
915c349dbc7Sjsg static void
parse_generic_dtd(struct drm_i915_private * i915,struct intel_panel * panel)9165ca02815Sjsg parse_generic_dtd(struct drm_i915_private *i915,
9171bb76ff1Sjsg struct intel_panel *panel)
918c349dbc7Sjsg {
919c349dbc7Sjsg const struct bdb_generic_dtd *generic_dtd;
920c349dbc7Sjsg const struct generic_dtd_entry *dtd;
921c349dbc7Sjsg struct drm_display_mode *panel_fixed_mode;
922c349dbc7Sjsg int num_dtd;
923c349dbc7Sjsg
9241bb76ff1Sjsg /*
9251bb76ff1Sjsg * Older VBTs provided DTD information for internal displays through
9261bb76ff1Sjsg * the "LFP panel tables" block (42). As of VBT revision 229 the
9271bb76ff1Sjsg * DTD information should be provided via a newer "generic DTD"
9281bb76ff1Sjsg * block (58). Just to be safe, we'll try the new generic DTD block
9291bb76ff1Sjsg * first on VBT >= 229, but still fall back to trying the old LFP
9301bb76ff1Sjsg * block if that fails.
9311bb76ff1Sjsg */
9321bb76ff1Sjsg if (i915->display.vbt.version < 229)
9331bb76ff1Sjsg return;
9341bb76ff1Sjsg
935f005ef32Sjsg generic_dtd = bdb_find_section(i915, BDB_GENERIC_DTD);
936c349dbc7Sjsg if (!generic_dtd)
937c349dbc7Sjsg return;
938c349dbc7Sjsg
939c349dbc7Sjsg if (generic_dtd->gdtd_size < sizeof(struct generic_dtd_entry)) {
9405ca02815Sjsg drm_err(&i915->drm, "GDTD size %u is too small.\n",
941c349dbc7Sjsg generic_dtd->gdtd_size);
942c349dbc7Sjsg return;
943c349dbc7Sjsg } else if (generic_dtd->gdtd_size !=
944c349dbc7Sjsg sizeof(struct generic_dtd_entry)) {
9455ca02815Sjsg drm_err(&i915->drm, "Unexpected GDTD size %u\n",
946c349dbc7Sjsg generic_dtd->gdtd_size);
947c349dbc7Sjsg /* DTD has unknown fields, but keep going */
948c349dbc7Sjsg }
949c349dbc7Sjsg
950c349dbc7Sjsg num_dtd = (get_blocksize(generic_dtd) -
951c349dbc7Sjsg sizeof(struct bdb_generic_dtd)) / generic_dtd->gdtd_size;
9521bb76ff1Sjsg if (panel->vbt.panel_type >= num_dtd) {
9535ca02815Sjsg drm_err(&i915->drm,
954c349dbc7Sjsg "Panel type %d not found in table of %d DTD's\n",
9551bb76ff1Sjsg panel->vbt.panel_type, num_dtd);
956c349dbc7Sjsg return;
957c349dbc7Sjsg }
958c349dbc7Sjsg
9591bb76ff1Sjsg dtd = &generic_dtd->dtd[panel->vbt.panel_type];
960c349dbc7Sjsg
961c349dbc7Sjsg panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
962c349dbc7Sjsg if (!panel_fixed_mode)
963c349dbc7Sjsg return;
964c349dbc7Sjsg
965c349dbc7Sjsg panel_fixed_mode->hdisplay = dtd->hactive;
966c349dbc7Sjsg panel_fixed_mode->hsync_start =
967c349dbc7Sjsg panel_fixed_mode->hdisplay + dtd->hfront_porch;
968c349dbc7Sjsg panel_fixed_mode->hsync_end =
969c349dbc7Sjsg panel_fixed_mode->hsync_start + dtd->hsync;
970c349dbc7Sjsg panel_fixed_mode->htotal =
971c349dbc7Sjsg panel_fixed_mode->hdisplay + dtd->hblank;
972c349dbc7Sjsg
973c349dbc7Sjsg panel_fixed_mode->vdisplay = dtd->vactive;
974c349dbc7Sjsg panel_fixed_mode->vsync_start =
975c349dbc7Sjsg panel_fixed_mode->vdisplay + dtd->vfront_porch;
976c349dbc7Sjsg panel_fixed_mode->vsync_end =
977c349dbc7Sjsg panel_fixed_mode->vsync_start + dtd->vsync;
978c349dbc7Sjsg panel_fixed_mode->vtotal =
979c349dbc7Sjsg panel_fixed_mode->vdisplay + dtd->vblank;
980c349dbc7Sjsg
981c349dbc7Sjsg panel_fixed_mode->clock = dtd->pixel_clock;
982c349dbc7Sjsg panel_fixed_mode->width_mm = dtd->width_mm;
983c349dbc7Sjsg panel_fixed_mode->height_mm = dtd->height_mm;
984c349dbc7Sjsg
985c349dbc7Sjsg panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
986c349dbc7Sjsg drm_mode_set_name(panel_fixed_mode);
987c349dbc7Sjsg
988c349dbc7Sjsg if (dtd->hsync_positive_polarity)
989c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
990c349dbc7Sjsg else
991c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
992c349dbc7Sjsg
993c349dbc7Sjsg if (dtd->vsync_positive_polarity)
994c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
995c349dbc7Sjsg else
996c349dbc7Sjsg panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
997c349dbc7Sjsg
9985ca02815Sjsg drm_dbg_kms(&i915->drm,
9991bb76ff1Sjsg "Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n",
10001bb76ff1Sjsg DRM_MODE_ARG(panel_fixed_mode));
1001c349dbc7Sjsg
10021bb76ff1Sjsg panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
1003c349dbc7Sjsg }
1004c349dbc7Sjsg
1005c349dbc7Sjsg static void
parse_lfp_backlight(struct drm_i915_private * i915,struct intel_panel * panel)10065ca02815Sjsg parse_lfp_backlight(struct drm_i915_private *i915,
10071bb76ff1Sjsg struct intel_panel *panel)
1008c349dbc7Sjsg {
1009c349dbc7Sjsg const struct bdb_lfp_backlight_data *backlight_data;
1010c349dbc7Sjsg const struct lfp_backlight_data_entry *entry;
10111bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
10125ca02815Sjsg u16 level;
1013c349dbc7Sjsg
1014f005ef32Sjsg backlight_data = bdb_find_section(i915, BDB_LVDS_BACKLIGHT);
1015c349dbc7Sjsg if (!backlight_data)
1016c349dbc7Sjsg return;
1017c349dbc7Sjsg
1018c349dbc7Sjsg if (backlight_data->entry_size != sizeof(backlight_data->data[0])) {
10195ca02815Sjsg drm_dbg_kms(&i915->drm,
1020c349dbc7Sjsg "Unsupported backlight data entry size %u\n",
1021c349dbc7Sjsg backlight_data->entry_size);
1022c349dbc7Sjsg return;
1023c349dbc7Sjsg }
1024c349dbc7Sjsg
1025c349dbc7Sjsg entry = &backlight_data->data[panel_type];
1026c349dbc7Sjsg
10271bb76ff1Sjsg panel->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM;
10281bb76ff1Sjsg if (!panel->vbt.backlight.present) {
10295ca02815Sjsg drm_dbg_kms(&i915->drm,
1030c349dbc7Sjsg "PWM backlight not present in VBT (type %u)\n",
1031c349dbc7Sjsg entry->type);
1032c349dbc7Sjsg return;
1033c349dbc7Sjsg }
1034c349dbc7Sjsg
10351bb76ff1Sjsg panel->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI;
1036f005ef32Sjsg panel->vbt.backlight.controller = 0;
10371bb76ff1Sjsg if (i915->display.vbt.version >= 191) {
1038c349dbc7Sjsg const struct lfp_backlight_control_method *method;
1039c349dbc7Sjsg
1040c349dbc7Sjsg method = &backlight_data->backlight_control[panel_type];
10411bb76ff1Sjsg panel->vbt.backlight.type = method->type;
10421bb76ff1Sjsg panel->vbt.backlight.controller = method->controller;
10435ca02815Sjsg }
1044c349dbc7Sjsg
10451bb76ff1Sjsg panel->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
10461bb76ff1Sjsg panel->vbt.backlight.active_low_pwm = entry->active_low_pwm;
10475ca02815Sjsg
10481bb76ff1Sjsg if (i915->display.vbt.version >= 234) {
10495ca02815Sjsg u16 min_level;
10505ca02815Sjsg bool scale;
10515ca02815Sjsg
10525ca02815Sjsg level = backlight_data->brightness_level[panel_type].level;
10535ca02815Sjsg min_level = backlight_data->brightness_min_level[panel_type].level;
10545ca02815Sjsg
10551bb76ff1Sjsg if (i915->display.vbt.version >= 236)
10565ca02815Sjsg scale = backlight_data->brightness_precision_bits[panel_type] == 16;
10575ca02815Sjsg else
10585ca02815Sjsg scale = level > 255;
10595ca02815Sjsg
10605ca02815Sjsg if (scale)
10615ca02815Sjsg min_level = min_level / 255;
10625ca02815Sjsg
10635ca02815Sjsg if (min_level > 255) {
10645ca02815Sjsg drm_warn(&i915->drm, "Brightness min level > 255\n");
10655ca02815Sjsg level = 255;
10665ca02815Sjsg }
10671bb76ff1Sjsg panel->vbt.backlight.min_brightness = min_level;
10681bb76ff1Sjsg
10691bb76ff1Sjsg panel->vbt.backlight.brightness_precision_bits =
10701bb76ff1Sjsg backlight_data->brightness_precision_bits[panel_type];
10715ca02815Sjsg } else {
10725ca02815Sjsg level = backlight_data->level[panel_type];
10731bb76ff1Sjsg panel->vbt.backlight.min_brightness = entry->min_brightness;
10745ca02815Sjsg }
10755ca02815Sjsg
1076f005ef32Sjsg if (i915->display.vbt.version >= 239)
1077f005ef32Sjsg panel->vbt.backlight.hdr_dpcd_refresh_timeout =
1078f005ef32Sjsg DIV_ROUND_UP(backlight_data->hdr_dpcd_refresh_timeout[panel_type], 100);
1079f005ef32Sjsg else
1080f005ef32Sjsg panel->vbt.backlight.hdr_dpcd_refresh_timeout = 30;
1081f005ef32Sjsg
10825ca02815Sjsg drm_dbg_kms(&i915->drm,
1083c349dbc7Sjsg "VBT backlight PWM modulation frequency %u Hz, "
1084c349dbc7Sjsg "active %s, min brightness %u, level %u, controller %u\n",
10851bb76ff1Sjsg panel->vbt.backlight.pwm_freq_hz,
10861bb76ff1Sjsg panel->vbt.backlight.active_low_pwm ? "low" : "high",
10871bb76ff1Sjsg panel->vbt.backlight.min_brightness,
10885ca02815Sjsg level,
10891bb76ff1Sjsg panel->vbt.backlight.controller);
1090c349dbc7Sjsg }
1091c349dbc7Sjsg
1092c349dbc7Sjsg /* Try to find sdvo panel data */
1093c349dbc7Sjsg static void
parse_sdvo_panel_data(struct drm_i915_private * i915,struct intel_panel * panel)10945ca02815Sjsg parse_sdvo_panel_data(struct drm_i915_private *i915,
10951bb76ff1Sjsg struct intel_panel *panel)
1096c349dbc7Sjsg {
1097c349dbc7Sjsg const struct bdb_sdvo_panel_dtds *dtds;
1098c349dbc7Sjsg struct drm_display_mode *panel_fixed_mode;
1099c349dbc7Sjsg int index;
1100c349dbc7Sjsg
11015ca02815Sjsg index = i915->params.vbt_sdvo_panel_type;
1102c349dbc7Sjsg if (index == -2) {
11035ca02815Sjsg drm_dbg_kms(&i915->drm,
1104c349dbc7Sjsg "Ignore SDVO panel mode from BIOS VBT tables.\n");
1105c349dbc7Sjsg return;
1106c349dbc7Sjsg }
1107c349dbc7Sjsg
1108c349dbc7Sjsg if (index == -1) {
1109c349dbc7Sjsg const struct bdb_sdvo_lvds_options *sdvo_lvds_options;
1110c349dbc7Sjsg
1111f005ef32Sjsg sdvo_lvds_options = bdb_find_section(i915, BDB_SDVO_LVDS_OPTIONS);
1112c349dbc7Sjsg if (!sdvo_lvds_options)
1113c349dbc7Sjsg return;
1114c349dbc7Sjsg
1115c349dbc7Sjsg index = sdvo_lvds_options->panel_type;
1116c349dbc7Sjsg }
1117c349dbc7Sjsg
1118f005ef32Sjsg dtds = bdb_find_section(i915, BDB_SDVO_PANEL_DTDS);
1119c349dbc7Sjsg if (!dtds)
1120c349dbc7Sjsg return;
1121c349dbc7Sjsg
1122c349dbc7Sjsg panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
1123c349dbc7Sjsg if (!panel_fixed_mode)
1124c349dbc7Sjsg return;
1125c349dbc7Sjsg
1126c349dbc7Sjsg fill_detail_timing_data(panel_fixed_mode, &dtds->dtds[index]);
1127c349dbc7Sjsg
11281bb76ff1Sjsg panel->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode;
1129c349dbc7Sjsg
11305ca02815Sjsg drm_dbg_kms(&i915->drm,
11311bb76ff1Sjsg "Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n",
11321bb76ff1Sjsg DRM_MODE_ARG(panel_fixed_mode));
1133c349dbc7Sjsg }
1134c349dbc7Sjsg
intel_bios_ssc_frequency(struct drm_i915_private * i915,bool alternate)11355ca02815Sjsg static int intel_bios_ssc_frequency(struct drm_i915_private *i915,
1136c349dbc7Sjsg bool alternate)
1137c349dbc7Sjsg {
11385ca02815Sjsg switch (DISPLAY_VER(i915)) {
1139c349dbc7Sjsg case 2:
1140c349dbc7Sjsg return alternate ? 66667 : 48000;
1141c349dbc7Sjsg case 3:
1142c349dbc7Sjsg case 4:
1143c349dbc7Sjsg return alternate ? 100000 : 96000;
1144c349dbc7Sjsg default:
1145c349dbc7Sjsg return alternate ? 100000 : 120000;
1146c349dbc7Sjsg }
1147c349dbc7Sjsg }
1148c349dbc7Sjsg
1149c349dbc7Sjsg static void
parse_general_features(struct drm_i915_private * i915)11501bb76ff1Sjsg parse_general_features(struct drm_i915_private *i915)
1151c349dbc7Sjsg {
1152c349dbc7Sjsg const struct bdb_general_features *general;
1153c349dbc7Sjsg
1154f005ef32Sjsg general = bdb_find_section(i915, BDB_GENERAL_FEATURES);
1155c349dbc7Sjsg if (!general)
1156c349dbc7Sjsg return;
1157c349dbc7Sjsg
11581bb76ff1Sjsg i915->display.vbt.int_tv_support = general->int_tv_support;
1159c349dbc7Sjsg /* int_crt_support can't be trusted on earlier platforms */
11601bb76ff1Sjsg if (i915->display.vbt.version >= 155 &&
11615ca02815Sjsg (HAS_DDI(i915) || IS_VALLEYVIEW(i915)))
11621bb76ff1Sjsg i915->display.vbt.int_crt_support = general->int_crt_support;
11631bb76ff1Sjsg i915->display.vbt.lvds_use_ssc = general->enable_ssc;
11641bb76ff1Sjsg i915->display.vbt.lvds_ssc_freq =
11655ca02815Sjsg intel_bios_ssc_frequency(i915, general->ssc_freq);
11661bb76ff1Sjsg i915->display.vbt.display_clock_mode = general->display_clock_mode;
11671bb76ff1Sjsg i915->display.vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
11681bb76ff1Sjsg if (i915->display.vbt.version >= 181) {
11691bb76ff1Sjsg i915->display.vbt.orientation = general->rotate_180 ?
1170c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP :
1171c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_NORMAL;
1172c349dbc7Sjsg } else {
11731bb76ff1Sjsg i915->display.vbt.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1174c349dbc7Sjsg }
11751bb76ff1Sjsg
11761bb76ff1Sjsg if (i915->display.vbt.version >= 249 && general->afc_startup_config) {
11771bb76ff1Sjsg i915->display.vbt.override_afc_startup = true;
11781bb76ff1Sjsg i915->display.vbt.override_afc_startup_val = general->afc_startup_config == 0x1 ? 0x0 : 0x7;
11791bb76ff1Sjsg }
11801bb76ff1Sjsg
11815ca02815Sjsg drm_dbg_kms(&i915->drm,
1182c349dbc7Sjsg "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",
11831bb76ff1Sjsg i915->display.vbt.int_tv_support,
11841bb76ff1Sjsg i915->display.vbt.int_crt_support,
11851bb76ff1Sjsg i915->display.vbt.lvds_use_ssc,
11861bb76ff1Sjsg i915->display.vbt.lvds_ssc_freq,
11871bb76ff1Sjsg i915->display.vbt.display_clock_mode,
11881bb76ff1Sjsg i915->display.vbt.fdi_rx_polarity_inverted);
1189c349dbc7Sjsg }
1190c349dbc7Sjsg
1191c349dbc7Sjsg static const struct child_device_config *
child_device_ptr(const struct bdb_general_definitions * defs,int i)1192c349dbc7Sjsg child_device_ptr(const struct bdb_general_definitions *defs, int i)
1193c349dbc7Sjsg {
1194c349dbc7Sjsg return (const void *) &defs->devices[i * defs->child_dev_size];
1195c349dbc7Sjsg }
1196c349dbc7Sjsg
1197c349dbc7Sjsg static void
parse_sdvo_device_mapping(struct drm_i915_private * i915)11985ca02815Sjsg parse_sdvo_device_mapping(struct drm_i915_private *i915)
1199c349dbc7Sjsg {
12005ca02815Sjsg const struct intel_bios_encoder_data *devdata;
1201c349dbc7Sjsg int count = 0;
1202c349dbc7Sjsg
1203c349dbc7Sjsg /*
1204c349dbc7Sjsg * Only parse SDVO mappings on gens that could have SDVO. This isn't
1205c349dbc7Sjsg * accurate and doesn't have to be, as long as it's not too strict.
1206c349dbc7Sjsg */
12075ca02815Sjsg if (!IS_DISPLAY_VER(i915, 3, 7)) {
12085ca02815Sjsg drm_dbg_kms(&i915->drm, "Skipping SDVO device mapping\n");
1209c349dbc7Sjsg return;
1210c349dbc7Sjsg }
1211c349dbc7Sjsg
12121bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
1213f005ef32Sjsg const struct child_device_config *child = &devdata->child;
1214f005ef32Sjsg struct sdvo_device_mapping *mapping;
1215c349dbc7Sjsg
1216c349dbc7Sjsg if (child->slave_addr != SLAVE_ADDR1 &&
1217c349dbc7Sjsg child->slave_addr != SLAVE_ADDR2) {
1218c349dbc7Sjsg /*
1219c349dbc7Sjsg * If the slave address is neither 0x70 nor 0x72,
1220c349dbc7Sjsg * it is not a SDVO device. Skip it.
1221c349dbc7Sjsg */
1222c349dbc7Sjsg continue;
1223c349dbc7Sjsg }
1224c349dbc7Sjsg if (child->dvo_port != DEVICE_PORT_DVOB &&
1225c349dbc7Sjsg child->dvo_port != DEVICE_PORT_DVOC) {
1226c349dbc7Sjsg /* skip the incorrect SDVO port */
12275ca02815Sjsg drm_dbg_kms(&i915->drm,
1228c349dbc7Sjsg "Incorrect SDVO port. Skip it\n");
1229c349dbc7Sjsg continue;
1230c349dbc7Sjsg }
12315ca02815Sjsg drm_dbg_kms(&i915->drm,
1232c349dbc7Sjsg "the SDVO device with slave addr %2x is found on"
1233c349dbc7Sjsg " %s port\n",
1234c349dbc7Sjsg child->slave_addr,
1235c349dbc7Sjsg (child->dvo_port == DEVICE_PORT_DVOB) ?
1236c349dbc7Sjsg "SDVOB" : "SDVOC");
12371bb76ff1Sjsg mapping = &i915->display.vbt.sdvo_mappings[child->dvo_port - 1];
1238c349dbc7Sjsg if (!mapping->initialized) {
1239c349dbc7Sjsg mapping->dvo_port = child->dvo_port;
1240c349dbc7Sjsg mapping->slave_addr = child->slave_addr;
1241c349dbc7Sjsg mapping->dvo_wiring = child->dvo_wiring;
1242c349dbc7Sjsg mapping->ddc_pin = child->ddc_pin;
1243c349dbc7Sjsg mapping->i2c_pin = child->i2c_pin;
1244c349dbc7Sjsg mapping->initialized = 1;
12455ca02815Sjsg drm_dbg_kms(&i915->drm,
1246c349dbc7Sjsg "SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
1247c349dbc7Sjsg mapping->dvo_port, mapping->slave_addr,
1248c349dbc7Sjsg mapping->dvo_wiring, mapping->ddc_pin,
1249c349dbc7Sjsg mapping->i2c_pin);
1250c349dbc7Sjsg } else {
12515ca02815Sjsg drm_dbg_kms(&i915->drm,
1252c349dbc7Sjsg "Maybe one SDVO port is shared by "
1253c349dbc7Sjsg "two SDVO device.\n");
1254c349dbc7Sjsg }
1255c349dbc7Sjsg if (child->slave2_addr) {
1256c349dbc7Sjsg /* Maybe this is a SDVO device with multiple inputs */
1257c349dbc7Sjsg /* And the mapping info is not added */
12585ca02815Sjsg drm_dbg_kms(&i915->drm,
1259c349dbc7Sjsg "there exists the slave2_addr. Maybe this"
1260c349dbc7Sjsg " is a SDVO device with multiple inputs.\n");
1261c349dbc7Sjsg }
1262c349dbc7Sjsg count++;
1263c349dbc7Sjsg }
1264c349dbc7Sjsg
1265c349dbc7Sjsg if (!count) {
1266c349dbc7Sjsg /* No SDVO device info is found */
12675ca02815Sjsg drm_dbg_kms(&i915->drm,
1268c349dbc7Sjsg "No SDVO device info is found in VBT\n");
1269c349dbc7Sjsg }
1270c349dbc7Sjsg }
1271c349dbc7Sjsg
1272c349dbc7Sjsg static void
parse_driver_features(struct drm_i915_private * i915)12731bb76ff1Sjsg parse_driver_features(struct drm_i915_private *i915)
1274c349dbc7Sjsg {
1275c349dbc7Sjsg const struct bdb_driver_features *driver;
1276c349dbc7Sjsg
1277f005ef32Sjsg driver = bdb_find_section(i915, BDB_DRIVER_FEATURES);
1278c349dbc7Sjsg if (!driver)
1279c349dbc7Sjsg return;
1280c349dbc7Sjsg
12815ca02815Sjsg if (DISPLAY_VER(i915) >= 5) {
1282c349dbc7Sjsg /*
1283c349dbc7Sjsg * Note that we consider BDB_DRIVER_FEATURE_INT_SDVO_LVDS
1284c349dbc7Sjsg * to mean "eDP". The VBT spec doesn't agree with that
1285c349dbc7Sjsg * interpretation, but real world VBTs seem to.
1286c349dbc7Sjsg */
1287c349dbc7Sjsg if (driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS)
12881bb76ff1Sjsg i915->display.vbt.int_lvds_support = 0;
1289c349dbc7Sjsg } else {
1290c349dbc7Sjsg /*
1291c349dbc7Sjsg * FIXME it's not clear which BDB version has the LVDS config
1292c349dbc7Sjsg * bits defined. Revision history in the VBT spec says:
1293c349dbc7Sjsg * "0.92 | Add two definitions for VBT value of LVDS Active
1294c349dbc7Sjsg * Config (00b and 11b values defined) | 06/13/2005"
1295c349dbc7Sjsg * but does not the specify the BDB version.
1296c349dbc7Sjsg *
1297c349dbc7Sjsg * So far version 134 (on i945gm) is the oldest VBT observed
1298c349dbc7Sjsg * in the wild with the bits correctly populated. Version
1299c349dbc7Sjsg * 108 (on i85x) does not have the bits correctly populated.
1300c349dbc7Sjsg */
13011bb76ff1Sjsg if (i915->display.vbt.version >= 134 &&
1302c349dbc7Sjsg driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS &&
1303c349dbc7Sjsg driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS)
13041bb76ff1Sjsg i915->display.vbt.int_lvds_support = 0;
13051bb76ff1Sjsg }
1306c349dbc7Sjsg }
1307c349dbc7Sjsg
13081bb76ff1Sjsg static void
parse_panel_driver_features(struct drm_i915_private * i915,struct intel_panel * panel)13091bb76ff1Sjsg parse_panel_driver_features(struct drm_i915_private *i915,
13101bb76ff1Sjsg struct intel_panel *panel)
13111bb76ff1Sjsg {
13121bb76ff1Sjsg const struct bdb_driver_features *driver;
13131bb76ff1Sjsg
1314f005ef32Sjsg driver = bdb_find_section(i915, BDB_DRIVER_FEATURES);
13151bb76ff1Sjsg if (!driver)
13161bb76ff1Sjsg return;
13171bb76ff1Sjsg
13181bb76ff1Sjsg if (i915->display.vbt.version < 228) {
13195ca02815Sjsg drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n",
1320c349dbc7Sjsg driver->drrs_enabled);
1321c349dbc7Sjsg /*
1322c349dbc7Sjsg * If DRRS is not supported, drrs_type has to be set to 0.
1323c349dbc7Sjsg * This is because, VBT is configured in such a way that
1324c349dbc7Sjsg * static DRRS is 0 and DRRS not supported is represented by
1325c349dbc7Sjsg * driver->drrs_enabled=false
1326c349dbc7Sjsg */
13271bb76ff1Sjsg if (!driver->drrs_enabled && panel->vbt.drrs_type != DRRS_TYPE_NONE) {
13281bb76ff1Sjsg /*
13291bb76ff1Sjsg * FIXME Should DMRRS perhaps be treated as seamless
13301bb76ff1Sjsg * but without the automatic downclocking?
13311bb76ff1Sjsg */
13321bb76ff1Sjsg if (driver->dmrrs_enabled)
13331bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_STATIC;
13341bb76ff1Sjsg else
13351bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_NONE;
13361bb76ff1Sjsg }
1337c349dbc7Sjsg
13381bb76ff1Sjsg panel->vbt.psr.enable = driver->psr_enabled;
1339c349dbc7Sjsg }
1340c349dbc7Sjsg }
1341c349dbc7Sjsg
1342c349dbc7Sjsg static void
parse_power_conservation_features(struct drm_i915_private * i915,struct intel_panel * panel)13435ca02815Sjsg parse_power_conservation_features(struct drm_i915_private *i915,
13441bb76ff1Sjsg struct intel_panel *panel)
1345c349dbc7Sjsg {
1346c349dbc7Sjsg const struct bdb_lfp_power *power;
13471bb76ff1Sjsg u8 panel_type = panel->vbt.panel_type;
1348c349dbc7Sjsg
13491bb76ff1Sjsg panel->vbt.vrr = true; /* matches Windows behaviour */
13501bb76ff1Sjsg
13511bb76ff1Sjsg if (i915->display.vbt.version < 228)
1352c349dbc7Sjsg return;
1353c349dbc7Sjsg
1354f005ef32Sjsg power = bdb_find_section(i915, BDB_LFP_POWER);
1355c349dbc7Sjsg if (!power)
1356c349dbc7Sjsg return;
1357c349dbc7Sjsg
13581bb76ff1Sjsg panel->vbt.psr.enable = panel_bool(power->psr, panel_type);
1359c349dbc7Sjsg
1360c349dbc7Sjsg /*
1361c349dbc7Sjsg * If DRRS is not supported, drrs_type has to be set to 0.
1362c349dbc7Sjsg * This is because, VBT is configured in such a way that
1363c349dbc7Sjsg * static DRRS is 0 and DRRS not supported is represented by
1364c349dbc7Sjsg * power->drrs & BIT(panel_type)=false
1365c349dbc7Sjsg */
13661bb76ff1Sjsg if (!panel_bool(power->drrs, panel_type) && panel->vbt.drrs_type != DRRS_TYPE_NONE) {
13671bb76ff1Sjsg /*
13681bb76ff1Sjsg * FIXME Should DMRRS perhaps be treated as seamless
13691bb76ff1Sjsg * but without the automatic downclocking?
13701bb76ff1Sjsg */
13711bb76ff1Sjsg if (panel_bool(power->dmrrs, panel_type))
13721bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_STATIC;
13731bb76ff1Sjsg else
13741bb76ff1Sjsg panel->vbt.drrs_type = DRRS_TYPE_NONE;
13751bb76ff1Sjsg }
1376ad8b1aafSjsg
13771bb76ff1Sjsg if (i915->display.vbt.version >= 232)
13781bb76ff1Sjsg panel->vbt.edp.hobl = panel_bool(power->hobl, panel_type);
13791bb76ff1Sjsg
13801bb76ff1Sjsg if (i915->display.vbt.version >= 233)
13811bb76ff1Sjsg panel->vbt.vrr = panel_bool(power->vrr_feature_enabled,
13821bb76ff1Sjsg panel_type);
1383c349dbc7Sjsg }
1384c349dbc7Sjsg
1385c349dbc7Sjsg static void
parse_edp(struct drm_i915_private * i915,struct intel_panel * panel)13861bb76ff1Sjsg parse_edp(struct drm_i915_private *i915,
13871bb76ff1Sjsg struct intel_panel *panel)
1388c349dbc7Sjsg {
1389c349dbc7Sjsg const struct bdb_edp *edp;
1390c349dbc7Sjsg const struct edp_power_seq *edp_pps;
1391c349dbc7Sjsg const struct edp_fast_link_params *edp_link_params;
13921bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
1393c349dbc7Sjsg
1394f005ef32Sjsg edp = bdb_find_section(i915, BDB_EDP);
1395c349dbc7Sjsg if (!edp)
1396c349dbc7Sjsg return;
1397c349dbc7Sjsg
13981bb76ff1Sjsg switch (panel_bits(edp->color_depth, panel_type, 2)) {
1399c349dbc7Sjsg case EDP_18BPP:
14001bb76ff1Sjsg panel->vbt.edp.bpp = 18;
1401c349dbc7Sjsg break;
1402c349dbc7Sjsg case EDP_24BPP:
14031bb76ff1Sjsg panel->vbt.edp.bpp = 24;
1404c349dbc7Sjsg break;
1405c349dbc7Sjsg case EDP_30BPP:
14061bb76ff1Sjsg panel->vbt.edp.bpp = 30;
1407c349dbc7Sjsg break;
1408c349dbc7Sjsg }
1409c349dbc7Sjsg
1410c349dbc7Sjsg /* Get the eDP sequencing and link info */
1411c349dbc7Sjsg edp_pps = &edp->power_seqs[panel_type];
1412c349dbc7Sjsg edp_link_params = &edp->fast_link_params[panel_type];
1413c349dbc7Sjsg
14141bb76ff1Sjsg panel->vbt.edp.pps = *edp_pps;
1415c349dbc7Sjsg
14161bb76ff1Sjsg if (i915->display.vbt.version >= 224) {
14171bb76ff1Sjsg panel->vbt.edp.rate =
14181bb76ff1Sjsg edp->edp_fast_link_training_rate[panel_type] * 20;
14191bb76ff1Sjsg } else {
1420c349dbc7Sjsg switch (edp_link_params->rate) {
1421c349dbc7Sjsg case EDP_RATE_1_62:
14221bb76ff1Sjsg panel->vbt.edp.rate = 162000;
1423c349dbc7Sjsg break;
1424c349dbc7Sjsg case EDP_RATE_2_7:
14251bb76ff1Sjsg panel->vbt.edp.rate = 270000;
14261bb76ff1Sjsg break;
14271bb76ff1Sjsg case EDP_RATE_5_4:
14281bb76ff1Sjsg panel->vbt.edp.rate = 540000;
1429c349dbc7Sjsg break;
1430c349dbc7Sjsg default:
14315ca02815Sjsg drm_dbg_kms(&i915->drm,
1432c349dbc7Sjsg "VBT has unknown eDP link rate value %u\n",
1433c349dbc7Sjsg edp_link_params->rate);
1434c349dbc7Sjsg break;
1435c349dbc7Sjsg }
14361bb76ff1Sjsg }
1437c349dbc7Sjsg
1438c349dbc7Sjsg switch (edp_link_params->lanes) {
1439c349dbc7Sjsg case EDP_LANE_1:
14401bb76ff1Sjsg panel->vbt.edp.lanes = 1;
1441c349dbc7Sjsg break;
1442c349dbc7Sjsg case EDP_LANE_2:
14431bb76ff1Sjsg panel->vbt.edp.lanes = 2;
1444c349dbc7Sjsg break;
1445c349dbc7Sjsg case EDP_LANE_4:
14461bb76ff1Sjsg panel->vbt.edp.lanes = 4;
1447c349dbc7Sjsg break;
1448c349dbc7Sjsg default:
14495ca02815Sjsg drm_dbg_kms(&i915->drm,
1450c349dbc7Sjsg "VBT has unknown eDP lane count value %u\n",
1451c349dbc7Sjsg edp_link_params->lanes);
1452c349dbc7Sjsg break;
1453c349dbc7Sjsg }
1454c349dbc7Sjsg
1455c349dbc7Sjsg switch (edp_link_params->preemphasis) {
1456c349dbc7Sjsg case EDP_PREEMPHASIS_NONE:
14571bb76ff1Sjsg panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
1458c349dbc7Sjsg break;
1459c349dbc7Sjsg case EDP_PREEMPHASIS_3_5dB:
14601bb76ff1Sjsg panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
1461c349dbc7Sjsg break;
1462c349dbc7Sjsg case EDP_PREEMPHASIS_6dB:
14631bb76ff1Sjsg panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
1464c349dbc7Sjsg break;
1465c349dbc7Sjsg case EDP_PREEMPHASIS_9_5dB:
14661bb76ff1Sjsg panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
1467c349dbc7Sjsg break;
1468c349dbc7Sjsg default:
14695ca02815Sjsg drm_dbg_kms(&i915->drm,
1470c349dbc7Sjsg "VBT has unknown eDP pre-emphasis value %u\n",
1471c349dbc7Sjsg edp_link_params->preemphasis);
1472c349dbc7Sjsg break;
1473c349dbc7Sjsg }
1474c349dbc7Sjsg
1475c349dbc7Sjsg switch (edp_link_params->vswing) {
1476c349dbc7Sjsg case EDP_VSWING_0_4V:
14771bb76ff1Sjsg panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
1478c349dbc7Sjsg break;
1479c349dbc7Sjsg case EDP_VSWING_0_6V:
14801bb76ff1Sjsg panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
1481c349dbc7Sjsg break;
1482c349dbc7Sjsg case EDP_VSWING_0_8V:
14831bb76ff1Sjsg panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
1484c349dbc7Sjsg break;
1485c349dbc7Sjsg case EDP_VSWING_1_2V:
14861bb76ff1Sjsg panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
1487c349dbc7Sjsg break;
1488c349dbc7Sjsg default:
14895ca02815Sjsg drm_dbg_kms(&i915->drm,
1490c349dbc7Sjsg "VBT has unknown eDP voltage swing value %u\n",
1491c349dbc7Sjsg edp_link_params->vswing);
1492c349dbc7Sjsg break;
1493c349dbc7Sjsg }
1494c349dbc7Sjsg
14951bb76ff1Sjsg if (i915->display.vbt.version >= 173) {
1496c349dbc7Sjsg u8 vswing;
1497c349dbc7Sjsg
1498c349dbc7Sjsg /* Don't read from VBT if module parameter has valid value*/
14995ca02815Sjsg if (i915->params.edp_vswing) {
15001bb76ff1Sjsg panel->vbt.edp.low_vswing =
15015ca02815Sjsg i915->params.edp_vswing == 1;
1502c349dbc7Sjsg } else {
1503c349dbc7Sjsg vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF;
15041bb76ff1Sjsg panel->vbt.edp.low_vswing = vswing == 0;
1505c349dbc7Sjsg }
1506c349dbc7Sjsg }
15071bb76ff1Sjsg
15081bb76ff1Sjsg panel->vbt.edp.drrs_msa_timing_delay =
15091bb76ff1Sjsg panel_bits(edp->sdrrs_msa_timing_delay, panel_type, 2);
15101bb76ff1Sjsg
15111bb76ff1Sjsg if (i915->display.vbt.version >= 244)
15121bb76ff1Sjsg panel->vbt.edp.max_link_rate =
15131bb76ff1Sjsg edp->edp_max_port_link_rate[panel_type] * 20;
1514c349dbc7Sjsg }
1515c349dbc7Sjsg
1516c349dbc7Sjsg static void
parse_psr(struct drm_i915_private * i915,struct intel_panel * panel)15171bb76ff1Sjsg parse_psr(struct drm_i915_private *i915,
15181bb76ff1Sjsg struct intel_panel *panel)
1519c349dbc7Sjsg {
1520c349dbc7Sjsg const struct bdb_psr *psr;
1521c349dbc7Sjsg const struct psr_table *psr_table;
15221bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
1523c349dbc7Sjsg
1524f005ef32Sjsg psr = bdb_find_section(i915, BDB_PSR);
1525c349dbc7Sjsg if (!psr) {
15265ca02815Sjsg drm_dbg_kms(&i915->drm, "No PSR BDB found.\n");
1527c349dbc7Sjsg return;
1528c349dbc7Sjsg }
1529c349dbc7Sjsg
1530c349dbc7Sjsg psr_table = &psr->psr_table[panel_type];
1531c349dbc7Sjsg
15321bb76ff1Sjsg panel->vbt.psr.full_link = psr_table->full_link;
15331bb76ff1Sjsg panel->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup;
1534c349dbc7Sjsg
1535c349dbc7Sjsg /* Allowed VBT values goes from 0 to 15 */
15361bb76ff1Sjsg panel->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 :
1537c349dbc7Sjsg psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames;
1538c349dbc7Sjsg
1539c349dbc7Sjsg /*
1540c349dbc7Sjsg * New psr options 0=500us, 1=100us, 2=2500us, 3=0us
1541c349dbc7Sjsg * Old decimal value is wake up time in multiples of 100 us.
1542c349dbc7Sjsg */
15431bb76ff1Sjsg if (i915->display.vbt.version >= 205 &&
15445ca02815Sjsg (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) {
1545c349dbc7Sjsg switch (psr_table->tp1_wakeup_time) {
1546c349dbc7Sjsg case 0:
15471bb76ff1Sjsg panel->vbt.psr.tp1_wakeup_time_us = 500;
1548c349dbc7Sjsg break;
1549c349dbc7Sjsg case 1:
15501bb76ff1Sjsg panel->vbt.psr.tp1_wakeup_time_us = 100;
1551c349dbc7Sjsg break;
1552c349dbc7Sjsg case 3:
15531bb76ff1Sjsg panel->vbt.psr.tp1_wakeup_time_us = 0;
1554c349dbc7Sjsg break;
1555c349dbc7Sjsg default:
15565ca02815Sjsg drm_dbg_kms(&i915->drm,
1557c349dbc7Sjsg "VBT tp1 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
1558c349dbc7Sjsg psr_table->tp1_wakeup_time);
1559ad8b1aafSjsg fallthrough;
1560c349dbc7Sjsg case 2:
15611bb76ff1Sjsg panel->vbt.psr.tp1_wakeup_time_us = 2500;
1562c349dbc7Sjsg break;
1563c349dbc7Sjsg }
1564c349dbc7Sjsg
1565c349dbc7Sjsg switch (psr_table->tp2_tp3_wakeup_time) {
1566c349dbc7Sjsg case 0:
15671bb76ff1Sjsg panel->vbt.psr.tp2_tp3_wakeup_time_us = 500;
1568c349dbc7Sjsg break;
1569c349dbc7Sjsg case 1:
15701bb76ff1Sjsg panel->vbt.psr.tp2_tp3_wakeup_time_us = 100;
1571c349dbc7Sjsg break;
1572c349dbc7Sjsg case 3:
15731bb76ff1Sjsg panel->vbt.psr.tp2_tp3_wakeup_time_us = 0;
1574c349dbc7Sjsg break;
1575c349dbc7Sjsg default:
15765ca02815Sjsg drm_dbg_kms(&i915->drm,
1577c349dbc7Sjsg "VBT tp2_tp3 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
1578c349dbc7Sjsg psr_table->tp2_tp3_wakeup_time);
1579ad8b1aafSjsg fallthrough;
1580c349dbc7Sjsg case 2:
15811bb76ff1Sjsg panel->vbt.psr.tp2_tp3_wakeup_time_us = 2500;
1582c349dbc7Sjsg break;
1583c349dbc7Sjsg }
1584c349dbc7Sjsg } else {
15851bb76ff1Sjsg panel->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100;
15861bb76ff1Sjsg panel->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100;
1587c349dbc7Sjsg }
1588c349dbc7Sjsg
15891bb76ff1Sjsg if (i915->display.vbt.version >= 226) {
1590c349dbc7Sjsg u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time;
1591c349dbc7Sjsg
15921bb76ff1Sjsg wakeup_time = panel_bits(wakeup_time, panel_type, 2);
1593c349dbc7Sjsg switch (wakeup_time) {
1594c349dbc7Sjsg case 0:
1595c349dbc7Sjsg wakeup_time = 500;
1596c349dbc7Sjsg break;
1597c349dbc7Sjsg case 1:
1598c349dbc7Sjsg wakeup_time = 100;
1599c349dbc7Sjsg break;
1600c349dbc7Sjsg case 3:
1601c349dbc7Sjsg wakeup_time = 50;
1602c349dbc7Sjsg break;
1603c349dbc7Sjsg default:
1604c349dbc7Sjsg case 2:
1605c349dbc7Sjsg wakeup_time = 2500;
1606c349dbc7Sjsg break;
1607c349dbc7Sjsg }
16081bb76ff1Sjsg panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time;
1609c349dbc7Sjsg } else {
1610c349dbc7Sjsg /* Reusing PSR1 wakeup time for PSR2 in older VBTs */
16111bb76ff1Sjsg panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = panel->vbt.psr.tp2_tp3_wakeup_time_us;
1612c349dbc7Sjsg }
1613c349dbc7Sjsg }
1614c349dbc7Sjsg
parse_dsi_backlight_ports(struct drm_i915_private * i915,struct intel_panel * panel,enum port port)16155ca02815Sjsg static void parse_dsi_backlight_ports(struct drm_i915_private *i915,
16161bb76ff1Sjsg struct intel_panel *panel,
16171bb76ff1Sjsg enum port port)
1618c349dbc7Sjsg {
16191bb76ff1Sjsg enum port port_bc = DISPLAY_VER(i915) >= 11 ? PORT_B : PORT_C;
16201bb76ff1Sjsg
16211bb76ff1Sjsg if (!panel->vbt.dsi.config->dual_link || i915->display.vbt.version < 197) {
16221bb76ff1Sjsg panel->vbt.dsi.bl_ports = BIT(port);
16231bb76ff1Sjsg if (panel->vbt.dsi.config->cabc_supported)
16241bb76ff1Sjsg panel->vbt.dsi.cabc_ports = BIT(port);
1625c349dbc7Sjsg
1626c349dbc7Sjsg return;
1627c349dbc7Sjsg }
1628c349dbc7Sjsg
16291bb76ff1Sjsg switch (panel->vbt.dsi.config->dl_dcs_backlight_ports) {
1630c349dbc7Sjsg case DL_DCS_PORT_A:
16311bb76ff1Sjsg panel->vbt.dsi.bl_ports = BIT(PORT_A);
1632c349dbc7Sjsg break;
1633c349dbc7Sjsg case DL_DCS_PORT_C:
16341bb76ff1Sjsg panel->vbt.dsi.bl_ports = BIT(port_bc);
1635c349dbc7Sjsg break;
1636c349dbc7Sjsg default:
1637c349dbc7Sjsg case DL_DCS_PORT_A_AND_C:
16381bb76ff1Sjsg panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(port_bc);
1639c349dbc7Sjsg break;
1640c349dbc7Sjsg }
1641c349dbc7Sjsg
16421bb76ff1Sjsg if (!panel->vbt.dsi.config->cabc_supported)
1643c349dbc7Sjsg return;
1644c349dbc7Sjsg
16451bb76ff1Sjsg switch (panel->vbt.dsi.config->dl_dcs_cabc_ports) {
1646c349dbc7Sjsg case DL_DCS_PORT_A:
16471bb76ff1Sjsg panel->vbt.dsi.cabc_ports = BIT(PORT_A);
1648c349dbc7Sjsg break;
1649c349dbc7Sjsg case DL_DCS_PORT_C:
16501bb76ff1Sjsg panel->vbt.dsi.cabc_ports = BIT(port_bc);
1651c349dbc7Sjsg break;
1652c349dbc7Sjsg default:
1653c349dbc7Sjsg case DL_DCS_PORT_A_AND_C:
16541bb76ff1Sjsg panel->vbt.dsi.cabc_ports =
16551bb76ff1Sjsg BIT(PORT_A) | BIT(port_bc);
1656c349dbc7Sjsg break;
1657c349dbc7Sjsg }
1658c349dbc7Sjsg }
1659c349dbc7Sjsg
1660c349dbc7Sjsg static void
parse_mipi_config(struct drm_i915_private * i915,struct intel_panel * panel)16615ca02815Sjsg parse_mipi_config(struct drm_i915_private *i915,
16621bb76ff1Sjsg struct intel_panel *panel)
1663c349dbc7Sjsg {
1664c349dbc7Sjsg const struct bdb_mipi_config *start;
1665c349dbc7Sjsg const struct mipi_config *config;
1666c349dbc7Sjsg const struct mipi_pps_data *pps;
16671bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
1668c349dbc7Sjsg enum port port;
1669c349dbc7Sjsg
1670c349dbc7Sjsg /* parse MIPI blocks only if LFP type is MIPI */
16715ca02815Sjsg if (!intel_bios_is_dsi_present(i915, &port))
1672c349dbc7Sjsg return;
1673c349dbc7Sjsg
1674c349dbc7Sjsg /* Initialize this to undefined indicating no generic MIPI support */
16751bb76ff1Sjsg panel->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
1676c349dbc7Sjsg
1677c349dbc7Sjsg /* Block #40 is already parsed and panel_fixed_mode is
16785ca02815Sjsg * stored in i915->lfp_lvds_vbt_mode
1679c349dbc7Sjsg * resuse this when needed
1680c349dbc7Sjsg */
1681c349dbc7Sjsg
1682c349dbc7Sjsg /* Parse #52 for panel index used from panel_type already
1683c349dbc7Sjsg * parsed
1684c349dbc7Sjsg */
1685f005ef32Sjsg start = bdb_find_section(i915, BDB_MIPI_CONFIG);
1686c349dbc7Sjsg if (!start) {
16875ca02815Sjsg drm_dbg_kms(&i915->drm, "No MIPI config BDB found");
1688c349dbc7Sjsg return;
1689c349dbc7Sjsg }
1690c349dbc7Sjsg
16915ca02815Sjsg drm_dbg(&i915->drm, "Found MIPI Config block, panel index = %d\n",
1692c349dbc7Sjsg panel_type);
1693c349dbc7Sjsg
1694c349dbc7Sjsg /*
1695c349dbc7Sjsg * get hold of the correct configuration block and pps data as per
1696c349dbc7Sjsg * the panel_type as index
1697c349dbc7Sjsg */
1698c349dbc7Sjsg config = &start->config[panel_type];
1699c349dbc7Sjsg pps = &start->pps[panel_type];
1700c349dbc7Sjsg
1701c349dbc7Sjsg /* store as of now full data. Trim when we realise all is not needed */
17021bb76ff1Sjsg panel->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL);
17031bb76ff1Sjsg if (!panel->vbt.dsi.config)
1704c349dbc7Sjsg return;
1705c349dbc7Sjsg
17061bb76ff1Sjsg panel->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL);
17071bb76ff1Sjsg if (!panel->vbt.dsi.pps) {
17081bb76ff1Sjsg kfree(panel->vbt.dsi.config);
1709c349dbc7Sjsg return;
1710c349dbc7Sjsg }
1711c349dbc7Sjsg
17121bb76ff1Sjsg parse_dsi_backlight_ports(i915, panel, port);
1713c349dbc7Sjsg
1714c349dbc7Sjsg /* FIXME is the 90 vs. 270 correct? */
1715c349dbc7Sjsg switch (config->rotation) {
1716c349dbc7Sjsg case ENABLE_ROTATION_0:
1717c349dbc7Sjsg /*
1718c349dbc7Sjsg * Most (all?) VBTs claim 0 degrees despite having
1719c349dbc7Sjsg * an upside down panel, thus we do not trust this.
1720c349dbc7Sjsg */
17211bb76ff1Sjsg panel->vbt.dsi.orientation =
1722c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1723c349dbc7Sjsg break;
1724c349dbc7Sjsg case ENABLE_ROTATION_90:
17251bb76ff1Sjsg panel->vbt.dsi.orientation =
1726c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
1727c349dbc7Sjsg break;
1728c349dbc7Sjsg case ENABLE_ROTATION_180:
17291bb76ff1Sjsg panel->vbt.dsi.orientation =
1730c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1731c349dbc7Sjsg break;
1732c349dbc7Sjsg case ENABLE_ROTATION_270:
17331bb76ff1Sjsg panel->vbt.dsi.orientation =
1734c349dbc7Sjsg DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
1735c349dbc7Sjsg break;
1736c349dbc7Sjsg }
1737c349dbc7Sjsg
1738c349dbc7Sjsg /* We have mandatory mipi config blocks. Initialize as generic panel */
17391bb76ff1Sjsg panel->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
1740c349dbc7Sjsg }
1741c349dbc7Sjsg
1742c349dbc7Sjsg /* Find the sequence block and size for the given panel. */
1743c349dbc7Sjsg static const u8 *
find_panel_sequence_block(const struct bdb_mipi_sequence * sequence,u16 panel_id,u32 * seq_size)1744c349dbc7Sjsg find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
1745c349dbc7Sjsg u16 panel_id, u32 *seq_size)
1746c349dbc7Sjsg {
1747c349dbc7Sjsg u32 total = get_blocksize(sequence);
1748c349dbc7Sjsg const u8 *data = &sequence->data[0];
1749c349dbc7Sjsg u8 current_id;
1750c349dbc7Sjsg u32 current_size;
1751c349dbc7Sjsg int header_size = sequence->version >= 3 ? 5 : 3;
1752c349dbc7Sjsg int index = 0;
1753c349dbc7Sjsg int i;
1754c349dbc7Sjsg
1755c349dbc7Sjsg /* skip new block size */
1756c349dbc7Sjsg if (sequence->version >= 3)
1757c349dbc7Sjsg data += 4;
1758c349dbc7Sjsg
1759c349dbc7Sjsg for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) {
1760c349dbc7Sjsg if (index + header_size > total) {
1761c349dbc7Sjsg DRM_ERROR("Invalid sequence block (header)\n");
1762c349dbc7Sjsg return NULL;
1763c349dbc7Sjsg }
1764c349dbc7Sjsg
1765c349dbc7Sjsg current_id = *(data + index);
1766c349dbc7Sjsg if (sequence->version >= 3)
1767c349dbc7Sjsg current_size = *((const u32 *)(data + index + 1));
1768c349dbc7Sjsg else
1769c349dbc7Sjsg current_size = *((const u16 *)(data + index + 1));
1770c349dbc7Sjsg
1771c349dbc7Sjsg index += header_size;
1772c349dbc7Sjsg
1773c349dbc7Sjsg if (index + current_size > total) {
1774c349dbc7Sjsg DRM_ERROR("Invalid sequence block\n");
1775c349dbc7Sjsg return NULL;
1776c349dbc7Sjsg }
1777c349dbc7Sjsg
1778c349dbc7Sjsg if (current_id == panel_id) {
1779c349dbc7Sjsg *seq_size = current_size;
1780c349dbc7Sjsg return data + index;
1781c349dbc7Sjsg }
1782c349dbc7Sjsg
1783c349dbc7Sjsg index += current_size;
1784c349dbc7Sjsg }
1785c349dbc7Sjsg
1786c349dbc7Sjsg DRM_ERROR("Sequence block detected but no valid configuration\n");
1787c349dbc7Sjsg
1788c349dbc7Sjsg return NULL;
1789c349dbc7Sjsg }
1790c349dbc7Sjsg
goto_next_sequence(const u8 * data,int index,int total)1791c349dbc7Sjsg static int goto_next_sequence(const u8 *data, int index, int total)
1792c349dbc7Sjsg {
1793c349dbc7Sjsg u16 len;
1794c349dbc7Sjsg
1795c349dbc7Sjsg /* Skip Sequence Byte. */
1796c349dbc7Sjsg for (index = index + 1; index < total; index += len) {
1797c349dbc7Sjsg u8 operation_byte = *(data + index);
1798c349dbc7Sjsg index++;
1799c349dbc7Sjsg
1800c349dbc7Sjsg switch (operation_byte) {
1801c349dbc7Sjsg case MIPI_SEQ_ELEM_END:
1802c349dbc7Sjsg return index;
1803c349dbc7Sjsg case MIPI_SEQ_ELEM_SEND_PKT:
1804c349dbc7Sjsg if (index + 4 > total)
1805c349dbc7Sjsg return 0;
1806c349dbc7Sjsg
1807c349dbc7Sjsg len = *((const u16 *)(data + index + 2)) + 4;
1808c349dbc7Sjsg break;
1809c349dbc7Sjsg case MIPI_SEQ_ELEM_DELAY:
1810c349dbc7Sjsg len = 4;
1811c349dbc7Sjsg break;
1812c349dbc7Sjsg case MIPI_SEQ_ELEM_GPIO:
1813c349dbc7Sjsg len = 2;
1814c349dbc7Sjsg break;
1815c349dbc7Sjsg case MIPI_SEQ_ELEM_I2C:
1816c349dbc7Sjsg if (index + 7 > total)
1817c349dbc7Sjsg return 0;
1818c349dbc7Sjsg len = *(data + index + 6) + 7;
1819c349dbc7Sjsg break;
1820c349dbc7Sjsg default:
1821c349dbc7Sjsg DRM_ERROR("Unknown operation byte\n");
1822c349dbc7Sjsg return 0;
1823c349dbc7Sjsg }
1824c349dbc7Sjsg }
1825c349dbc7Sjsg
1826c349dbc7Sjsg return 0;
1827c349dbc7Sjsg }
1828c349dbc7Sjsg
goto_next_sequence_v3(const u8 * data,int index,int total)1829c349dbc7Sjsg static int goto_next_sequence_v3(const u8 *data, int index, int total)
1830c349dbc7Sjsg {
1831c349dbc7Sjsg int seq_end;
1832c349dbc7Sjsg u16 len;
1833c349dbc7Sjsg u32 size_of_sequence;
1834c349dbc7Sjsg
1835c349dbc7Sjsg /*
1836c349dbc7Sjsg * Could skip sequence based on Size of Sequence alone, but also do some
1837c349dbc7Sjsg * checking on the structure.
1838c349dbc7Sjsg */
1839c349dbc7Sjsg if (total < 5) {
1840c349dbc7Sjsg DRM_ERROR("Too small sequence size\n");
1841c349dbc7Sjsg return 0;
1842c349dbc7Sjsg }
1843c349dbc7Sjsg
1844c349dbc7Sjsg /* Skip Sequence Byte. */
1845c349dbc7Sjsg index++;
1846c349dbc7Sjsg
1847c349dbc7Sjsg /*
1848c349dbc7Sjsg * Size of Sequence. Excludes the Sequence Byte and the size itself,
1849c349dbc7Sjsg * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END
1850c349dbc7Sjsg * byte.
1851c349dbc7Sjsg */
1852c349dbc7Sjsg size_of_sequence = *((const u32 *)(data + index));
1853c349dbc7Sjsg index += 4;
1854c349dbc7Sjsg
1855c349dbc7Sjsg seq_end = index + size_of_sequence;
1856c349dbc7Sjsg if (seq_end > total) {
1857c349dbc7Sjsg DRM_ERROR("Invalid sequence size\n");
1858c349dbc7Sjsg return 0;
1859c349dbc7Sjsg }
1860c349dbc7Sjsg
1861c349dbc7Sjsg for (; index < total; index += len) {
1862c349dbc7Sjsg u8 operation_byte = *(data + index);
1863c349dbc7Sjsg index++;
1864c349dbc7Sjsg
1865c349dbc7Sjsg if (operation_byte == MIPI_SEQ_ELEM_END) {
1866c349dbc7Sjsg if (index != seq_end) {
1867c349dbc7Sjsg DRM_ERROR("Invalid element structure\n");
1868c349dbc7Sjsg return 0;
1869c349dbc7Sjsg }
1870c349dbc7Sjsg return index;
1871c349dbc7Sjsg }
1872c349dbc7Sjsg
1873c349dbc7Sjsg len = *(data + index);
1874c349dbc7Sjsg index++;
1875c349dbc7Sjsg
1876c349dbc7Sjsg /*
1877c349dbc7Sjsg * FIXME: Would be nice to check elements like for v1/v2 in
1878c349dbc7Sjsg * goto_next_sequence() above.
1879c349dbc7Sjsg */
1880c349dbc7Sjsg switch (operation_byte) {
1881c349dbc7Sjsg case MIPI_SEQ_ELEM_SEND_PKT:
1882c349dbc7Sjsg case MIPI_SEQ_ELEM_DELAY:
1883c349dbc7Sjsg case MIPI_SEQ_ELEM_GPIO:
1884c349dbc7Sjsg case MIPI_SEQ_ELEM_I2C:
1885c349dbc7Sjsg case MIPI_SEQ_ELEM_SPI:
1886c349dbc7Sjsg case MIPI_SEQ_ELEM_PMIC:
1887c349dbc7Sjsg break;
1888c349dbc7Sjsg default:
1889c349dbc7Sjsg DRM_ERROR("Unknown operation byte %u\n",
1890c349dbc7Sjsg operation_byte);
1891c349dbc7Sjsg break;
1892c349dbc7Sjsg }
1893c349dbc7Sjsg }
1894c349dbc7Sjsg
1895c349dbc7Sjsg return 0;
1896c349dbc7Sjsg }
1897c349dbc7Sjsg
1898c349dbc7Sjsg /*
1899c349dbc7Sjsg * Get len of pre-fixed deassert fragment from a v1 init OTP sequence,
1900c349dbc7Sjsg * skip all delay + gpio operands and stop at the first DSI packet op.
1901c349dbc7Sjsg */
get_init_otp_deassert_fragment_len(struct drm_i915_private * i915,struct intel_panel * panel)19021bb76ff1Sjsg static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915,
19031bb76ff1Sjsg struct intel_panel *panel)
1904c349dbc7Sjsg {
19051bb76ff1Sjsg const u8 *data = panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
1906c349dbc7Sjsg int index, len;
1907c349dbc7Sjsg
19085ca02815Sjsg if (drm_WARN_ON(&i915->drm,
19091bb76ff1Sjsg !data || panel->vbt.dsi.seq_version != 1))
1910c349dbc7Sjsg return 0;
1911c349dbc7Sjsg
1912c349dbc7Sjsg /* index = 1 to skip sequence byte */
1913c349dbc7Sjsg for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) {
1914c349dbc7Sjsg switch (data[index]) {
1915c349dbc7Sjsg case MIPI_SEQ_ELEM_SEND_PKT:
1916c349dbc7Sjsg return index == 1 ? 0 : index;
1917c349dbc7Sjsg case MIPI_SEQ_ELEM_DELAY:
1918c349dbc7Sjsg len = 5; /* 1 byte for operand + uint32 */
1919c349dbc7Sjsg break;
1920c349dbc7Sjsg case MIPI_SEQ_ELEM_GPIO:
1921c349dbc7Sjsg len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */
1922c349dbc7Sjsg break;
1923c349dbc7Sjsg default:
1924c349dbc7Sjsg return 0;
1925c349dbc7Sjsg }
1926c349dbc7Sjsg }
1927c349dbc7Sjsg
1928c349dbc7Sjsg return 0;
1929c349dbc7Sjsg }
1930c349dbc7Sjsg
1931c349dbc7Sjsg /*
1932c349dbc7Sjsg * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence.
1933c349dbc7Sjsg * The deassert must be done before calling intel_dsi_device_ready, so for
1934c349dbc7Sjsg * these devices we split the init OTP sequence into a deassert sequence and
1935c349dbc7Sjsg * the actual init OTP part.
1936c349dbc7Sjsg */
vlv_fixup_mipi_sequences(struct drm_i915_private * i915,struct intel_panel * panel)1937*00370b25Sjsg static void vlv_fixup_mipi_sequences(struct drm_i915_private *i915,
19381bb76ff1Sjsg struct intel_panel *panel)
1939c349dbc7Sjsg {
1940c349dbc7Sjsg u8 *init_otp;
1941c349dbc7Sjsg int len;
1942c349dbc7Sjsg
1943c349dbc7Sjsg /* Limit this to v1 vid-mode sequences */
19441bb76ff1Sjsg if (panel->vbt.dsi.config->is_cmd_mode ||
19451bb76ff1Sjsg panel->vbt.dsi.seq_version != 1)
1946c349dbc7Sjsg return;
1947c349dbc7Sjsg
1948c349dbc7Sjsg /* Only do this if there are otp and assert seqs and no deassert seq */
19491bb76ff1Sjsg if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] ||
19501bb76ff1Sjsg !panel->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] ||
19511bb76ff1Sjsg panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET])
1952c349dbc7Sjsg return;
1953c349dbc7Sjsg
1954c349dbc7Sjsg /* The deassert-sequence ends at the first DSI packet */
19551bb76ff1Sjsg len = get_init_otp_deassert_fragment_len(i915, panel);
1956c349dbc7Sjsg if (!len)
1957c349dbc7Sjsg return;
1958c349dbc7Sjsg
19595ca02815Sjsg drm_dbg_kms(&i915->drm,
1960c349dbc7Sjsg "Using init OTP fragment to deassert reset\n");
1961c349dbc7Sjsg
1962c349dbc7Sjsg /* Copy the fragment, update seq byte and terminate it */
19631bb76ff1Sjsg init_otp = (u8 *)panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
19641bb76ff1Sjsg panel->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL);
19651bb76ff1Sjsg if (!panel->vbt.dsi.deassert_seq)
1966c349dbc7Sjsg return;
19671bb76ff1Sjsg panel->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET;
19681bb76ff1Sjsg panel->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END;
1969c349dbc7Sjsg /* Use the copy for deassert */
19701bb76ff1Sjsg panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] =
19711bb76ff1Sjsg panel->vbt.dsi.deassert_seq;
1972c349dbc7Sjsg /* Replace the last byte of the fragment with init OTP seq byte */
1973c349dbc7Sjsg init_otp[len - 1] = MIPI_SEQ_INIT_OTP;
1974c349dbc7Sjsg /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */
19751bb76ff1Sjsg panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1;
1976c349dbc7Sjsg }
1977c349dbc7Sjsg
1978*00370b25Sjsg /*
1979*00370b25Sjsg * Some machines (eg. Lenovo 82TQ) appear to have broken
1980*00370b25Sjsg * VBT sequences:
1981*00370b25Sjsg * - INIT_OTP is not present at all
1982*00370b25Sjsg * - what should be in INIT_OTP is in DISPLAY_ON
1983*00370b25Sjsg * - what should be in DISPLAY_ON is in BACKLIGHT_ON
1984*00370b25Sjsg * (along with the actual backlight stuff)
1985*00370b25Sjsg *
1986*00370b25Sjsg * To make those work we simply swap DISPLAY_ON and INIT_OTP.
1987*00370b25Sjsg *
1988*00370b25Sjsg * TODO: Do we need to limit this to specific machines,
1989*00370b25Sjsg * or examine the contents of the sequences to
1990*00370b25Sjsg * avoid false positives?
1991*00370b25Sjsg */
icl_fixup_mipi_sequences(struct drm_i915_private * i915,struct intel_panel * panel)1992*00370b25Sjsg static void icl_fixup_mipi_sequences(struct drm_i915_private *i915,
1993*00370b25Sjsg struct intel_panel *panel)
1994*00370b25Sjsg {
1995*00370b25Sjsg if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] &&
1996*00370b25Sjsg panel->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON]) {
1997*00370b25Sjsg drm_dbg_kms(&i915->drm, "Broken VBT: Swapping INIT_OTP and DISPLAY_ON sequences\n");
1998*00370b25Sjsg
1999*00370b25Sjsg swap(panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP],
2000*00370b25Sjsg panel->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON]);
2001*00370b25Sjsg }
2002*00370b25Sjsg }
2003*00370b25Sjsg
fixup_mipi_sequences(struct drm_i915_private * i915,struct intel_panel * panel)2004*00370b25Sjsg static void fixup_mipi_sequences(struct drm_i915_private *i915,
2005*00370b25Sjsg struct intel_panel *panel)
2006*00370b25Sjsg {
2007*00370b25Sjsg if (DISPLAY_VER(i915) >= 11)
2008*00370b25Sjsg icl_fixup_mipi_sequences(i915, panel);
2009*00370b25Sjsg else if (IS_VALLEYVIEW(i915))
2010*00370b25Sjsg vlv_fixup_mipi_sequences(i915, panel);
2011*00370b25Sjsg }
2012*00370b25Sjsg
2013c349dbc7Sjsg static void
parse_mipi_sequence(struct drm_i915_private * i915,struct intel_panel * panel)20145ca02815Sjsg parse_mipi_sequence(struct drm_i915_private *i915,
20151bb76ff1Sjsg struct intel_panel *panel)
2016c349dbc7Sjsg {
20171bb76ff1Sjsg int panel_type = panel->vbt.panel_type;
2018c349dbc7Sjsg const struct bdb_mipi_sequence *sequence;
2019c349dbc7Sjsg const u8 *seq_data;
2020c349dbc7Sjsg u32 seq_size;
2021c349dbc7Sjsg u8 *data;
2022c349dbc7Sjsg int index = 0;
2023c349dbc7Sjsg
2024c349dbc7Sjsg /* Only our generic panel driver uses the sequence block. */
20251bb76ff1Sjsg if (panel->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
2026c349dbc7Sjsg return;
2027c349dbc7Sjsg
2028f005ef32Sjsg sequence = bdb_find_section(i915, BDB_MIPI_SEQUENCE);
2029c349dbc7Sjsg if (!sequence) {
20305ca02815Sjsg drm_dbg_kms(&i915->drm,
2031c349dbc7Sjsg "No MIPI Sequence found, parsing complete\n");
2032c349dbc7Sjsg return;
2033c349dbc7Sjsg }
2034c349dbc7Sjsg
2035c349dbc7Sjsg /* Fail gracefully for forward incompatible sequence block. */
2036c349dbc7Sjsg if (sequence->version >= 4) {
20375ca02815Sjsg drm_err(&i915->drm,
2038c349dbc7Sjsg "Unable to parse MIPI Sequence Block v%u\n",
2039c349dbc7Sjsg sequence->version);
2040c349dbc7Sjsg return;
2041c349dbc7Sjsg }
2042c349dbc7Sjsg
20435ca02815Sjsg drm_dbg(&i915->drm, "Found MIPI sequence block v%u\n",
2044c349dbc7Sjsg sequence->version);
2045c349dbc7Sjsg
2046c349dbc7Sjsg seq_data = find_panel_sequence_block(sequence, panel_type, &seq_size);
2047c349dbc7Sjsg if (!seq_data)
2048c349dbc7Sjsg return;
2049c349dbc7Sjsg
2050c349dbc7Sjsg data = kmemdup(seq_data, seq_size, GFP_KERNEL);
2051c349dbc7Sjsg if (!data)
2052c349dbc7Sjsg return;
2053c349dbc7Sjsg
2054c349dbc7Sjsg /* Parse the sequences, store pointers to each sequence. */
2055c349dbc7Sjsg for (;;) {
2056c349dbc7Sjsg u8 seq_id = *(data + index);
2057c349dbc7Sjsg if (seq_id == MIPI_SEQ_END)
2058c349dbc7Sjsg break;
2059c349dbc7Sjsg
2060c349dbc7Sjsg if (seq_id >= MIPI_SEQ_MAX) {
20615ca02815Sjsg drm_err(&i915->drm, "Unknown sequence %u\n",
2062c349dbc7Sjsg seq_id);
2063c349dbc7Sjsg goto err;
2064c349dbc7Sjsg }
2065c349dbc7Sjsg
2066c349dbc7Sjsg /* Log about presence of sequences we won't run. */
2067c349dbc7Sjsg if (seq_id == MIPI_SEQ_TEAR_ON || seq_id == MIPI_SEQ_TEAR_OFF)
20685ca02815Sjsg drm_dbg_kms(&i915->drm,
2069c349dbc7Sjsg "Unsupported sequence %u\n", seq_id);
2070c349dbc7Sjsg
20711bb76ff1Sjsg panel->vbt.dsi.sequence[seq_id] = data + index;
2072c349dbc7Sjsg
2073c349dbc7Sjsg if (sequence->version >= 3)
2074c349dbc7Sjsg index = goto_next_sequence_v3(data, index, seq_size);
2075c349dbc7Sjsg else
2076c349dbc7Sjsg index = goto_next_sequence(data, index, seq_size);
2077c349dbc7Sjsg if (!index) {
20785ca02815Sjsg drm_err(&i915->drm, "Invalid sequence %u\n",
2079c349dbc7Sjsg seq_id);
2080c349dbc7Sjsg goto err;
2081c349dbc7Sjsg }
2082c349dbc7Sjsg }
2083c349dbc7Sjsg
20841bb76ff1Sjsg panel->vbt.dsi.data = data;
20851bb76ff1Sjsg panel->vbt.dsi.size = seq_size;
20861bb76ff1Sjsg panel->vbt.dsi.seq_version = sequence->version;
2087c349dbc7Sjsg
20881bb76ff1Sjsg fixup_mipi_sequences(i915, panel);
2089c349dbc7Sjsg
20905ca02815Sjsg drm_dbg(&i915->drm, "MIPI related VBT parsing complete\n");
2091c349dbc7Sjsg return;
2092c349dbc7Sjsg
2093c349dbc7Sjsg err:
2094c349dbc7Sjsg kfree(data);
20951bb76ff1Sjsg memset(panel->vbt.dsi.sequence, 0, sizeof(panel->vbt.dsi.sequence));
2096c349dbc7Sjsg }
2097c349dbc7Sjsg
2098c349dbc7Sjsg static void
parse_compression_parameters(struct drm_i915_private * i915)20991bb76ff1Sjsg parse_compression_parameters(struct drm_i915_private *i915)
2100c349dbc7Sjsg {
2101c349dbc7Sjsg const struct bdb_compression_parameters *params;
21025ca02815Sjsg struct intel_bios_encoder_data *devdata;
2103c349dbc7Sjsg u16 block_size;
2104c349dbc7Sjsg int index;
2105c349dbc7Sjsg
21061bb76ff1Sjsg if (i915->display.vbt.version < 198)
2107c349dbc7Sjsg return;
2108c349dbc7Sjsg
2109f005ef32Sjsg params = bdb_find_section(i915, BDB_COMPRESSION_PARAMETERS);
2110c349dbc7Sjsg if (params) {
2111c349dbc7Sjsg /* Sanity checks */
2112c349dbc7Sjsg if (params->entry_size != sizeof(params->data[0])) {
2113c349dbc7Sjsg drm_dbg_kms(&i915->drm,
2114c349dbc7Sjsg "VBT: unsupported compression param entry size\n");
2115c349dbc7Sjsg return;
2116c349dbc7Sjsg }
2117c349dbc7Sjsg
2118c349dbc7Sjsg block_size = get_blocksize(params);
2119c349dbc7Sjsg if (block_size < sizeof(*params)) {
2120c349dbc7Sjsg drm_dbg_kms(&i915->drm,
2121c349dbc7Sjsg "VBT: expected 16 compression param entries\n");
2122c349dbc7Sjsg return;
2123c349dbc7Sjsg }
2124c349dbc7Sjsg }
2125c349dbc7Sjsg
21261bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
2127f005ef32Sjsg const struct child_device_config *child = &devdata->child;
2128c349dbc7Sjsg
2129c349dbc7Sjsg if (!child->compression_enable)
2130c349dbc7Sjsg continue;
2131c349dbc7Sjsg
2132c349dbc7Sjsg if (!params) {
2133c349dbc7Sjsg drm_dbg_kms(&i915->drm,
2134c349dbc7Sjsg "VBT: compression params not available\n");
2135c349dbc7Sjsg continue;
2136c349dbc7Sjsg }
2137c349dbc7Sjsg
2138c349dbc7Sjsg if (child->compression_method_cps) {
2139c349dbc7Sjsg drm_dbg_kms(&i915->drm,
2140c349dbc7Sjsg "VBT: CPS compression not supported\n");
2141c349dbc7Sjsg continue;
2142c349dbc7Sjsg }
2143c349dbc7Sjsg
2144c349dbc7Sjsg index = child->compression_structure_index;
2145c349dbc7Sjsg
2146c349dbc7Sjsg devdata->dsc = kmemdup(¶ms->data[index],
2147c349dbc7Sjsg sizeof(*devdata->dsc), GFP_KERNEL);
2148c349dbc7Sjsg }
2149c349dbc7Sjsg }
2150c349dbc7Sjsg
translate_iboost(u8 val)2151c349dbc7Sjsg static u8 translate_iboost(u8 val)
2152c349dbc7Sjsg {
2153c349dbc7Sjsg static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
2154c349dbc7Sjsg
2155c349dbc7Sjsg if (val >= ARRAY_SIZE(mapping)) {
2156c349dbc7Sjsg DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
2157c349dbc7Sjsg return 0;
2158c349dbc7Sjsg }
2159c349dbc7Sjsg return mapping[val];
2160c349dbc7Sjsg }
2161c349dbc7Sjsg
2162c349dbc7Sjsg static const u8 cnp_ddc_pin_map[] = {
2163c349dbc7Sjsg [0] = 0, /* N/A */
2164f005ef32Sjsg [GMBUS_PIN_1_BXT] = DDC_BUS_DDI_B,
2165f005ef32Sjsg [GMBUS_PIN_2_BXT] = DDC_BUS_DDI_C,
2166f005ef32Sjsg [GMBUS_PIN_4_CNP] = DDC_BUS_DDI_D, /* sic */
2167f005ef32Sjsg [GMBUS_PIN_3_BXT] = DDC_BUS_DDI_F, /* sic */
2168c349dbc7Sjsg };
2169c349dbc7Sjsg
2170c349dbc7Sjsg static const u8 icp_ddc_pin_map[] = {
2171f005ef32Sjsg [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A,
2172f005ef32Sjsg [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B,
2173f005ef32Sjsg [GMBUS_PIN_3_BXT] = TGL_DDC_BUS_DDI_C,
2174f005ef32Sjsg [GMBUS_PIN_9_TC1_ICP] = ICL_DDC_BUS_PORT_1,
2175f005ef32Sjsg [GMBUS_PIN_10_TC2_ICP] = ICL_DDC_BUS_PORT_2,
2176f005ef32Sjsg [GMBUS_PIN_11_TC3_ICP] = ICL_DDC_BUS_PORT_3,
2177f005ef32Sjsg [GMBUS_PIN_12_TC4_ICP] = ICL_DDC_BUS_PORT_4,
2178f005ef32Sjsg [GMBUS_PIN_13_TC5_TGP] = TGL_DDC_BUS_PORT_5,
2179f005ef32Sjsg [GMBUS_PIN_14_TC6_TGP] = TGL_DDC_BUS_PORT_6,
2180c349dbc7Sjsg };
2181c349dbc7Sjsg
21825ca02815Sjsg static const u8 rkl_pch_tgp_ddc_pin_map[] = {
2183f005ef32Sjsg [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A,
2184f005ef32Sjsg [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B,
2185f005ef32Sjsg [GMBUS_PIN_9_TC1_ICP] = RKL_DDC_BUS_DDI_D,
2186f005ef32Sjsg [GMBUS_PIN_10_TC2_ICP] = RKL_DDC_BUS_DDI_E,
21875ca02815Sjsg };
21885ca02815Sjsg
21895ca02815Sjsg static const u8 adls_ddc_pin_map[] = {
2190f005ef32Sjsg [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A,
2191f005ef32Sjsg [GMBUS_PIN_9_TC1_ICP] = ADLS_DDC_BUS_PORT_TC1,
2192f005ef32Sjsg [GMBUS_PIN_10_TC2_ICP] = ADLS_DDC_BUS_PORT_TC2,
2193f005ef32Sjsg [GMBUS_PIN_11_TC3_ICP] = ADLS_DDC_BUS_PORT_TC3,
2194f005ef32Sjsg [GMBUS_PIN_12_TC4_ICP] = ADLS_DDC_BUS_PORT_TC4,
21955ca02815Sjsg };
21965ca02815Sjsg
21975ca02815Sjsg static const u8 gen9bc_tgp_ddc_pin_map[] = {
2198f005ef32Sjsg [GMBUS_PIN_2_BXT] = DDC_BUS_DDI_B,
2199f005ef32Sjsg [GMBUS_PIN_9_TC1_ICP] = DDC_BUS_DDI_C,
2200f005ef32Sjsg [GMBUS_PIN_10_TC2_ICP] = DDC_BUS_DDI_D,
22015ca02815Sjsg };
22025ca02815Sjsg
22036e1ff440Sjsg static const u8 adlp_ddc_pin_map[] = {
2204f005ef32Sjsg [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A,
2205f005ef32Sjsg [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B,
2206f005ef32Sjsg [GMBUS_PIN_9_TC1_ICP] = ADLP_DDC_BUS_PORT_TC1,
2207f005ef32Sjsg [GMBUS_PIN_10_TC2_ICP] = ADLP_DDC_BUS_PORT_TC2,
2208f005ef32Sjsg [GMBUS_PIN_11_TC3_ICP] = ADLP_DDC_BUS_PORT_TC3,
2209f005ef32Sjsg [GMBUS_PIN_12_TC4_ICP] = ADLP_DDC_BUS_PORT_TC4,
22106e1ff440Sjsg };
22116e1ff440Sjsg
map_ddc_pin(struct drm_i915_private * i915,u8 vbt_pin)22125ca02815Sjsg static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
2213c349dbc7Sjsg {
2214c349dbc7Sjsg const u8 *ddc_pin_map;
2215f005ef32Sjsg int i, n_entries;
2216c349dbc7Sjsg
2217f005ef32Sjsg if (HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) {
22186e1ff440Sjsg ddc_pin_map = adlp_ddc_pin_map;
22196e1ff440Sjsg n_entries = ARRAY_SIZE(adlp_ddc_pin_map);
22206e1ff440Sjsg } else if (IS_ALDERLAKE_S(i915)) {
22215ca02815Sjsg ddc_pin_map = adls_ddc_pin_map;
22225ca02815Sjsg n_entries = ARRAY_SIZE(adls_ddc_pin_map);
22235ca02815Sjsg } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
22245ca02815Sjsg return vbt_pin;
22255ca02815Sjsg } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) {
22265ca02815Sjsg ddc_pin_map = rkl_pch_tgp_ddc_pin_map;
22275ca02815Sjsg n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map);
22285ca02815Sjsg } else if (HAS_PCH_TGP(i915) && DISPLAY_VER(i915) == 9) {
22295ca02815Sjsg ddc_pin_map = gen9bc_tgp_ddc_pin_map;
22305ca02815Sjsg n_entries = ARRAY_SIZE(gen9bc_tgp_ddc_pin_map);
22315ca02815Sjsg } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
2232c349dbc7Sjsg ddc_pin_map = icp_ddc_pin_map;
2233c349dbc7Sjsg n_entries = ARRAY_SIZE(icp_ddc_pin_map);
22345ca02815Sjsg } else if (HAS_PCH_CNP(i915)) {
2235c349dbc7Sjsg ddc_pin_map = cnp_ddc_pin_map;
2236c349dbc7Sjsg n_entries = ARRAY_SIZE(cnp_ddc_pin_map);
2237c349dbc7Sjsg } else {
2238c349dbc7Sjsg /* Assuming direct map */
2239c349dbc7Sjsg return vbt_pin;
2240c349dbc7Sjsg }
2241c349dbc7Sjsg
2242f005ef32Sjsg for (i = 0; i < n_entries; i++) {
2243f005ef32Sjsg if (ddc_pin_map[i] == vbt_pin)
2244f005ef32Sjsg return i;
2245f005ef32Sjsg }
2246c349dbc7Sjsg
22475ca02815Sjsg drm_dbg_kms(&i915->drm,
2248c349dbc7Sjsg "Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n",
2249c349dbc7Sjsg vbt_pin);
2250c349dbc7Sjsg return 0;
2251c349dbc7Sjsg }
2252c349dbc7Sjsg
dvo_port_type(u8 dvo_port)22535ca02815Sjsg static u8 dvo_port_type(u8 dvo_port)
22545ca02815Sjsg {
22555ca02815Sjsg switch (dvo_port) {
22565ca02815Sjsg case DVO_PORT_HDMIA:
22575ca02815Sjsg case DVO_PORT_HDMIB:
22585ca02815Sjsg case DVO_PORT_HDMIC:
22595ca02815Sjsg case DVO_PORT_HDMID:
22605ca02815Sjsg case DVO_PORT_HDMIE:
22615ca02815Sjsg case DVO_PORT_HDMIF:
22625ca02815Sjsg case DVO_PORT_HDMIG:
22635ca02815Sjsg case DVO_PORT_HDMIH:
22645ca02815Sjsg case DVO_PORT_HDMII:
22655ca02815Sjsg return DVO_PORT_HDMIA;
22665ca02815Sjsg case DVO_PORT_DPA:
22675ca02815Sjsg case DVO_PORT_DPB:
22685ca02815Sjsg case DVO_PORT_DPC:
22695ca02815Sjsg case DVO_PORT_DPD:
22705ca02815Sjsg case DVO_PORT_DPE:
22715ca02815Sjsg case DVO_PORT_DPF:
22725ca02815Sjsg case DVO_PORT_DPG:
22735ca02815Sjsg case DVO_PORT_DPH:
22745ca02815Sjsg case DVO_PORT_DPI:
22755ca02815Sjsg return DVO_PORT_DPA;
22765ca02815Sjsg case DVO_PORT_MIPIA:
22775ca02815Sjsg case DVO_PORT_MIPIB:
22785ca02815Sjsg case DVO_PORT_MIPIC:
22795ca02815Sjsg case DVO_PORT_MIPID:
22805ca02815Sjsg return DVO_PORT_MIPIA;
22815ca02815Sjsg default:
22825ca02815Sjsg return dvo_port;
22835ca02815Sjsg }
22845ca02815Sjsg }
22855ca02815Sjsg
__dvo_port_to_port(int n_ports,int n_dvo,const int port_mapping[][3],u8 dvo_port)2286ad8b1aafSjsg static enum port __dvo_port_to_port(int n_ports, int n_dvo,
2287ad8b1aafSjsg const int port_mapping[][3], u8 dvo_port)
2288c349dbc7Sjsg {
2289c349dbc7Sjsg enum port port;
2290c349dbc7Sjsg int i;
2291c349dbc7Sjsg
2292ad8b1aafSjsg for (port = PORT_A; port < n_ports; port++) {
2293ad8b1aafSjsg for (i = 0; i < n_dvo; i++) {
2294ad8b1aafSjsg if (port_mapping[port][i] == -1)
2295c349dbc7Sjsg break;
2296c349dbc7Sjsg
2297ad8b1aafSjsg if (dvo_port == port_mapping[port][i])
2298c349dbc7Sjsg return port;
2299c349dbc7Sjsg }
2300c349dbc7Sjsg }
2301c349dbc7Sjsg
2302c349dbc7Sjsg return PORT_NONE;
2303c349dbc7Sjsg }
2304c349dbc7Sjsg
dvo_port_to_port(struct drm_i915_private * i915,u8 dvo_port)23055ca02815Sjsg static enum port dvo_port_to_port(struct drm_i915_private *i915,
2306ad8b1aafSjsg u8 dvo_port)
2307ad8b1aafSjsg {
2308ad8b1aafSjsg /*
2309ad8b1aafSjsg * Each DDI port can have more than one value on the "DVO Port" field,
2310ad8b1aafSjsg * so look for all the possible values for each port.
2311ad8b1aafSjsg */
2312ad8b1aafSjsg static const int port_mapping[][3] = {
2313ad8b1aafSjsg [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
2314ad8b1aafSjsg [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
2315ad8b1aafSjsg [PORT_C] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
2316ad8b1aafSjsg [PORT_D] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
2317ad8b1aafSjsg [PORT_E] = { DVO_PORT_HDMIE, DVO_PORT_DPE, DVO_PORT_CRT },
2318ad8b1aafSjsg [PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 },
2319ad8b1aafSjsg [PORT_G] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -1 },
2320ad8b1aafSjsg [PORT_H] = { DVO_PORT_HDMIH, DVO_PORT_DPH, -1 },
2321ad8b1aafSjsg [PORT_I] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 },
2322ad8b1aafSjsg };
2323ad8b1aafSjsg /*
23245ca02815Sjsg * RKL VBT uses PHY based mapping. Combo PHYs A,B,C,D
23255ca02815Sjsg * map to DDI A,B,TC1,TC2 respectively.
2326ad8b1aafSjsg */
2327ad8b1aafSjsg static const int rkl_port_mapping[][3] = {
2328ad8b1aafSjsg [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
2329ad8b1aafSjsg [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
2330ad8b1aafSjsg [PORT_C] = { -1 },
23315ca02815Sjsg [PORT_TC1] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
23325ca02815Sjsg [PORT_TC2] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
23335ca02815Sjsg };
23345ca02815Sjsg /*
23355ca02815Sjsg * Alderlake S ports used in the driver are PORT_A, PORT_D, PORT_E,
23365ca02815Sjsg * PORT_F and PORT_G, we need to map that to correct VBT sections.
23375ca02815Sjsg */
23385ca02815Sjsg static const int adls_port_mapping[][3] = {
23395ca02815Sjsg [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
23405ca02815Sjsg [PORT_B] = { -1 },
23415ca02815Sjsg [PORT_C] = { -1 },
23425ca02815Sjsg [PORT_TC1] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
23435ca02815Sjsg [PORT_TC2] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
23445ca02815Sjsg [PORT_TC3] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
23455ca02815Sjsg [PORT_TC4] = { DVO_PORT_HDMIE, DVO_PORT_DPE, -1 },
23465ca02815Sjsg };
23475ca02815Sjsg static const int xelpd_port_mapping[][3] = {
23485ca02815Sjsg [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 },
23495ca02815Sjsg [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 },
23505ca02815Sjsg [PORT_C] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 },
23515ca02815Sjsg [PORT_D_XELPD] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 },
23525ca02815Sjsg [PORT_E_XELPD] = { DVO_PORT_HDMIE, DVO_PORT_DPE, -1 },
23535ca02815Sjsg [PORT_TC1] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 },
23545ca02815Sjsg [PORT_TC2] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -1 },
23555ca02815Sjsg [PORT_TC3] = { DVO_PORT_HDMIH, DVO_PORT_DPH, -1 },
23565ca02815Sjsg [PORT_TC4] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 },
2357ad8b1aafSjsg };
2358ad8b1aafSjsg
23591bb76ff1Sjsg if (DISPLAY_VER(i915) >= 13)
23605ca02815Sjsg return __dvo_port_to_port(ARRAY_SIZE(xelpd_port_mapping),
23615ca02815Sjsg ARRAY_SIZE(xelpd_port_mapping[0]),
23625ca02815Sjsg xelpd_port_mapping,
23635ca02815Sjsg dvo_port);
23645ca02815Sjsg else if (IS_ALDERLAKE_S(i915))
23655ca02815Sjsg return __dvo_port_to_port(ARRAY_SIZE(adls_port_mapping),
23665ca02815Sjsg ARRAY_SIZE(adls_port_mapping[0]),
23675ca02815Sjsg adls_port_mapping,
23685ca02815Sjsg dvo_port);
23695ca02815Sjsg else if (IS_DG1(i915) || IS_ROCKETLAKE(i915))
2370ad8b1aafSjsg return __dvo_port_to_port(ARRAY_SIZE(rkl_port_mapping),
2371ad8b1aafSjsg ARRAY_SIZE(rkl_port_mapping[0]),
2372ad8b1aafSjsg rkl_port_mapping,
2373ad8b1aafSjsg dvo_port);
2374ad8b1aafSjsg else
2375ad8b1aafSjsg return __dvo_port_to_port(ARRAY_SIZE(port_mapping),
2376ad8b1aafSjsg ARRAY_SIZE(port_mapping[0]),
2377ad8b1aafSjsg port_mapping,
2378ad8b1aafSjsg dvo_port);
2379ad8b1aafSjsg }
2380ad8b1aafSjsg
238150603113Sjsg static enum port
dsi_dvo_port_to_port(struct drm_i915_private * i915,u8 dvo_port)238250603113Sjsg dsi_dvo_port_to_port(struct drm_i915_private *i915, u8 dvo_port)
238350603113Sjsg {
238450603113Sjsg switch (dvo_port) {
238550603113Sjsg case DVO_PORT_MIPIA:
238650603113Sjsg return PORT_A;
238750603113Sjsg case DVO_PORT_MIPIC:
238850603113Sjsg if (DISPLAY_VER(i915) >= 11)
238950603113Sjsg return PORT_B;
239050603113Sjsg else
239150603113Sjsg return PORT_C;
239250603113Sjsg default:
239350603113Sjsg return PORT_NONE;
239450603113Sjsg }
239550603113Sjsg }
239650603113Sjsg
intel_bios_encoder_port(const struct intel_bios_encoder_data * devdata)2397f005ef32Sjsg enum port intel_bios_encoder_port(const struct intel_bios_encoder_data *devdata)
2398f005ef32Sjsg {
2399f005ef32Sjsg struct drm_i915_private *i915 = devdata->i915;
2400f005ef32Sjsg const struct child_device_config *child = &devdata->child;
2401f005ef32Sjsg enum port port;
2402f005ef32Sjsg
2403f005ef32Sjsg port = dvo_port_to_port(i915, child->dvo_port);
2404f005ef32Sjsg if (port == PORT_NONE && DISPLAY_VER(i915) >= 11)
2405f005ef32Sjsg port = dsi_dvo_port_to_port(i915, child->dvo_port);
2406f005ef32Sjsg
2407f005ef32Sjsg return port;
2408f005ef32Sjsg }
2409f005ef32Sjsg
parse_bdb_230_dp_max_link_rate(const int vbt_max_link_rate)24105ca02815Sjsg static int parse_bdb_230_dp_max_link_rate(const int vbt_max_link_rate)
24115ca02815Sjsg {
24125ca02815Sjsg switch (vbt_max_link_rate) {
24135ca02815Sjsg default:
24145ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_DEF:
24155ca02815Sjsg return 0;
24165ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR20:
24175ca02815Sjsg return 2000000;
24185ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR13P5:
24195ca02815Sjsg return 1350000;
24205ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR10:
24215ca02815Sjsg return 1000000;
24225ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_HBR3:
24235ca02815Sjsg return 810000;
24245ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_HBR2:
24255ca02815Sjsg return 540000;
24265ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_HBR:
24275ca02815Sjsg return 270000;
24285ca02815Sjsg case BDB_230_VBT_DP_MAX_LINK_RATE_LBR:
24295ca02815Sjsg return 162000;
24305ca02815Sjsg }
24315ca02815Sjsg }
24325ca02815Sjsg
parse_bdb_216_dp_max_link_rate(const int vbt_max_link_rate)24335ca02815Sjsg static int parse_bdb_216_dp_max_link_rate(const int vbt_max_link_rate)
24345ca02815Sjsg {
24355ca02815Sjsg switch (vbt_max_link_rate) {
24365ca02815Sjsg default:
24375ca02815Sjsg case BDB_216_VBT_DP_MAX_LINK_RATE_HBR3:
24385ca02815Sjsg return 810000;
24395ca02815Sjsg case BDB_216_VBT_DP_MAX_LINK_RATE_HBR2:
24405ca02815Sjsg return 540000;
24415ca02815Sjsg case BDB_216_VBT_DP_MAX_LINK_RATE_HBR:
24425ca02815Sjsg return 270000;
24435ca02815Sjsg case BDB_216_VBT_DP_MAX_LINK_RATE_LBR:
24445ca02815Sjsg return 162000;
24455ca02815Sjsg }
24465ca02815Sjsg }
24475ca02815Sjsg
intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data * devdata)2448f005ef32Sjsg int intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data *devdata)
24491bb76ff1Sjsg {
24501bb76ff1Sjsg if (!devdata || devdata->i915->display.vbt.version < 216)
24511bb76ff1Sjsg return 0;
24521bb76ff1Sjsg
24531bb76ff1Sjsg if (devdata->i915->display.vbt.version >= 230)
24541bb76ff1Sjsg return parse_bdb_230_dp_max_link_rate(devdata->child.dp_max_link_rate);
24551bb76ff1Sjsg else
24561bb76ff1Sjsg return parse_bdb_216_dp_max_link_rate(devdata->child.dp_max_link_rate);
24571bb76ff1Sjsg }
24581bb76ff1Sjsg
intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data * devdata)2459f005ef32Sjsg int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata)
24601bb76ff1Sjsg {
24611bb76ff1Sjsg if (!devdata || devdata->i915->display.vbt.version < 244)
24621bb76ff1Sjsg return 0;
24631bb76ff1Sjsg
24641bb76ff1Sjsg return devdata->child.dp_max_lane_count + 1;
24651bb76ff1Sjsg }
24661bb76ff1Sjsg
sanitize_device_type(struct intel_bios_encoder_data * devdata,enum port port)24675ca02815Sjsg static void sanitize_device_type(struct intel_bios_encoder_data *devdata,
24685ca02815Sjsg enum port port)
24695ca02815Sjsg {
24705ca02815Sjsg struct drm_i915_private *i915 = devdata->i915;
24715ca02815Sjsg bool is_hdmi;
24725ca02815Sjsg
24735ca02815Sjsg if (port != PORT_A || DISPLAY_VER(i915) >= 12)
24745ca02815Sjsg return;
24755ca02815Sjsg
24761bb76ff1Sjsg if (!intel_bios_encoder_supports_dvi(devdata))
24775ca02815Sjsg return;
24785ca02815Sjsg
24791bb76ff1Sjsg is_hdmi = intel_bios_encoder_supports_hdmi(devdata);
24805ca02815Sjsg
24815ca02815Sjsg drm_dbg_kms(&i915->drm, "VBT claims port A supports DVI%s, ignoring\n",
24825ca02815Sjsg is_hdmi ? "/HDMI" : "");
24835ca02815Sjsg
24845ca02815Sjsg devdata->child.device_type &= ~DEVICE_TYPE_TMDS_DVI_SIGNALING;
24855ca02815Sjsg devdata->child.device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
24865ca02815Sjsg }
24875ca02815Sjsg
24885ca02815Sjsg static bool
intel_bios_encoder_supports_crt(const struct intel_bios_encoder_data * devdata)24895ca02815Sjsg intel_bios_encoder_supports_crt(const struct intel_bios_encoder_data *devdata)
24905ca02815Sjsg {
24915ca02815Sjsg return devdata->child.device_type & DEVICE_TYPE_ANALOG_OUTPUT;
24925ca02815Sjsg }
24935ca02815Sjsg
24945ca02815Sjsg bool
intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data * devdata)24955ca02815Sjsg intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data *devdata)
24965ca02815Sjsg {
24975ca02815Sjsg return devdata->child.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
24985ca02815Sjsg }
24995ca02815Sjsg
25005ca02815Sjsg bool
intel_bios_encoder_supports_hdmi(const struct intel_bios_encoder_data * devdata)25015ca02815Sjsg intel_bios_encoder_supports_hdmi(const struct intel_bios_encoder_data *devdata)
25025ca02815Sjsg {
25035ca02815Sjsg return intel_bios_encoder_supports_dvi(devdata) &&
25045ca02815Sjsg (devdata->child.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
25055ca02815Sjsg }
25065ca02815Sjsg
25075ca02815Sjsg bool
intel_bios_encoder_supports_dp(const struct intel_bios_encoder_data * devdata)25085ca02815Sjsg intel_bios_encoder_supports_dp(const struct intel_bios_encoder_data *devdata)
25095ca02815Sjsg {
25105ca02815Sjsg return devdata->child.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
25115ca02815Sjsg }
25125ca02815Sjsg
2513f005ef32Sjsg bool
intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data * devdata)25145ca02815Sjsg intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata)
25155ca02815Sjsg {
25165ca02815Sjsg return intel_bios_encoder_supports_dp(devdata) &&
25175ca02815Sjsg devdata->child.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR;
25185ca02815Sjsg }
25195ca02815Sjsg
2520f005ef32Sjsg bool
intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data * devdata)252154075a0eSjsg intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data *devdata)
252254075a0eSjsg {
252354075a0eSjsg return devdata->child.device_type & DEVICE_TYPE_MIPI_OUTPUT;
252454075a0eSjsg }
252554075a0eSjsg
2526f005ef32Sjsg bool
intel_bios_encoder_is_lspcon(const struct intel_bios_encoder_data * devdata)2527f005ef32Sjsg intel_bios_encoder_is_lspcon(const struct intel_bios_encoder_data *devdata)
25281bb76ff1Sjsg {
2529f005ef32Sjsg return devdata && HAS_LSPCON(devdata->i915) && devdata->child.lspcon;
2530f005ef32Sjsg }
2531f005ef32Sjsg
2532f005ef32Sjsg /* This is an index in the HDMI/DVI DDI buffer translation table, or -1 */
intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data * devdata)2533f005ef32Sjsg int intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata)
2534f005ef32Sjsg {
2535f005ef32Sjsg if (!devdata || devdata->i915->display.vbt.version < 158 ||
2536f005ef32Sjsg DISPLAY_VER(devdata->i915) >= 14)
25371bb76ff1Sjsg return -1;
25381bb76ff1Sjsg
25391bb76ff1Sjsg return devdata->child.hdmi_level_shifter_value;
25401bb76ff1Sjsg }
25411bb76ff1Sjsg
intel_bios_hdmi_max_tmds_clock(const struct intel_bios_encoder_data * devdata)2542f005ef32Sjsg int intel_bios_hdmi_max_tmds_clock(const struct intel_bios_encoder_data *devdata)
25431bb76ff1Sjsg {
25441bb76ff1Sjsg if (!devdata || devdata->i915->display.vbt.version < 204)
25451bb76ff1Sjsg return 0;
25461bb76ff1Sjsg
25471bb76ff1Sjsg switch (devdata->child.hdmi_max_data_rate) {
25481bb76ff1Sjsg default:
25491bb76ff1Sjsg MISSING_CASE(devdata->child.hdmi_max_data_rate);
25501bb76ff1Sjsg fallthrough;
25511bb76ff1Sjsg case HDMI_MAX_DATA_RATE_PLATFORM:
25521bb76ff1Sjsg return 0;
25531bb76ff1Sjsg case HDMI_MAX_DATA_RATE_594:
25541bb76ff1Sjsg return 594000;
25551bb76ff1Sjsg case HDMI_MAX_DATA_RATE_340:
25561bb76ff1Sjsg return 340000;
25571bb76ff1Sjsg case HDMI_MAX_DATA_RATE_300:
25581bb76ff1Sjsg return 300000;
25591bb76ff1Sjsg case HDMI_MAX_DATA_RATE_297:
25601bb76ff1Sjsg return 297000;
25611bb76ff1Sjsg case HDMI_MAX_DATA_RATE_165:
25621bb76ff1Sjsg return 165000;
25631bb76ff1Sjsg }
25641bb76ff1Sjsg }
25651bb76ff1Sjsg
is_port_valid(struct drm_i915_private * i915,enum port port)25665ca02815Sjsg static bool is_port_valid(struct drm_i915_private *i915, enum port port)
25675ca02815Sjsg {
25685ca02815Sjsg /*
25695ca02815Sjsg * On some ICL SKUs port F is not present, but broken VBTs mark
25705ca02815Sjsg * the port as present. Only try to initialize port F for the
25715ca02815Sjsg * SKUs that may actually have it.
25725ca02815Sjsg */
25735ca02815Sjsg if (port == PORT_F && IS_ICELAKE(i915))
25745ca02815Sjsg return IS_ICL_WITH_PORT_F(i915);
25755ca02815Sjsg
25765ca02815Sjsg return true;
25775ca02815Sjsg }
25785ca02815Sjsg
print_ddi_port(const struct intel_bios_encoder_data * devdata)2579f005ef32Sjsg static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
2580c349dbc7Sjsg {
25811bb76ff1Sjsg struct drm_i915_private *i915 = devdata->i915;
2582c349dbc7Sjsg const struct child_device_config *child = &devdata->child;
258354075a0eSjsg bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
25841bb76ff1Sjsg int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
2585f005ef32Sjsg enum port port;
2586f005ef32Sjsg
2587f005ef32Sjsg port = intel_bios_encoder_port(devdata);
2588f005ef32Sjsg if (port == PORT_NONE)
2589f005ef32Sjsg return;
2590c349dbc7Sjsg
25915ca02815Sjsg is_dvi = intel_bios_encoder_supports_dvi(devdata);
25925ca02815Sjsg is_dp = intel_bios_encoder_supports_dp(devdata);
25935ca02815Sjsg is_crt = intel_bios_encoder_supports_crt(devdata);
25945ca02815Sjsg is_hdmi = intel_bios_encoder_supports_hdmi(devdata);
25955ca02815Sjsg is_edp = intel_bios_encoder_supports_edp(devdata);
259654075a0eSjsg is_dsi = intel_bios_encoder_supports_dsi(devdata);
2597c349dbc7Sjsg
25985ca02815Sjsg supports_typec_usb = intel_bios_encoder_supports_typec_usb(devdata);
25995ca02815Sjsg supports_tbt = intel_bios_encoder_supports_tbt(devdata);
2600c349dbc7Sjsg
26015ca02815Sjsg drm_dbg_kms(&i915->drm,
2602f005ef32Sjsg "Port %c VBT info: CRT:%d DVI:%d HDMI:%d DP:%d eDP:%d DSI:%d DP++:%d LSPCON:%d USB-Type-C:%d TBT:%d DSC:%d\n",
260354075a0eSjsg port_name(port), is_crt, is_dvi, is_hdmi, is_dp, is_edp, is_dsi,
2604f005ef32Sjsg intel_bios_encoder_supports_dp_dual_mode(devdata),
2605f005ef32Sjsg intel_bios_encoder_is_lspcon(devdata),
26065ca02815Sjsg supports_typec_usb, supports_tbt,
2607c349dbc7Sjsg devdata->dsc != NULL);
2608c349dbc7Sjsg
2609f005ef32Sjsg hdmi_level_shift = intel_bios_hdmi_level_shift(devdata);
26101bb76ff1Sjsg if (hdmi_level_shift >= 0) {
26115ca02815Sjsg drm_dbg_kms(&i915->drm,
26125ca02815Sjsg "Port %c VBT HDMI level shift: %d\n",
26131bb76ff1Sjsg port_name(port), hdmi_level_shift);
2614c349dbc7Sjsg }
2615c349dbc7Sjsg
2616f005ef32Sjsg max_tmds_clock = intel_bios_hdmi_max_tmds_clock(devdata);
2617c349dbc7Sjsg if (max_tmds_clock)
26185ca02815Sjsg drm_dbg_kms(&i915->drm,
26195ca02815Sjsg "Port %c VBT HDMI max TMDS clock: %d kHz\n",
2620c349dbc7Sjsg port_name(port), max_tmds_clock);
2621c349dbc7Sjsg
26225ca02815Sjsg /* I_boost config for SKL and above */
2623f005ef32Sjsg dp_boost_level = intel_bios_dp_boost_level(devdata);
26245ca02815Sjsg if (dp_boost_level)
26255ca02815Sjsg drm_dbg_kms(&i915->drm,
26265ca02815Sjsg "Port %c VBT (e)DP boost level: %d\n",
26275ca02815Sjsg port_name(port), dp_boost_level);
2628c349dbc7Sjsg
2629f005ef32Sjsg hdmi_boost_level = intel_bios_hdmi_boost_level(devdata);
26305ca02815Sjsg if (hdmi_boost_level)
26315ca02815Sjsg drm_dbg_kms(&i915->drm,
26325ca02815Sjsg "Port %c VBT HDMI boost level: %d\n",
26335ca02815Sjsg port_name(port), hdmi_boost_level);
26345ca02815Sjsg
2635f005ef32Sjsg dp_max_link_rate = intel_bios_dp_max_link_rate(devdata);
26361bb76ff1Sjsg if (dp_max_link_rate)
26375ca02815Sjsg drm_dbg_kms(&i915->drm,
26385ca02815Sjsg "Port %c VBT DP max link rate: %d\n",
26391bb76ff1Sjsg port_name(port), dp_max_link_rate);
2640f005ef32Sjsg
2641f005ef32Sjsg /*
2642f005ef32Sjsg * FIXME need to implement support for VBT
2643f005ef32Sjsg * vswing/preemph tables should this ever trigger.
2644f005ef32Sjsg */
2645f005ef32Sjsg drm_WARN(&i915->drm, child->use_vbt_vswing,
2646f005ef32Sjsg "Port %c asks to use VBT vswing/preemph tables\n",
2647f005ef32Sjsg port_name(port));
2648c349dbc7Sjsg }
2649c349dbc7Sjsg
parse_ddi_port(struct intel_bios_encoder_data * devdata)26501bb76ff1Sjsg static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
26511bb76ff1Sjsg {
26521bb76ff1Sjsg struct drm_i915_private *i915 = devdata->i915;
26531bb76ff1Sjsg enum port port;
26541bb76ff1Sjsg
2655f005ef32Sjsg port = intel_bios_encoder_port(devdata);
26561bb76ff1Sjsg if (port == PORT_NONE)
26571bb76ff1Sjsg return;
26581bb76ff1Sjsg
26591bb76ff1Sjsg if (!is_port_valid(i915, port)) {
26601bb76ff1Sjsg drm_dbg_kms(&i915->drm,
26611bb76ff1Sjsg "VBT reports port %c as supported, but that can't be true: skipping\n",
26621bb76ff1Sjsg port_name(port));
26631bb76ff1Sjsg return;
26641bb76ff1Sjsg }
26651bb76ff1Sjsg
26661bb76ff1Sjsg sanitize_device_type(devdata, port);
26671bb76ff1Sjsg }
26681bb76ff1Sjsg
has_ddi_port_info(struct drm_i915_private * i915)26691bb76ff1Sjsg static bool has_ddi_port_info(struct drm_i915_private *i915)
26701bb76ff1Sjsg {
26711bb76ff1Sjsg return DISPLAY_VER(i915) >= 5 || IS_G4X(i915);
2672c349dbc7Sjsg }
2673c349dbc7Sjsg
parse_ddi_ports(struct drm_i915_private * i915)26745ca02815Sjsg static void parse_ddi_ports(struct drm_i915_private *i915)
2675c349dbc7Sjsg {
26765ca02815Sjsg struct intel_bios_encoder_data *devdata;
2677c349dbc7Sjsg
26781bb76ff1Sjsg if (!has_ddi_port_info(i915))
2679c349dbc7Sjsg return;
2680c349dbc7Sjsg
26811bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
26821bb76ff1Sjsg parse_ddi_port(devdata);
2683c349dbc7Sjsg
2684f005ef32Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
2685f005ef32Sjsg print_ddi_port(devdata);
2686c349dbc7Sjsg }
2687c349dbc7Sjsg
2688c349dbc7Sjsg static void
parse_general_definitions(struct drm_i915_private * i915)26891bb76ff1Sjsg parse_general_definitions(struct drm_i915_private *i915)
2690c349dbc7Sjsg {
2691c349dbc7Sjsg const struct bdb_general_definitions *defs;
26925ca02815Sjsg struct intel_bios_encoder_data *devdata;
2693c349dbc7Sjsg const struct child_device_config *child;
2694c349dbc7Sjsg int i, child_device_num;
2695c349dbc7Sjsg u8 expected_size;
2696c349dbc7Sjsg u16 block_size;
2697c349dbc7Sjsg int bus_pin;
2698c349dbc7Sjsg
2699f005ef32Sjsg defs = bdb_find_section(i915, BDB_GENERAL_DEFINITIONS);
2700c349dbc7Sjsg if (!defs) {
27015ca02815Sjsg drm_dbg_kms(&i915->drm,
2702c349dbc7Sjsg "No general definition block is found, no devices defined.\n");
2703c349dbc7Sjsg return;
2704c349dbc7Sjsg }
2705c349dbc7Sjsg
2706c349dbc7Sjsg block_size = get_blocksize(defs);
2707c349dbc7Sjsg if (block_size < sizeof(*defs)) {
27085ca02815Sjsg drm_dbg_kms(&i915->drm,
2709c349dbc7Sjsg "General definitions block too small (%u)\n",
2710c349dbc7Sjsg block_size);
2711c349dbc7Sjsg return;
2712c349dbc7Sjsg }
2713c349dbc7Sjsg
2714c349dbc7Sjsg bus_pin = defs->crt_ddc_gmbus_pin;
27155ca02815Sjsg drm_dbg_kms(&i915->drm, "crt_ddc_bus_pin: %d\n", bus_pin);
27165ca02815Sjsg if (intel_gmbus_is_valid_pin(i915, bus_pin))
27171bb76ff1Sjsg i915->display.vbt.crt_ddc_pin = bus_pin;
2718c349dbc7Sjsg
27191bb76ff1Sjsg if (i915->display.vbt.version < 106) {
2720c349dbc7Sjsg expected_size = 22;
27211bb76ff1Sjsg } else if (i915->display.vbt.version < 111) {
2722c349dbc7Sjsg expected_size = 27;
27231bb76ff1Sjsg } else if (i915->display.vbt.version < 195) {
2724c349dbc7Sjsg expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE;
27251bb76ff1Sjsg } else if (i915->display.vbt.version == 195) {
2726c349dbc7Sjsg expected_size = 37;
27271bb76ff1Sjsg } else if (i915->display.vbt.version <= 215) {
2728c349dbc7Sjsg expected_size = 38;
2729f005ef32Sjsg } else if (i915->display.vbt.version <= 250) {
2730c349dbc7Sjsg expected_size = 39;
2731c349dbc7Sjsg } else {
2732c349dbc7Sjsg expected_size = sizeof(*child);
2733c349dbc7Sjsg BUILD_BUG_ON(sizeof(*child) < 39);
27345ca02815Sjsg drm_dbg(&i915->drm,
2735c349dbc7Sjsg "Expected child device config size for VBT version %u not known; assuming %u\n",
27361bb76ff1Sjsg i915->display.vbt.version, expected_size);
2737c349dbc7Sjsg }
2738c349dbc7Sjsg
2739c349dbc7Sjsg /* Flag an error for unexpected size, but continue anyway. */
2740c349dbc7Sjsg if (defs->child_dev_size != expected_size)
27415ca02815Sjsg drm_err(&i915->drm,
2742c349dbc7Sjsg "Unexpected child device config size %u (expected %u for VBT version %u)\n",
27431bb76ff1Sjsg defs->child_dev_size, expected_size, i915->display.vbt.version);
2744c349dbc7Sjsg
2745c349dbc7Sjsg /* The legacy sized child device config is the minimum we need. */
2746c349dbc7Sjsg if (defs->child_dev_size < LEGACY_CHILD_DEVICE_CONFIG_SIZE) {
27475ca02815Sjsg drm_dbg_kms(&i915->drm,
2748c349dbc7Sjsg "Child device config size %u is too small.\n",
2749c349dbc7Sjsg defs->child_dev_size);
2750c349dbc7Sjsg return;
2751c349dbc7Sjsg }
2752c349dbc7Sjsg
2753c349dbc7Sjsg /* get the number of child device */
2754c349dbc7Sjsg child_device_num = (block_size - sizeof(*defs)) / defs->child_dev_size;
2755c349dbc7Sjsg
2756c349dbc7Sjsg for (i = 0; i < child_device_num; i++) {
2757c349dbc7Sjsg child = child_device_ptr(defs, i);
2758c349dbc7Sjsg if (!child->device_type)
2759c349dbc7Sjsg continue;
2760c349dbc7Sjsg
27615ca02815Sjsg drm_dbg_kms(&i915->drm,
2762c349dbc7Sjsg "Found VBT child device with type 0x%x\n",
2763c349dbc7Sjsg child->device_type);
2764c349dbc7Sjsg
2765c349dbc7Sjsg devdata = kzalloc(sizeof(*devdata), GFP_KERNEL);
2766c349dbc7Sjsg if (!devdata)
2767c349dbc7Sjsg break;
2768c349dbc7Sjsg
27695ca02815Sjsg devdata->i915 = i915;
27705ca02815Sjsg
2771c349dbc7Sjsg /*
2772c349dbc7Sjsg * Copy as much as we know (sizeof) and is available
2773c349dbc7Sjsg * (child_dev_size) of the child device config. Accessing the
2774c349dbc7Sjsg * data must depend on VBT version.
2775c349dbc7Sjsg */
2776c349dbc7Sjsg memcpy(&devdata->child, child,
2777c349dbc7Sjsg min_t(size_t, defs->child_dev_size, sizeof(*child)));
2778c349dbc7Sjsg
27791bb76ff1Sjsg list_add_tail(&devdata->node, &i915->display.vbt.display_devices);
2780c349dbc7Sjsg }
2781c349dbc7Sjsg
27821bb76ff1Sjsg if (list_empty(&i915->display.vbt.display_devices))
27835ca02815Sjsg drm_dbg_kms(&i915->drm,
2784c349dbc7Sjsg "no child dev is parsed from VBT\n");
2785c349dbc7Sjsg }
2786c349dbc7Sjsg
2787c349dbc7Sjsg /* Common defaults which may be overridden by VBT. */
2788c349dbc7Sjsg static void
init_vbt_defaults(struct drm_i915_private * i915)27895ca02815Sjsg init_vbt_defaults(struct drm_i915_private *i915)
2790c349dbc7Sjsg {
27911bb76ff1Sjsg i915->display.vbt.crt_ddc_pin = GMBUS_PIN_VGADDC;
2792c349dbc7Sjsg
2793c349dbc7Sjsg /* general features */
27941bb76ff1Sjsg i915->display.vbt.int_tv_support = 1;
27951bb76ff1Sjsg i915->display.vbt.int_crt_support = 1;
2796c349dbc7Sjsg
2797c349dbc7Sjsg /* driver features */
27981bb76ff1Sjsg i915->display.vbt.int_lvds_support = 1;
2799c349dbc7Sjsg
2800c349dbc7Sjsg /* Default to using SSC */
28011bb76ff1Sjsg i915->display.vbt.lvds_use_ssc = 1;
2802c349dbc7Sjsg /*
2803c349dbc7Sjsg * Core/SandyBridge/IvyBridge use alternative (120MHz) reference
2804c349dbc7Sjsg * clock for LVDS.
2805c349dbc7Sjsg */
28061bb76ff1Sjsg i915->display.vbt.lvds_ssc_freq = intel_bios_ssc_frequency(i915,
28075ca02815Sjsg !HAS_PCH_SPLIT(i915));
28085ca02815Sjsg drm_dbg_kms(&i915->drm, "Set default to SSC at %d kHz\n",
28091bb76ff1Sjsg i915->display.vbt.lvds_ssc_freq);
28101bb76ff1Sjsg }
28111bb76ff1Sjsg
28121bb76ff1Sjsg /* Common defaults which may be overridden by VBT. */
28131bb76ff1Sjsg static void
init_vbt_panel_defaults(struct intel_panel * panel)28141bb76ff1Sjsg init_vbt_panel_defaults(struct intel_panel *panel)
28151bb76ff1Sjsg {
28161bb76ff1Sjsg /* Default to having backlight */
28171bb76ff1Sjsg panel->vbt.backlight.present = true;
28181bb76ff1Sjsg
28191bb76ff1Sjsg /* LFP panel data */
28201bb76ff1Sjsg panel->vbt.lvds_dither = true;
2821c349dbc7Sjsg }
2822c349dbc7Sjsg
2823c349dbc7Sjsg /* Defaults to initialize only if there is no VBT. */
2824c349dbc7Sjsg static void
init_vbt_missing_defaults(struct drm_i915_private * i915)28255ca02815Sjsg init_vbt_missing_defaults(struct drm_i915_private *i915)
2826c349dbc7Sjsg {
2827c349dbc7Sjsg enum port port;
28285ca02815Sjsg int ports = BIT(PORT_A) | BIT(PORT_B) | BIT(PORT_C) |
28295ca02815Sjsg BIT(PORT_D) | BIT(PORT_E) | BIT(PORT_F);
2830c349dbc7Sjsg
28315ca02815Sjsg if (!HAS_DDI(i915) && !IS_CHERRYVIEW(i915))
28325ca02815Sjsg return;
28335ca02815Sjsg
28345ca02815Sjsg for_each_port_masked(port, ports) {
28355ca02815Sjsg struct intel_bios_encoder_data *devdata;
28365ca02815Sjsg struct child_device_config *child;
28375ca02815Sjsg enum phy phy = intel_port_to_phy(i915, port);
2838c349dbc7Sjsg
2839c349dbc7Sjsg /*
2840c349dbc7Sjsg * VBT has the TypeC mode (native,TBT/USB) and we don't want
2841c349dbc7Sjsg * to detect it.
2842c349dbc7Sjsg */
28435ca02815Sjsg if (intel_phy_is_tc(i915, phy))
2844c349dbc7Sjsg continue;
2845c349dbc7Sjsg
28465ca02815Sjsg /* Create fake child device config */
28475ca02815Sjsg devdata = kzalloc(sizeof(*devdata), GFP_KERNEL);
28485ca02815Sjsg if (!devdata)
28495ca02815Sjsg break;
28505ca02815Sjsg
28515ca02815Sjsg devdata->i915 = i915;
28525ca02815Sjsg child = &devdata->child;
28535ca02815Sjsg
28545ca02815Sjsg if (port == PORT_F)
28555ca02815Sjsg child->dvo_port = DVO_PORT_HDMIF;
28565ca02815Sjsg else if (port == PORT_E)
28575ca02815Sjsg child->dvo_port = DVO_PORT_HDMIE;
28585ca02815Sjsg else
28595ca02815Sjsg child->dvo_port = DVO_PORT_HDMIA + port;
28605ca02815Sjsg
28615ca02815Sjsg if (port != PORT_A && port != PORT_E)
28625ca02815Sjsg child->device_type |= DEVICE_TYPE_TMDS_DVI_SIGNALING;
28635ca02815Sjsg
28645ca02815Sjsg if (port != PORT_E)
28655ca02815Sjsg child->device_type |= DEVICE_TYPE_DISPLAYPORT_OUTPUT;
28665ca02815Sjsg
28675ca02815Sjsg if (port == PORT_A)
28685ca02815Sjsg child->device_type |= DEVICE_TYPE_INTERNAL_CONNECTOR;
28695ca02815Sjsg
28701bb76ff1Sjsg list_add_tail(&devdata->node, &i915->display.vbt.display_devices);
28715ca02815Sjsg
28725ca02815Sjsg drm_dbg_kms(&i915->drm,
28735ca02815Sjsg "Generating default VBT child device with type 0x04%x on port %c\n",
28745ca02815Sjsg child->device_type, port_name(port));
2875c349dbc7Sjsg }
28765ca02815Sjsg
28775ca02815Sjsg /* Bypass some minimum baseline VBT version checks */
28781bb76ff1Sjsg i915->display.vbt.version = 155;
2879c349dbc7Sjsg }
2880c349dbc7Sjsg
get_bdb_header(const struct vbt_header * vbt)2881c349dbc7Sjsg static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
2882c349dbc7Sjsg {
2883c349dbc7Sjsg const void *_vbt = vbt;
2884c349dbc7Sjsg
2885c349dbc7Sjsg return _vbt + vbt->bdb_offset;
2886c349dbc7Sjsg }
2887c349dbc7Sjsg
2888c349dbc7Sjsg #include <dev/isa/isareg.h>
2889c349dbc7Sjsg #include <dev/isa/isavar.h>
2890c349dbc7Sjsg
2891c349dbc7Sjsg #define VGA_BIOS_ADDR 0xc0000
2892c349dbc7Sjsg #define VGA_BIOS_LEN 0x10000
2893c349dbc7Sjsg
2894c349dbc7Sjsg /**
2895c349dbc7Sjsg * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT
2896c349dbc7Sjsg * @buf: pointer to a buffer to validate
2897c349dbc7Sjsg * @size: size of the buffer
2898c349dbc7Sjsg *
2899c349dbc7Sjsg * Returns true on valid VBT.
2900c349dbc7Sjsg */
intel_bios_is_valid_vbt(const void * buf,size_t size)2901c349dbc7Sjsg bool intel_bios_is_valid_vbt(const void *buf, size_t size)
2902c349dbc7Sjsg {
2903c349dbc7Sjsg const struct vbt_header *vbt = buf;
2904c349dbc7Sjsg const struct bdb_header *bdb;
2905c349dbc7Sjsg
2906c349dbc7Sjsg if (!vbt)
2907c349dbc7Sjsg return false;
2908c349dbc7Sjsg
2909c349dbc7Sjsg if (sizeof(struct vbt_header) > size) {
2910c349dbc7Sjsg DRM_DEBUG_DRIVER("VBT header incomplete\n");
2911c349dbc7Sjsg return false;
2912c349dbc7Sjsg }
2913c349dbc7Sjsg
2914c349dbc7Sjsg if (memcmp(vbt->signature, "$VBT", 4)) {
2915c349dbc7Sjsg DRM_DEBUG_DRIVER("VBT invalid signature\n");
2916c349dbc7Sjsg return false;
2917c349dbc7Sjsg }
2918c349dbc7Sjsg
2919c349dbc7Sjsg if (vbt->vbt_size > size) {
2920c349dbc7Sjsg DRM_DEBUG_DRIVER("VBT incomplete (vbt_size overflows)\n");
2921c349dbc7Sjsg return false;
2922c349dbc7Sjsg }
2923c349dbc7Sjsg
2924c349dbc7Sjsg size = vbt->vbt_size;
2925c349dbc7Sjsg
2926c349dbc7Sjsg if (range_overflows_t(size_t,
2927c349dbc7Sjsg vbt->bdb_offset,
2928c349dbc7Sjsg sizeof(struct bdb_header),
2929c349dbc7Sjsg size)) {
2930c349dbc7Sjsg DRM_DEBUG_DRIVER("BDB header incomplete\n");
2931c349dbc7Sjsg return false;
2932c349dbc7Sjsg }
2933c349dbc7Sjsg
2934c349dbc7Sjsg bdb = get_bdb_header(vbt);
2935c349dbc7Sjsg if (range_overflows_t(size_t, vbt->bdb_offset, bdb->bdb_size, size)) {
2936c349dbc7Sjsg DRM_DEBUG_DRIVER("BDB incomplete\n");
2937c349dbc7Sjsg return false;
2938c349dbc7Sjsg }
2939c349dbc7Sjsg
2940c349dbc7Sjsg return vbt;
2941c349dbc7Sjsg }
2942c349dbc7Sjsg
intel_spi_read(struct intel_uncore * uncore,u32 offset)2943f005ef32Sjsg static u32 intel_spi_read(struct intel_uncore *uncore, u32 offset)
2944f005ef32Sjsg {
2945f005ef32Sjsg intel_uncore_write(uncore, PRIMARY_SPI_ADDRESS, offset);
2946f005ef32Sjsg
2947f005ef32Sjsg return intel_uncore_read(uncore, PRIMARY_SPI_TRIGGER);
2948f005ef32Sjsg }
2949f005ef32Sjsg
spi_oprom_get_vbt(struct drm_i915_private * i915)29501bb76ff1Sjsg static struct vbt_header *spi_oprom_get_vbt(struct drm_i915_private *i915)
29511bb76ff1Sjsg {
29521bb76ff1Sjsg u32 count, data, found, store = 0;
29531bb76ff1Sjsg u32 static_region, oprom_offset;
29541bb76ff1Sjsg u32 oprom_size = 0x200000;
29551bb76ff1Sjsg u16 vbt_size;
29561bb76ff1Sjsg u32 *vbt;
29571bb76ff1Sjsg
29581bb76ff1Sjsg static_region = intel_uncore_read(&i915->uncore, SPI_STATIC_REGIONS);
29591bb76ff1Sjsg static_region &= OPTIONROM_SPI_REGIONID_MASK;
29601bb76ff1Sjsg intel_uncore_write(&i915->uncore, PRIMARY_SPI_REGIONID, static_region);
29611bb76ff1Sjsg
29621bb76ff1Sjsg oprom_offset = intel_uncore_read(&i915->uncore, OROM_OFFSET);
29631bb76ff1Sjsg oprom_offset &= OROM_OFFSET_MASK;
29641bb76ff1Sjsg
29651bb76ff1Sjsg for (count = 0; count < oprom_size; count += 4) {
2966f005ef32Sjsg data = intel_spi_read(&i915->uncore, oprom_offset + count);
29671bb76ff1Sjsg if (data == *((const u32 *)"$VBT")) {
29681bb76ff1Sjsg found = oprom_offset + count;
29691bb76ff1Sjsg break;
29701bb76ff1Sjsg }
29711bb76ff1Sjsg }
29721bb76ff1Sjsg
29731bb76ff1Sjsg if (count >= oprom_size)
29741bb76ff1Sjsg goto err_not_found;
29751bb76ff1Sjsg
29761bb76ff1Sjsg /* Get VBT size and allocate space for the VBT */
2977f005ef32Sjsg vbt_size = intel_spi_read(&i915->uncore,
2978f005ef32Sjsg found + offsetof(struct vbt_header, vbt_size));
29791bb76ff1Sjsg vbt_size &= 0xffff;
29801bb76ff1Sjsg
29811bb76ff1Sjsg vbt = kzalloc(round_up(vbt_size, 4), GFP_KERNEL);
29821bb76ff1Sjsg if (!vbt)
29831bb76ff1Sjsg goto err_not_found;
29841bb76ff1Sjsg
2985f005ef32Sjsg for (count = 0; count < vbt_size; count += 4)
2986f005ef32Sjsg *(vbt + store++) = intel_spi_read(&i915->uncore, found + count);
29871bb76ff1Sjsg
29881bb76ff1Sjsg if (!intel_bios_is_valid_vbt(vbt, vbt_size))
29891bb76ff1Sjsg goto err_free_vbt;
29901bb76ff1Sjsg
29911bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Found valid VBT in SPI flash\n");
29921bb76ff1Sjsg
29931bb76ff1Sjsg return (struct vbt_header *)vbt;
29941bb76ff1Sjsg
29951bb76ff1Sjsg err_free_vbt:
29961bb76ff1Sjsg kfree(vbt);
29971bb76ff1Sjsg err_not_found:
29981bb76ff1Sjsg return NULL;
29991bb76ff1Sjsg }
30001bb76ff1Sjsg
oprom_get_vbt(struct drm_i915_private * i915)30015ca02815Sjsg static struct vbt_header *oprom_get_vbt(struct drm_i915_private *i915)
3002c349dbc7Sjsg {
3003c349dbc7Sjsg #ifdef __linux__
30045ca02815Sjsg struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
3005c349dbc7Sjsg #endif
3006c349dbc7Sjsg void __iomem *p = NULL, *oprom;
3007c349dbc7Sjsg struct vbt_header *vbt;
3008c349dbc7Sjsg u16 vbt_size;
3009c349dbc7Sjsg size_t i, size;
3010c349dbc7Sjsg
3011c349dbc7Sjsg #ifdef __linux__
3012c349dbc7Sjsg oprom = pci_map_rom(pdev, &size);
3013c349dbc7Sjsg if (!oprom)
3014c349dbc7Sjsg return NULL;
3015c349dbc7Sjsg #else
3016c349dbc7Sjsg oprom = (u8 *)ISA_HOLE_VADDR(VGA_BIOS_ADDR);
3017c349dbc7Sjsg size = VGA_BIOS_LEN;
3018c349dbc7Sjsg #endif
3019c349dbc7Sjsg
3020c349dbc7Sjsg /* Scour memory looking for the VBT signature. */
3021c349dbc7Sjsg for (i = 0; i + 4 < size; i += 4) {
3022c349dbc7Sjsg if (ioread32(oprom + i) != *((const u32 *)"$VBT"))
3023c349dbc7Sjsg continue;
3024c349dbc7Sjsg
3025c349dbc7Sjsg p = oprom + i;
3026c349dbc7Sjsg size -= i;
3027c349dbc7Sjsg break;
3028c349dbc7Sjsg }
3029c349dbc7Sjsg
3030c349dbc7Sjsg if (!p)
3031c349dbc7Sjsg goto err_unmap_oprom;
3032c349dbc7Sjsg
3033c349dbc7Sjsg if (sizeof(struct vbt_header) > size) {
30345ca02815Sjsg drm_dbg(&i915->drm, "VBT header incomplete\n");
3035c349dbc7Sjsg goto err_unmap_oprom;
3036c349dbc7Sjsg }
3037c349dbc7Sjsg
3038c349dbc7Sjsg vbt_size = ioread16(p + offsetof(struct vbt_header, vbt_size));
3039c349dbc7Sjsg if (vbt_size > size) {
30405ca02815Sjsg drm_dbg(&i915->drm,
3041c349dbc7Sjsg "VBT incomplete (vbt_size overflows)\n");
3042c349dbc7Sjsg goto err_unmap_oprom;
3043c349dbc7Sjsg }
3044c349dbc7Sjsg
3045c349dbc7Sjsg /* The rest will be validated by intel_bios_is_valid_vbt() */
3046c349dbc7Sjsg vbt = kmalloc(vbt_size, GFP_KERNEL);
3047c349dbc7Sjsg if (!vbt)
3048c349dbc7Sjsg goto err_unmap_oprom;
3049c349dbc7Sjsg
3050c349dbc7Sjsg memcpy_fromio(vbt, p, vbt_size);
3051c349dbc7Sjsg
3052c349dbc7Sjsg if (!intel_bios_is_valid_vbt(vbt, vbt_size))
3053c349dbc7Sjsg goto err_free_vbt;
3054c349dbc7Sjsg
3055c349dbc7Sjsg #ifdef __linux__
3056c349dbc7Sjsg pci_unmap_rom(pdev, oprom);
3057c349dbc7Sjsg #endif
3058c349dbc7Sjsg
30591bb76ff1Sjsg drm_dbg_kms(&i915->drm, "Found valid VBT in PCI ROM\n");
30601bb76ff1Sjsg
3061c349dbc7Sjsg return vbt;
3062c349dbc7Sjsg
3063c349dbc7Sjsg err_free_vbt:
3064c349dbc7Sjsg kfree(vbt);
3065c349dbc7Sjsg err_unmap_oprom:
3066c349dbc7Sjsg #ifdef __linux__
3067c349dbc7Sjsg pci_unmap_rom(pdev, oprom);
3068c349dbc7Sjsg #endif
3069c349dbc7Sjsg
3070c349dbc7Sjsg return NULL;
3071c349dbc7Sjsg }
3072c349dbc7Sjsg
3073c349dbc7Sjsg /**
3074c349dbc7Sjsg * intel_bios_init - find VBT and initialize settings from the BIOS
30755ca02815Sjsg * @i915: i915 device instance
3076c349dbc7Sjsg *
3077c349dbc7Sjsg * Parse and initialize settings from the Video BIOS Tables (VBT). If the VBT
3078c349dbc7Sjsg * was not found in ACPI OpRegion, try to find it in PCI ROM first. Also
3079c349dbc7Sjsg * initialize some defaults if the VBT is not present at all.
3080c349dbc7Sjsg */
intel_bios_init(struct drm_i915_private * i915)30815ca02815Sjsg void intel_bios_init(struct drm_i915_private *i915)
3082c349dbc7Sjsg {
30831bb76ff1Sjsg const struct vbt_header *vbt = i915->display.opregion.vbt;
3084c349dbc7Sjsg struct vbt_header *oprom_vbt = NULL;
3085c349dbc7Sjsg const struct bdb_header *bdb;
3086c349dbc7Sjsg
30871bb76ff1Sjsg INIT_LIST_HEAD(&i915->display.vbt.display_devices);
30881bb76ff1Sjsg INIT_LIST_HEAD(&i915->display.vbt.bdb_blocks);
3089c349dbc7Sjsg
30905ca02815Sjsg if (!HAS_DISPLAY(i915)) {
30915ca02815Sjsg drm_dbg_kms(&i915->drm,
3092c349dbc7Sjsg "Skipping VBT init due to disabled display.\n");
3093c349dbc7Sjsg return;
3094c349dbc7Sjsg }
3095c349dbc7Sjsg
30965ca02815Sjsg init_vbt_defaults(i915);
3097c349dbc7Sjsg
30981bb76ff1Sjsg /*
30991bb76ff1Sjsg * If the OpRegion does not have VBT, look in SPI flash through MMIO or
31001bb76ff1Sjsg * PCI mapping
31011bb76ff1Sjsg */
31021bb76ff1Sjsg if (!vbt && IS_DGFX(i915)) {
31031bb76ff1Sjsg oprom_vbt = spi_oprom_get_vbt(i915);
3104c349dbc7Sjsg vbt = oprom_vbt;
3105c349dbc7Sjsg }
3106c349dbc7Sjsg
31071bb76ff1Sjsg if (!vbt) {
31081bb76ff1Sjsg oprom_vbt = oprom_get_vbt(i915);
31091bb76ff1Sjsg vbt = oprom_vbt;
31101bb76ff1Sjsg }
31111bb76ff1Sjsg
31121bb76ff1Sjsg if (!vbt)
31131bb76ff1Sjsg goto out;
31141bb76ff1Sjsg
3115c349dbc7Sjsg bdb = get_bdb_header(vbt);
31161bb76ff1Sjsg i915->display.vbt.version = bdb->version;
3117c349dbc7Sjsg
31185ca02815Sjsg drm_dbg_kms(&i915->drm,
3119c349dbc7Sjsg "VBT signature \"%.*s\", BDB version %d\n",
31201bb76ff1Sjsg (int)sizeof(vbt->signature), vbt->signature, i915->display.vbt.version);
31211bb76ff1Sjsg
31221bb76ff1Sjsg init_bdb_blocks(i915, bdb);
3123c349dbc7Sjsg
3124c349dbc7Sjsg /* Grab useful general definitions */
31251bb76ff1Sjsg parse_general_features(i915);
31261bb76ff1Sjsg parse_general_definitions(i915);
31271bb76ff1Sjsg parse_driver_features(i915);
3128c349dbc7Sjsg
3129c349dbc7Sjsg /* Depends on child device list */
31301bb76ff1Sjsg parse_compression_parameters(i915);
3131c349dbc7Sjsg
3132c349dbc7Sjsg out:
3133c349dbc7Sjsg if (!vbt) {
31345ca02815Sjsg drm_info(&i915->drm,
3135c349dbc7Sjsg "Failed to find VBIOS tables (VBT)\n");
31365ca02815Sjsg init_vbt_missing_defaults(i915);
3137c349dbc7Sjsg }
3138c349dbc7Sjsg
31395ca02815Sjsg /* Further processing on pre-parsed or generated child device data */
31405ca02815Sjsg parse_sdvo_device_mapping(i915);
31415ca02815Sjsg parse_ddi_ports(i915);
31425ca02815Sjsg
3143c349dbc7Sjsg kfree(oprom_vbt);
3144c349dbc7Sjsg }
3145c349dbc7Sjsg
intel_bios_init_panel(struct drm_i915_private * i915,struct intel_panel * panel,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid,bool use_fallback)314626d05183Sjsg static void intel_bios_init_panel(struct drm_i915_private *i915,
31471bb76ff1Sjsg struct intel_panel *panel,
31481bb76ff1Sjsg const struct intel_bios_encoder_data *devdata,
3149f005ef32Sjsg const struct drm_edid *drm_edid,
315026d05183Sjsg bool use_fallback)
31511bb76ff1Sjsg {
315226d05183Sjsg /* already have it? */
315326d05183Sjsg if (panel->vbt.panel_type >= 0) {
315426d05183Sjsg drm_WARN_ON(&i915->drm, !use_fallback);
315526d05183Sjsg return;
315626d05183Sjsg }
31571bb76ff1Sjsg
315826d05183Sjsg panel->vbt.panel_type = get_panel_type(i915, devdata,
3159f005ef32Sjsg drm_edid, use_fallback);
316026d05183Sjsg if (panel->vbt.panel_type < 0) {
316126d05183Sjsg drm_WARN_ON(&i915->drm, use_fallback);
316226d05183Sjsg return;
316326d05183Sjsg }
316426d05183Sjsg
316526d05183Sjsg init_vbt_panel_defaults(panel);
31661bb76ff1Sjsg
31671bb76ff1Sjsg parse_panel_options(i915, panel);
31681bb76ff1Sjsg parse_generic_dtd(i915, panel);
31691bb76ff1Sjsg parse_lfp_data(i915, panel);
31701bb76ff1Sjsg parse_lfp_backlight(i915, panel);
31711bb76ff1Sjsg parse_sdvo_panel_data(i915, panel);
31721bb76ff1Sjsg parse_panel_driver_features(i915, panel);
31731bb76ff1Sjsg parse_power_conservation_features(i915, panel);
31741bb76ff1Sjsg parse_edp(i915, panel);
31751bb76ff1Sjsg parse_psr(i915, panel);
31761bb76ff1Sjsg parse_mipi_config(i915, panel);
31771bb76ff1Sjsg parse_mipi_sequence(i915, panel);
31781bb76ff1Sjsg }
31791bb76ff1Sjsg
intel_bios_init_panel_early(struct drm_i915_private * i915,struct intel_panel * panel,const struct intel_bios_encoder_data * devdata)318026d05183Sjsg void intel_bios_init_panel_early(struct drm_i915_private *i915,
318126d05183Sjsg struct intel_panel *panel,
318226d05183Sjsg const struct intel_bios_encoder_data *devdata)
318326d05183Sjsg {
318426d05183Sjsg intel_bios_init_panel(i915, panel, devdata, NULL, false);
318526d05183Sjsg }
318626d05183Sjsg
intel_bios_init_panel_late(struct drm_i915_private * i915,struct intel_panel * panel,const struct intel_bios_encoder_data * devdata,const struct drm_edid * drm_edid)318726d05183Sjsg void intel_bios_init_panel_late(struct drm_i915_private *i915,
318826d05183Sjsg struct intel_panel *panel,
318926d05183Sjsg const struct intel_bios_encoder_data *devdata,
3190f005ef32Sjsg const struct drm_edid *drm_edid)
319126d05183Sjsg {
3192f005ef32Sjsg intel_bios_init_panel(i915, panel, devdata, drm_edid, true);
319326d05183Sjsg }
319426d05183Sjsg
3195c349dbc7Sjsg /**
3196c349dbc7Sjsg * intel_bios_driver_remove - Free any resources allocated by intel_bios_init()
31975ca02815Sjsg * @i915: i915 device instance
3198c349dbc7Sjsg */
intel_bios_driver_remove(struct drm_i915_private * i915)31995ca02815Sjsg void intel_bios_driver_remove(struct drm_i915_private *i915)
3200c349dbc7Sjsg {
32011bb76ff1Sjsg struct intel_bios_encoder_data *devdata, *nd;
32021bb76ff1Sjsg struct bdb_block_entry *entry, *ne;
3203c349dbc7Sjsg
32041bb76ff1Sjsg list_for_each_entry_safe(devdata, nd, &i915->display.vbt.display_devices, node) {
3205c349dbc7Sjsg list_del(&devdata->node);
3206c349dbc7Sjsg kfree(devdata->dsc);
3207c349dbc7Sjsg kfree(devdata);
3208c349dbc7Sjsg }
3209c349dbc7Sjsg
32101bb76ff1Sjsg list_for_each_entry_safe(entry, ne, &i915->display.vbt.bdb_blocks, node) {
32111bb76ff1Sjsg list_del(&entry->node);
32121bb76ff1Sjsg kfree(entry);
32131bb76ff1Sjsg }
32141bb76ff1Sjsg }
32151bb76ff1Sjsg
intel_bios_fini_panel(struct intel_panel * panel)32161bb76ff1Sjsg void intel_bios_fini_panel(struct intel_panel *panel)
32171bb76ff1Sjsg {
32181bb76ff1Sjsg kfree(panel->vbt.sdvo_lvds_vbt_mode);
32191bb76ff1Sjsg panel->vbt.sdvo_lvds_vbt_mode = NULL;
32201bb76ff1Sjsg kfree(panel->vbt.lfp_lvds_vbt_mode);
32211bb76ff1Sjsg panel->vbt.lfp_lvds_vbt_mode = NULL;
32221bb76ff1Sjsg kfree(panel->vbt.dsi.data);
32231bb76ff1Sjsg panel->vbt.dsi.data = NULL;
32241bb76ff1Sjsg kfree(panel->vbt.dsi.pps);
32251bb76ff1Sjsg panel->vbt.dsi.pps = NULL;
32261bb76ff1Sjsg kfree(panel->vbt.dsi.config);
32271bb76ff1Sjsg panel->vbt.dsi.config = NULL;
32281bb76ff1Sjsg kfree(panel->vbt.dsi.deassert_seq);
32291bb76ff1Sjsg panel->vbt.dsi.deassert_seq = NULL;
3230c349dbc7Sjsg }
3231c349dbc7Sjsg
3232c349dbc7Sjsg /**
3233c349dbc7Sjsg * intel_bios_is_tv_present - is integrated TV present in VBT
32345ca02815Sjsg * @i915: i915 device instance
3235c349dbc7Sjsg *
3236c349dbc7Sjsg * Return true if TV is present. If no child devices were parsed from VBT,
3237c349dbc7Sjsg * assume TV is present.
3238c349dbc7Sjsg */
intel_bios_is_tv_present(struct drm_i915_private * i915)32395ca02815Sjsg bool intel_bios_is_tv_present(struct drm_i915_private *i915)
3240c349dbc7Sjsg {
32415ca02815Sjsg const struct intel_bios_encoder_data *devdata;
3242c349dbc7Sjsg
32431bb76ff1Sjsg if (!i915->display.vbt.int_tv_support)
3244c349dbc7Sjsg return false;
3245c349dbc7Sjsg
32461bb76ff1Sjsg if (list_empty(&i915->display.vbt.display_devices))
3247c349dbc7Sjsg return true;
3248c349dbc7Sjsg
32491bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3250f005ef32Sjsg const struct child_device_config *child = &devdata->child;
3251c349dbc7Sjsg
3252c349dbc7Sjsg /*
3253c349dbc7Sjsg * If the device type is not TV, continue.
3254c349dbc7Sjsg */
3255c349dbc7Sjsg switch (child->device_type) {
3256c349dbc7Sjsg case DEVICE_TYPE_INT_TV:
3257c349dbc7Sjsg case DEVICE_TYPE_TV:
3258c349dbc7Sjsg case DEVICE_TYPE_TV_SVIDEO_COMPOSITE:
3259c349dbc7Sjsg break;
3260c349dbc7Sjsg default:
3261c349dbc7Sjsg continue;
3262c349dbc7Sjsg }
3263c349dbc7Sjsg /* Only when the addin_offset is non-zero, it is regarded
3264c349dbc7Sjsg * as present.
3265c349dbc7Sjsg */
3266c349dbc7Sjsg if (child->addin_offset)
3267c349dbc7Sjsg return true;
3268c349dbc7Sjsg }
3269c349dbc7Sjsg
3270c349dbc7Sjsg return false;
3271c349dbc7Sjsg }
3272c349dbc7Sjsg
3273c349dbc7Sjsg /**
3274c349dbc7Sjsg * intel_bios_is_lvds_present - is LVDS present in VBT
32755ca02815Sjsg * @i915: i915 device instance
3276c349dbc7Sjsg * @i2c_pin: i2c pin for LVDS if present
3277c349dbc7Sjsg *
3278c349dbc7Sjsg * Return true if LVDS is present. If no child devices were parsed from VBT,
3279c349dbc7Sjsg * assume LVDS is present.
3280c349dbc7Sjsg */
intel_bios_is_lvds_present(struct drm_i915_private * i915,u8 * i2c_pin)32815ca02815Sjsg bool intel_bios_is_lvds_present(struct drm_i915_private *i915, u8 *i2c_pin)
3282c349dbc7Sjsg {
32835ca02815Sjsg const struct intel_bios_encoder_data *devdata;
3284c349dbc7Sjsg
32851bb76ff1Sjsg if (list_empty(&i915->display.vbt.display_devices))
3286c349dbc7Sjsg return true;
3287c349dbc7Sjsg
32881bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3289f005ef32Sjsg const struct child_device_config *child = &devdata->child;
3290c349dbc7Sjsg
3291c349dbc7Sjsg /* If the device type is not LFP, continue.
3292c349dbc7Sjsg * We have to check both the new identifiers as well as the
3293c349dbc7Sjsg * old for compatibility with some BIOSes.
3294c349dbc7Sjsg */
3295c349dbc7Sjsg if (child->device_type != DEVICE_TYPE_INT_LFP &&
3296c349dbc7Sjsg child->device_type != DEVICE_TYPE_LFP)
3297c349dbc7Sjsg continue;
3298c349dbc7Sjsg
32995ca02815Sjsg if (intel_gmbus_is_valid_pin(i915, child->i2c_pin))
3300c349dbc7Sjsg *i2c_pin = child->i2c_pin;
3301c349dbc7Sjsg
3302c349dbc7Sjsg /* However, we cannot trust the BIOS writers to populate
3303c349dbc7Sjsg * the VBT correctly. Since LVDS requires additional
3304c349dbc7Sjsg * information from AIM blocks, a non-zero addin offset is
3305c349dbc7Sjsg * a good indicator that the LVDS is actually present.
3306c349dbc7Sjsg */
3307c349dbc7Sjsg if (child->addin_offset)
3308c349dbc7Sjsg return true;
3309c349dbc7Sjsg
3310c349dbc7Sjsg /* But even then some BIOS writers perform some black magic
3311c349dbc7Sjsg * and instantiate the device without reference to any
3312c349dbc7Sjsg * additional data. Trust that if the VBT was written into
3313c349dbc7Sjsg * the OpRegion then they have validated the LVDS's existence.
3314c349dbc7Sjsg */
33151bb76ff1Sjsg if (i915->display.opregion.vbt)
3316c349dbc7Sjsg return true;
3317c349dbc7Sjsg }
3318c349dbc7Sjsg
3319c349dbc7Sjsg return false;
3320c349dbc7Sjsg }
3321c349dbc7Sjsg
3322c349dbc7Sjsg /**
3323c349dbc7Sjsg * intel_bios_is_port_present - is the specified digital port present
33245ca02815Sjsg * @i915: i915 device instance
3325c349dbc7Sjsg * @port: port to check
3326c349dbc7Sjsg *
3327c349dbc7Sjsg * Return true if the device in %port is present.
3328c349dbc7Sjsg */
intel_bios_is_port_present(struct drm_i915_private * i915,enum port port)33295ca02815Sjsg bool intel_bios_is_port_present(struct drm_i915_private *i915, enum port port)
3330c349dbc7Sjsg {
3331f005ef32Sjsg const struct intel_bios_encoder_data *devdata;
3332f005ef32Sjsg
33331bb76ff1Sjsg if (WARN_ON(!has_ddi_port_info(i915)))
3334c349dbc7Sjsg return true;
3335c349dbc7Sjsg
3336f005ef32Sjsg if (!is_port_valid(i915, port))
333739642ac1Sjsg return false;
333839642ac1Sjsg
3339f005ef32Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3340f005ef32Sjsg const struct child_device_config *child = &devdata->child;
3341f005ef32Sjsg
3342f005ef32Sjsg if (dvo_port_to_port(i915, child->dvo_port) == port)
3343f005ef32Sjsg return true;
33445ca02815Sjsg }
33455ca02815Sjsg
3346f005ef32Sjsg return false;
3347f005ef32Sjsg }
3348f005ef32Sjsg
intel_bios_encoder_supports_dp_dual_mode(const struct intel_bios_encoder_data * devdata)3349f005ef32Sjsg bool intel_bios_encoder_supports_dp_dual_mode(const struct intel_bios_encoder_data *devdata)
33505ca02815Sjsg {
33511bb76ff1Sjsg const struct child_device_config *child = &devdata->child;
33521bb76ff1Sjsg
3353818037a2Sjsg if (!devdata)
3354818037a2Sjsg return false;
3355818037a2Sjsg
33561bb76ff1Sjsg if (!intel_bios_encoder_supports_dp(devdata) ||
33571bb76ff1Sjsg !intel_bios_encoder_supports_hdmi(devdata))
33585ca02815Sjsg return false;
33595ca02815Sjsg
33605ca02815Sjsg if (dvo_port_type(child->dvo_port) == DVO_PORT_DPA)
33615ca02815Sjsg return true;
33625ca02815Sjsg
33635ca02815Sjsg /* Only accept a HDMI dvo_port as DP++ if it has an AUX channel */
33645ca02815Sjsg if (dvo_port_type(child->dvo_port) == DVO_PORT_HDMIA &&
33655ca02815Sjsg child->aux_channel != 0)
33665ca02815Sjsg return true;
33675ca02815Sjsg
33685ca02815Sjsg return false;
33695ca02815Sjsg }
33705ca02815Sjsg
3371c349dbc7Sjsg /**
3372c349dbc7Sjsg * intel_bios_is_dsi_present - is DSI present in VBT
33735ca02815Sjsg * @i915: i915 device instance
3374c349dbc7Sjsg * @port: port for DSI if present
3375c349dbc7Sjsg *
3376c349dbc7Sjsg * Return true if DSI is present, and return the port in %port.
3377c349dbc7Sjsg */
intel_bios_is_dsi_present(struct drm_i915_private * i915,enum port * port)33785ca02815Sjsg bool intel_bios_is_dsi_present(struct drm_i915_private *i915,
3379c349dbc7Sjsg enum port *port)
3380c349dbc7Sjsg {
33815ca02815Sjsg const struct intel_bios_encoder_data *devdata;
3382c349dbc7Sjsg
33831bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3384f005ef32Sjsg const struct child_device_config *child = &devdata->child;
3385f005ef32Sjsg u8 dvo_port = child->dvo_port;
3386c349dbc7Sjsg
3387c349dbc7Sjsg if (!(child->device_type & DEVICE_TYPE_MIPI_OUTPUT))
3388c349dbc7Sjsg continue;
3389c349dbc7Sjsg
339050603113Sjsg if (dsi_dvo_port_to_port(i915, dvo_port) == PORT_NONE) {
33915ca02815Sjsg drm_dbg_kms(&i915->drm,
3392c349dbc7Sjsg "VBT has unsupported DSI port %c\n",
3393c349dbc7Sjsg port_name(dvo_port - DVO_PORT_MIPIA));
339450603113Sjsg continue;
3395c349dbc7Sjsg }
339650603113Sjsg
339750603113Sjsg if (port)
339850603113Sjsg *port = dsi_dvo_port_to_port(i915, dvo_port);
339950603113Sjsg return true;
3400c349dbc7Sjsg }
3401c349dbc7Sjsg
3402c349dbc7Sjsg return false;
3403c349dbc7Sjsg }
3404c349dbc7Sjsg
fill_dsc(struct intel_crtc_state * crtc_state,struct dsc_compression_parameters_entry * dsc,int dsc_max_bpc)3405c349dbc7Sjsg static void fill_dsc(struct intel_crtc_state *crtc_state,
3406c349dbc7Sjsg struct dsc_compression_parameters_entry *dsc,
3407c349dbc7Sjsg int dsc_max_bpc)
3408c349dbc7Sjsg {
3409c349dbc7Sjsg struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
3410c349dbc7Sjsg int bpc = 8;
3411c349dbc7Sjsg
3412c349dbc7Sjsg vdsc_cfg->dsc_version_major = dsc->version_major;
3413c349dbc7Sjsg vdsc_cfg->dsc_version_minor = dsc->version_minor;
3414c349dbc7Sjsg
3415c349dbc7Sjsg if (dsc->support_12bpc && dsc_max_bpc >= 12)
3416c349dbc7Sjsg bpc = 12;
3417c349dbc7Sjsg else if (dsc->support_10bpc && dsc_max_bpc >= 10)
3418c349dbc7Sjsg bpc = 10;
3419c349dbc7Sjsg else if (dsc->support_8bpc && dsc_max_bpc >= 8)
3420c349dbc7Sjsg bpc = 8;
3421c349dbc7Sjsg else
3422c349dbc7Sjsg DRM_DEBUG_KMS("VBT: Unsupported BPC %d for DCS\n",
3423c349dbc7Sjsg dsc_max_bpc);
3424c349dbc7Sjsg
3425c349dbc7Sjsg crtc_state->pipe_bpp = bpc * 3;
3426c349dbc7Sjsg
3427c349dbc7Sjsg crtc_state->dsc.compressed_bpp = min(crtc_state->pipe_bpp,
3428c349dbc7Sjsg VBT_DSC_MAX_BPP(dsc->max_bpp));
3429c349dbc7Sjsg
3430c349dbc7Sjsg /*
3431c349dbc7Sjsg * FIXME: This is ugly, and slice count should take DSC engine
3432c349dbc7Sjsg * throughput etc. into account.
3433c349dbc7Sjsg *
3434c349dbc7Sjsg * Also, per spec DSI supports 1, 2, 3 or 4 horizontal slices.
3435c349dbc7Sjsg */
3436c349dbc7Sjsg if (dsc->slices_per_line & BIT(2)) {
3437c349dbc7Sjsg crtc_state->dsc.slice_count = 4;
3438c349dbc7Sjsg } else if (dsc->slices_per_line & BIT(1)) {
3439c349dbc7Sjsg crtc_state->dsc.slice_count = 2;
3440c349dbc7Sjsg } else {
3441c349dbc7Sjsg /* FIXME */
3442c349dbc7Sjsg if (!(dsc->slices_per_line & BIT(0)))
3443c349dbc7Sjsg DRM_DEBUG_KMS("VBT: Unsupported DSC slice count for DSI\n");
3444c349dbc7Sjsg
3445c349dbc7Sjsg crtc_state->dsc.slice_count = 1;
3446c349dbc7Sjsg }
3447c349dbc7Sjsg
3448c349dbc7Sjsg if (crtc_state->hw.adjusted_mode.crtc_hdisplay %
3449c349dbc7Sjsg crtc_state->dsc.slice_count != 0)
3450c349dbc7Sjsg DRM_DEBUG_KMS("VBT: DSC hdisplay %d not divisible by slice count %d\n",
3451c349dbc7Sjsg crtc_state->hw.adjusted_mode.crtc_hdisplay,
3452c349dbc7Sjsg crtc_state->dsc.slice_count);
3453c349dbc7Sjsg
3454c349dbc7Sjsg /*
3455c349dbc7Sjsg * The VBT rc_buffer_block_size and rc_buffer_size definitions
34565ca02815Sjsg * correspond to DP 1.4 DPCD offsets 0x62 and 0x63.
3457c349dbc7Sjsg */
34585ca02815Sjsg vdsc_cfg->rc_model_size = drm_dsc_dp_rc_buffer_size(dsc->rc_buffer_block_size,
34595ca02815Sjsg dsc->rc_buffer_size);
3460c349dbc7Sjsg
3461c349dbc7Sjsg /* FIXME: DSI spec says bpc + 1 for this one */
3462c349dbc7Sjsg vdsc_cfg->line_buf_depth = VBT_DSC_LINE_BUFFER_DEPTH(dsc->line_buffer_depth);
3463c349dbc7Sjsg
3464c349dbc7Sjsg vdsc_cfg->block_pred_enable = dsc->block_prediction_enable;
3465c349dbc7Sjsg
3466c349dbc7Sjsg vdsc_cfg->slice_height = dsc->slice_height;
3467c349dbc7Sjsg }
3468c349dbc7Sjsg
3469c349dbc7Sjsg /* FIXME: initially DSI specific */
intel_bios_get_dsc_params(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state,int dsc_max_bpc)3470c349dbc7Sjsg bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
3471c349dbc7Sjsg struct intel_crtc_state *crtc_state,
3472c349dbc7Sjsg int dsc_max_bpc)
3473c349dbc7Sjsg {
3474c349dbc7Sjsg struct drm_i915_private *i915 = to_i915(encoder->base.dev);
34755ca02815Sjsg const struct intel_bios_encoder_data *devdata;
3476c349dbc7Sjsg
34771bb76ff1Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3478f005ef32Sjsg const struct child_device_config *child = &devdata->child;
3479c349dbc7Sjsg
3480c349dbc7Sjsg if (!(child->device_type & DEVICE_TYPE_MIPI_OUTPUT))
3481c349dbc7Sjsg continue;
3482c349dbc7Sjsg
348350603113Sjsg if (dsi_dvo_port_to_port(i915, child->dvo_port) == encoder->port) {
3484c349dbc7Sjsg if (!devdata->dsc)
3485c349dbc7Sjsg return false;
3486c349dbc7Sjsg
3487c349dbc7Sjsg if (crtc_state)
3488c349dbc7Sjsg fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc);
3489c349dbc7Sjsg
3490c349dbc7Sjsg return true;
3491c349dbc7Sjsg }
3492c349dbc7Sjsg }
3493c349dbc7Sjsg
3494c349dbc7Sjsg return false;
3495c349dbc7Sjsg }
3496c349dbc7Sjsg
3497f005ef32Sjsg static const u8 adlp_aux_ch_map[] = {
3498f005ef32Sjsg [AUX_CH_A] = DP_AUX_A,
3499f005ef32Sjsg [AUX_CH_B] = DP_AUX_B,
3500f005ef32Sjsg [AUX_CH_C] = DP_AUX_C,
3501f005ef32Sjsg [AUX_CH_D_XELPD] = DP_AUX_D,
3502f005ef32Sjsg [AUX_CH_E_XELPD] = DP_AUX_E,
3503f005ef32Sjsg [AUX_CH_USBC1] = DP_AUX_F,
3504f005ef32Sjsg [AUX_CH_USBC2] = DP_AUX_G,
3505f005ef32Sjsg [AUX_CH_USBC3] = DP_AUX_H,
3506f005ef32Sjsg [AUX_CH_USBC4] = DP_AUX_I,
3507f005ef32Sjsg };
3508f005ef32Sjsg
3509f005ef32Sjsg /*
3510f005ef32Sjsg * ADL-S VBT uses PHY based mapping. Combo PHYs A,B,C,D,E
3511f005ef32Sjsg * map to DDI A,TC1,TC2,TC3,TC4 respectively.
3512c349dbc7Sjsg */
3513f005ef32Sjsg static const u8 adls_aux_ch_map[] = {
3514f005ef32Sjsg [AUX_CH_A] = DP_AUX_A,
3515f005ef32Sjsg [AUX_CH_USBC1] = DP_AUX_B,
3516f005ef32Sjsg [AUX_CH_USBC2] = DP_AUX_C,
3517f005ef32Sjsg [AUX_CH_USBC3] = DP_AUX_D,
3518f005ef32Sjsg [AUX_CH_USBC4] = DP_AUX_E,
3519f005ef32Sjsg };
3520c349dbc7Sjsg
35215ca02815Sjsg /*
35225ca02815Sjsg * RKL/DG1 VBT uses PHY based mapping. Combo PHYs A,B,C,D
35235ca02815Sjsg * map to DDI A,B,TC1,TC2 respectively.
35245ca02815Sjsg */
3525f005ef32Sjsg static const u8 rkl_aux_ch_map[] = {
3526f005ef32Sjsg [AUX_CH_A] = DP_AUX_A,
3527f005ef32Sjsg [AUX_CH_B] = DP_AUX_B,
3528f005ef32Sjsg [AUX_CH_USBC1] = DP_AUX_C,
3529f005ef32Sjsg [AUX_CH_USBC2] = DP_AUX_D,
3530f005ef32Sjsg };
3531c349dbc7Sjsg
3532f005ef32Sjsg static const u8 direct_aux_ch_map[] = {
3533f005ef32Sjsg [AUX_CH_A] = DP_AUX_A,
3534f005ef32Sjsg [AUX_CH_B] = DP_AUX_B,
3535f005ef32Sjsg [AUX_CH_C] = DP_AUX_C,
3536f005ef32Sjsg [AUX_CH_D] = DP_AUX_D, /* aka AUX_CH_USBC1 */
3537f005ef32Sjsg [AUX_CH_E] = DP_AUX_E, /* aka AUX_CH_USBC2 */
3538f005ef32Sjsg [AUX_CH_F] = DP_AUX_F, /* aka AUX_CH_USBC3 */
3539f005ef32Sjsg [AUX_CH_G] = DP_AUX_G, /* aka AUX_CH_USBC4 */
3540f005ef32Sjsg [AUX_CH_H] = DP_AUX_H, /* aka AUX_CH_USBC5 */
3541f005ef32Sjsg [AUX_CH_I] = DP_AUX_I, /* aka AUX_CH_USBC6 */
3542f005ef32Sjsg };
3543c349dbc7Sjsg
map_aux_ch(struct drm_i915_private * i915,u8 aux_channel)3544f005ef32Sjsg static enum aux_ch map_aux_ch(struct drm_i915_private *i915, u8 aux_channel)
3545c349dbc7Sjsg {
3546f005ef32Sjsg const u8 *aux_ch_map;
3547f005ef32Sjsg int i, n_entries;
3548c349dbc7Sjsg
3549f005ef32Sjsg if (DISPLAY_VER(i915) >= 13) {
3550f005ef32Sjsg aux_ch_map = adlp_aux_ch_map;
3551f005ef32Sjsg n_entries = ARRAY_SIZE(adlp_aux_ch_map);
3552f005ef32Sjsg } else if (IS_ALDERLAKE_S(i915)) {
3553f005ef32Sjsg aux_ch_map = adls_aux_ch_map;
3554f005ef32Sjsg n_entries = ARRAY_SIZE(adls_aux_ch_map);
3555f005ef32Sjsg } else if (IS_DG1(i915) || IS_ROCKETLAKE(i915)) {
3556f005ef32Sjsg aux_ch_map = rkl_aux_ch_map;
3557f005ef32Sjsg n_entries = ARRAY_SIZE(rkl_aux_ch_map);
3558f005ef32Sjsg } else {
3559f005ef32Sjsg aux_ch_map = direct_aux_ch_map;
3560f005ef32Sjsg n_entries = ARRAY_SIZE(direct_aux_ch_map);
3561c349dbc7Sjsg }
3562c349dbc7Sjsg
3563f005ef32Sjsg for (i = 0; i < n_entries; i++) {
3564f005ef32Sjsg if (aux_ch_map[i] == aux_channel)
3565f005ef32Sjsg return i;
3566f005ef32Sjsg }
3567f005ef32Sjsg
3568f005ef32Sjsg drm_dbg_kms(&i915->drm,
3569f005ef32Sjsg "Ignoring alternate AUX CH: VBT claims AUX 0x%x, which is not valid for this platform\n",
3570f005ef32Sjsg aux_channel);
3571f005ef32Sjsg
3572f005ef32Sjsg return AUX_CH_NONE;
3573f005ef32Sjsg }
3574f005ef32Sjsg
intel_bios_dp_aux_ch(const struct intel_bios_encoder_data * devdata)3575f005ef32Sjsg enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata)
3576c349dbc7Sjsg {
3577f005ef32Sjsg if (!devdata || !devdata->child.aux_channel)
3578f005ef32Sjsg return AUX_CH_NONE;
3579c349dbc7Sjsg
3580f005ef32Sjsg return map_aux_ch(devdata->i915, devdata->child.aux_channel);
3581c349dbc7Sjsg }
3582c349dbc7Sjsg
intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data * devdata)3583f005ef32Sjsg bool intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data *devdata)
3584f005ef32Sjsg {
3585f005ef32Sjsg struct drm_i915_private *i915;
3586f005ef32Sjsg u8 aux_channel;
3587f005ef32Sjsg int count = 0;
3588f005ef32Sjsg
3589f005ef32Sjsg if (!devdata || !devdata->child.aux_channel)
3590f005ef32Sjsg return false;
3591f005ef32Sjsg
3592f005ef32Sjsg i915 = devdata->i915;
3593f005ef32Sjsg aux_channel = devdata->child.aux_channel;
3594f005ef32Sjsg
3595f005ef32Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3596f005ef32Sjsg if (intel_bios_encoder_supports_dp(devdata) &&
3597f005ef32Sjsg aux_channel == devdata->child.aux_channel)
3598f005ef32Sjsg count++;
3599f005ef32Sjsg }
3600f005ef32Sjsg
3601f005ef32Sjsg return count > 1;
3602f005ef32Sjsg }
3603f005ef32Sjsg
intel_bios_dp_boost_level(const struct intel_bios_encoder_data * devdata)3604f005ef32Sjsg int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata)
3605c349dbc7Sjsg {
36061bb76ff1Sjsg if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
36075ca02815Sjsg return 0;
3608c349dbc7Sjsg
36095ca02815Sjsg return translate_iboost(devdata->child.dp_iboost_level);
3610c349dbc7Sjsg }
3611c349dbc7Sjsg
intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data * devdata)3612f005ef32Sjsg int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata)
3613c349dbc7Sjsg {
36141bb76ff1Sjsg if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
36155ca02815Sjsg return 0;
3616c349dbc7Sjsg
36175ca02815Sjsg return translate_iboost(devdata->child.hdmi_iboost_level);
3618c349dbc7Sjsg }
3619c349dbc7Sjsg
intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data * devdata)3620f005ef32Sjsg int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata)
3621c349dbc7Sjsg {
36221bb76ff1Sjsg if (!devdata || !devdata->child.ddc_pin)
36231bb76ff1Sjsg return 0;
36241bb76ff1Sjsg
3625f005ef32Sjsg return map_ddc_pin(devdata->i915, devdata->child.ddc_pin);
3626c349dbc7Sjsg }
3627c349dbc7Sjsg
intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data * devdata)36285ca02815Sjsg bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata)
3629c349dbc7Sjsg {
36301bb76ff1Sjsg return devdata->i915->display.vbt.version >= 195 && devdata->child.dp_usb_type_c;
3631c349dbc7Sjsg }
3632c349dbc7Sjsg
intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data * devdata)36335ca02815Sjsg bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devdata)
3634c349dbc7Sjsg {
36351bb76ff1Sjsg return devdata->i915->display.vbt.version >= 209 && devdata->child.tbt;
3636c349dbc7Sjsg }
3637c349dbc7Sjsg
intel_bios_encoder_lane_reversal(const struct intel_bios_encoder_data * devdata)3638f005ef32Sjsg bool intel_bios_encoder_lane_reversal(const struct intel_bios_encoder_data *devdata)
3639f005ef32Sjsg {
3640f005ef32Sjsg return devdata && devdata->child.lane_reversal;
3641f005ef32Sjsg }
3642f005ef32Sjsg
intel_bios_encoder_hpd_invert(const struct intel_bios_encoder_data * devdata)3643f005ef32Sjsg bool intel_bios_encoder_hpd_invert(const struct intel_bios_encoder_data *devdata)
3644f005ef32Sjsg {
3645f005ef32Sjsg return devdata && devdata->child.hpd_invert;
3646f005ef32Sjsg }
3647f005ef32Sjsg
36485ca02815Sjsg const struct intel_bios_encoder_data *
intel_bios_encoder_data_lookup(struct drm_i915_private * i915,enum port port)36495ca02815Sjsg intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port)
3650c349dbc7Sjsg {
3651f005ef32Sjsg struct intel_bios_encoder_data *devdata;
3652f005ef32Sjsg
3653f005ef32Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
3654f005ef32Sjsg if (intel_bios_encoder_port(devdata) == port)
3655f005ef32Sjsg return devdata;
3656f005ef32Sjsg }
3657f005ef32Sjsg
3658f005ef32Sjsg return NULL;
3659f005ef32Sjsg }
3660f005ef32Sjsg
intel_bios_for_each_encoder(struct drm_i915_private * i915,void (* func)(struct drm_i915_private * i915,const struct intel_bios_encoder_data * devdata))3661f005ef32Sjsg void intel_bios_for_each_encoder(struct drm_i915_private *i915,
3662f005ef32Sjsg void (*func)(struct drm_i915_private *i915,
3663f005ef32Sjsg const struct intel_bios_encoder_data *devdata))
3664f005ef32Sjsg {
3665f005ef32Sjsg struct intel_bios_encoder_data *devdata;
3666f005ef32Sjsg
3667f005ef32Sjsg list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
3668f005ef32Sjsg func(i915, devdata);
3669c349dbc7Sjsg }
3670