}
static const void *
-find_section(const void *_bdb, enum bdb_block_id section_id)
+find_raw_section(const void *_bdb, enum bdb_block_id section_id)
{
const struct bdb_header *bdb = _bdb;
const u8 *base = _bdb;
return NULL;
}
+/*
+ * Offset from the start of BDB to the start of the
+ * block data (just past the block header).
+ */
+static u32 block_offset(const void *bdb, enum bdb_block_id section_id)
+{
+ const void *block;
+
+ block = find_raw_section(bdb, section_id);
+ if (!block)
+ return 0;
+
+ return block - bdb;
+}
+
+struct bdb_block_entry {
+ struct list_head node;
+ enum bdb_block_id section_id;
+ u8 data[];
+};
+
+static const void *
+find_section(struct drm_i915_private *i915,
+ enum bdb_block_id section_id)
+{
+ struct bdb_block_entry *entry;
+
+ list_for_each_entry(entry, &i915->vbt.bdb_blocks, node) {
+ if (entry->section_id == section_id)
+ return entry->data + 3;
+ }
+
+ return NULL;
+}
+
+static const struct {
+ enum bdb_block_id section_id;
+ size_t min_size;
+} bdb_blocks[] = {
+ { .section_id = BDB_GENERAL_FEATURES,
+ .min_size = sizeof(struct bdb_general_features), },
+ { .section_id = BDB_GENERAL_DEFINITIONS,
+ .min_size = sizeof(struct bdb_general_definitions), },
+ { .section_id = BDB_PSR,
+ .min_size = sizeof(struct bdb_psr), },
+ { .section_id = BDB_DRIVER_FEATURES,
+ .min_size = sizeof(struct bdb_driver_features), },
+ { .section_id = BDB_SDVO_LVDS_OPTIONS,
+ .min_size = sizeof(struct bdb_sdvo_lvds_options), },
+ { .section_id = BDB_SDVO_PANEL_DTDS,
+ .min_size = sizeof(struct bdb_sdvo_panel_dtds), },
+ { .section_id = BDB_EDP,
+ .min_size = sizeof(struct bdb_edp), },
+ { .section_id = BDB_LVDS_OPTIONS,
+ .min_size = sizeof(struct bdb_lvds_options), },
+ { .section_id = BDB_LVDS_LFP_DATA_PTRS,
+ .min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), },
+ { .section_id = BDB_LVDS_LFP_DATA,
+ .min_size = sizeof(struct bdb_lvds_lfp_data), },
+ { .section_id = BDB_LVDS_BACKLIGHT,
+ .min_size = sizeof(struct bdb_lfp_backlight_data), },
+ { .section_id = BDB_LFP_POWER,
+ .min_size = sizeof(struct bdb_lfp_power), },
+ { .section_id = BDB_MIPI_CONFIG,
+ .min_size = sizeof(struct bdb_mipi_config), },
+ { .section_id = BDB_MIPI_SEQUENCE,
+ .min_size = sizeof(struct bdb_mipi_sequence) },
+ { .section_id = BDB_COMPRESSION_PARAMETERS,
+ .min_size = sizeof(struct bdb_compression_parameters), },
+ { .section_id = BDB_GENERIC_DTD,
+ .min_size = sizeof(struct bdb_generic_dtd), },
+};
+
+static void
+init_bdb_block(struct drm_i915_private *i915,
+ const void *bdb, enum bdb_block_id section_id,
+ size_t min_size)
+{
+ struct bdb_block_entry *entry;
+ const void *block;
+ size_t block_size;
+
+ block = find_raw_section(bdb, section_id);
+ if (!block)
+ return;
+
+ drm_WARN(&i915->drm, min_size == 0,
+ "Block %d min_size is zero\n", section_id);
+
+ block_size = get_blocksize(block);
+
+ entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
+ GFP_KERNEL);
+ if (!entry)
+ return;
+
+ entry->section_id = section_id;
+ memcpy(entry->data, block - 3, block_size + 3);
+
+ drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n",
+ section_id, block_size, min_size);
+
+ list_add_tail(&entry->node, &i915->vbt.bdb_blocks);
+}
+
+static void init_bdb_blocks(struct drm_i915_private *i915,
+ const void *bdb)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bdb_blocks); i++) {
+ enum bdb_block_id section_id = bdb_blocks[i].section_id;
+ size_t min_size = bdb_blocks[i].min_size;
+
+ init_bdb_block(i915, bdb, section_id, min_size);
+ }
+}
+
static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
const struct lvds_dvo_timing *dvo_timing)
const struct bdb_lvds_lfp_data_ptrs *ptrs,
int index)
{
- size_t data_ofs = (const u8 *)data - (const u8 *)bdb;
+ size_t data_ofs = block_offset(bdb, BDB_LVDS_LFP_DATA);
u16 data_size = ((const u16 *)data)[-1]; /* stored in header */
size_t ofs;
/* Parse general panel options */
static void
-parse_panel_options(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_panel_options(struct drm_i915_private *i915)
{
const struct bdb_lvds_options *lvds_options;
int panel_type;
int drrs_mode;
int ret;
- lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+ lvds_options = find_section(i915, BDB_LVDS_OPTIONS);
if (!lvds_options)
return;
struct drm_display_mode *panel_fixed_mode;
int panel_type = i915->vbt.panel_type;
- lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
+ lvds_lfp_data = find_section(i915, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
return;
- lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
+ lvds_lfp_data_ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
if (!lvds_lfp_data_ptrs)
return;
}
static void
-parse_generic_dtd(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_generic_dtd(struct drm_i915_private *i915)
{
const struct bdb_generic_dtd *generic_dtd;
const struct generic_dtd_entry *dtd;
struct drm_display_mode *panel_fixed_mode;
int num_dtd;
- generic_dtd = find_section(bdb, BDB_GENERIC_DTD);
+ generic_dtd = find_section(i915, BDB_GENERIC_DTD);
if (!generic_dtd)
return;
* back to trying the old LFP block if that fails.
*/
if (i915->vbt.version >= 229)
- parse_generic_dtd(i915, bdb);
+ parse_generic_dtd(i915);
if (!i915->vbt.lfp_lvds_vbt_mode)
parse_lfp_panel_dtd(i915, bdb);
}
static void
-parse_lfp_backlight(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_lfp_backlight(struct drm_i915_private *i915)
{
const struct bdb_lfp_backlight_data *backlight_data;
const struct lfp_backlight_data_entry *entry;
int panel_type = i915->vbt.panel_type;
u16 level;
- backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
+ backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT);
if (!backlight_data)
return;
/* Try to find sdvo panel data */
static void
-parse_sdvo_panel_data(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_sdvo_panel_data(struct drm_i915_private *i915)
{
const struct bdb_sdvo_panel_dtds *dtds;
struct drm_display_mode *panel_fixed_mode;
if (index == -1) {
const struct bdb_sdvo_lvds_options *sdvo_lvds_options;
- sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
+ sdvo_lvds_options = find_section(i915, BDB_SDVO_LVDS_OPTIONS);
if (!sdvo_lvds_options)
return;
index = sdvo_lvds_options->panel_type;
}
- dtds = find_section(bdb, BDB_SDVO_PANEL_DTDS);
+ dtds = find_section(i915, BDB_SDVO_PANEL_DTDS);
if (!dtds)
return;
}
static void
-parse_general_features(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_general_features(struct drm_i915_private *i915)
{
const struct bdb_general_features *general;
- general = find_section(bdb, BDB_GENERAL_FEATURES);
+ general = find_section(i915, BDB_GENERAL_FEATURES);
if (!general)
return;
}
static void
-parse_driver_features(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_driver_features(struct drm_i915_private *i915)
{
const struct bdb_driver_features *driver;
- driver = find_section(bdb, BDB_DRIVER_FEATURES);
+ driver = find_section(i915, BDB_DRIVER_FEATURES);
if (!driver)
return;
}
static void
-parse_power_conservation_features(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_power_conservation_features(struct drm_i915_private *i915)
{
const struct bdb_lfp_power *power;
u8 panel_type = i915->vbt.panel_type;
if (i915->vbt.version < 228)
return;
- power = find_section(bdb, BDB_LFP_POWER);
+ power = find_section(i915, BDB_LFP_POWER);
if (!power)
return;
}
static void
-parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb)
+parse_edp(struct drm_i915_private *i915)
{
const struct bdb_edp *edp;
const struct edp_power_seq *edp_pps;
const struct edp_fast_link_params *edp_link_params;
int panel_type = i915->vbt.panel_type;
- edp = find_section(bdb, BDB_EDP);
+ edp = find_section(i915, BDB_EDP);
if (!edp)
return;
}
static void
-parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb)
+parse_psr(struct drm_i915_private *i915)
{
const struct bdb_psr *psr;
const struct psr_table *psr_table;
int panel_type = i915->vbt.panel_type;
- psr = find_section(bdb, BDB_PSR);
+ psr = find_section(i915, BDB_PSR);
if (!psr) {
drm_dbg_kms(&i915->drm, "No PSR BDB found.\n");
return;
}
static void
-parse_mipi_config(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_mipi_config(struct drm_i915_private *i915)
{
const struct bdb_mipi_config *start;
const struct mipi_config *config;
/* Parse #52 for panel index used from panel_type already
* parsed
*/
- start = find_section(bdb, BDB_MIPI_CONFIG);
+ start = find_section(i915, BDB_MIPI_CONFIG);
if (!start) {
drm_dbg_kms(&i915->drm, "No MIPI config BDB found");
return;
}
static void
-parse_mipi_sequence(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_mipi_sequence(struct drm_i915_private *i915)
{
int panel_type = i915->vbt.panel_type;
const struct bdb_mipi_sequence *sequence;
if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
return;
- sequence = find_section(bdb, BDB_MIPI_SEQUENCE);
+ sequence = find_section(i915, BDB_MIPI_SEQUENCE);
if (!sequence) {
drm_dbg_kms(&i915->drm,
"No MIPI Sequence found, parsing complete\n");
}
static void
-parse_compression_parameters(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_compression_parameters(struct drm_i915_private *i915)
{
const struct bdb_compression_parameters *params;
struct intel_bios_encoder_data *devdata;
if (i915->vbt.version < 198)
return;
- params = find_section(bdb, BDB_COMPRESSION_PARAMETERS);
+ params = find_section(i915, BDB_COMPRESSION_PARAMETERS);
if (params) {
/* Sanity checks */
if (params->entry_size != sizeof(params->data[0])) {
}
static void
-parse_general_definitions(struct drm_i915_private *i915,
- const struct bdb_header *bdb)
+parse_general_definitions(struct drm_i915_private *i915)
{
const struct bdb_general_definitions *defs;
struct intel_bios_encoder_data *devdata;
u16 block_size;
int bus_pin;
- defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+ defs = find_section(i915, BDB_GENERAL_DEFINITIONS);
if (!defs) {
drm_dbg_kms(&i915->drm,
"No general definition block is found, no devices defined.\n");
const struct bdb_header *bdb;
INIT_LIST_HEAD(&i915->vbt.display_devices);
+ INIT_LIST_HEAD(&i915->vbt.bdb_blocks);
if (!HAS_DISPLAY(i915)) {
drm_dbg_kms(&i915->drm,
"VBT signature \"%.*s\", BDB version %d\n",
(int)sizeof(vbt->signature), vbt->signature, i915->vbt.version);
+ init_bdb_blocks(i915, bdb);
+
/* Grab useful general definitions */
- parse_general_features(i915, bdb);
- parse_general_definitions(i915, bdb);
- parse_panel_options(i915, bdb);
+ parse_general_features(i915);
+ parse_general_definitions(i915);
+ parse_panel_options(i915);
parse_panel_dtd(i915, bdb);
- parse_lfp_backlight(i915, bdb);
- parse_sdvo_panel_data(i915, bdb);
- parse_driver_features(i915, bdb);
- parse_power_conservation_features(i915, bdb);
- parse_edp(i915, bdb);
- parse_psr(i915, bdb);
- parse_mipi_config(i915, bdb);
- parse_mipi_sequence(i915, bdb);
+ parse_lfp_backlight(i915);
+ parse_sdvo_panel_data(i915);
+ parse_driver_features(i915);
+ parse_power_conservation_features(i915);
+ parse_edp(i915);
+ parse_psr(i915);
+ parse_mipi_config(i915);
+ parse_mipi_sequence(i915);
/* Depends on child device list */
- parse_compression_parameters(i915, bdb);
+ parse_compression_parameters(i915);
out:
if (!vbt) {
*/
void intel_bios_driver_remove(struct drm_i915_private *i915)
{
- struct intel_bios_encoder_data *devdata, *n;
+ struct intel_bios_encoder_data *devdata, *nd;
+ struct bdb_block_entry *entry, *ne;
- list_for_each_entry_safe(devdata, n, &i915->vbt.display_devices, node) {
+ list_for_each_entry_safe(devdata, nd, &i915->vbt.display_devices, node) {
list_del(&devdata->node);
kfree(devdata->dsc);
kfree(devdata);
}
+ list_for_each_entry_safe(entry, ne, &i915->vbt.bdb_blocks, node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+
kfree(i915->vbt.sdvo_lvds_vbt_mode);
i915->vbt.sdvo_lvds_vbt_mode = NULL;
kfree(i915->vbt.lfp_lvds_vbt_mode);