diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_bios.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_bios.c | 652 |
1 files changed, 416 insertions, 236 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 96cd1f0b9d32..ab23324c0402 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -124,7 +124,7 @@ find_raw_section(const void *_bdb, enum bdb_block_id section_id) * 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) +static u32 raw_block_offset(const void *bdb, enum bdb_block_id section_id) { const void *block; @@ -136,7 +136,7 @@ static u32 block_offset(const void *bdb, enum bdb_block_id section_id) } /* size of the block excluding the header */ -static u32 block_size(const void *bdb, enum bdb_block_id section_id) +static u32 raw_block_size(const void *bdb, enum bdb_block_id section_id) { const void *block; @@ -233,7 +233,7 @@ static bool validate_lfp_data_ptrs(const void *bdb, int data_block_size, lfp_data_size; int i; - data_block_size = block_size(bdb, BDB_LVDS_LFP_DATA); + data_block_size = raw_block_size(bdb, BDB_LVDS_LFP_DATA); if (data_block_size == 0) return false; @@ -310,7 +310,7 @@ static bool fixup_lfp_data_ptrs(const void *bdb, void *ptrs_block) u32 offset; int i; - offset = block_offset(bdb, BDB_LVDS_LFP_DATA); + offset = raw_block_offset(bdb, BDB_LVDS_LFP_DATA); for (i = 0; i < 16; i++) { if (ptrs->ptr[i].fp_timing.offset < offset || @@ -586,6 +586,14 @@ get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data, return (const void *)data + ptrs->ptr[index].fp_timing.offset; } +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) +{ + return (const void *)data + ptrs->ptr[index].panel_pnp_id.offset; +} + 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) @@ -596,12 +604,16 @@ get_lfp_data_tail(const struct bdb_lvds_lfp_data *data, return NULL; } -static int opregion_get_panel_type(struct drm_i915_private *i915) +static int opregion_get_panel_type(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) { return intel_opregion_get_panel_type(i915); } -static int vbt_get_panel_type(struct drm_i915_private *i915) +static int vbt_get_panel_type(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) { const struct bdb_lvds_options *lvds_options; @@ -609,16 +621,71 @@ static int vbt_get_panel_type(struct drm_i915_private *i915) if (!lvds_options) return -1; - if (lvds_options->panel_type > 0xf) { + if (lvds_options->panel_type > 0xf && + lvds_options->panel_type != 0xff) { drm_dbg_kms(&i915->drm, "Invalid VBT panel type 0x%x\n", lvds_options->panel_type); return -1; } + if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) + return lvds_options->panel_type2; + + drm_WARN_ON(&i915->drm, devdata && devdata->child.handle != DEVICE_HANDLE_LFP1); + return lvds_options->panel_type; } -static int fallback_get_panel_type(struct drm_i915_private *i915) +static int pnpid_get_panel_type(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) +{ + const struct bdb_lvds_lfp_data *data; + const struct bdb_lvds_lfp_data_ptrs *ptrs; + const struct lvds_pnp_id *edid_id; + struct lvds_pnp_id edid_id_nodate; + int i, best = -1; + + if (!edid) + return -1; + + edid_id = (const void *)&edid->mfg_id[0]; + + edid_id_nodate = *edid_id; + edid_id_nodate.mfg_week = 0; + edid_id_nodate.mfg_year = 0; + + ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS); + if (!ptrs) + return -1; + + data = find_section(i915, BDB_LVDS_LFP_DATA); + if (!data) + return -1; + + for (i = 0; i < 16; i++) { + const struct lvds_pnp_id *vbt_id = + get_lvds_pnp_id(data, ptrs, i); + + /* full match? */ + if (!memcmp(vbt_id, edid_id, sizeof(*vbt_id))) + return i; + + /* + * Accept a match w/o date if no full match is found, + * and the VBT entry does not specify a date. + */ + if (best < 0 && + !memcmp(vbt_id, &edid_id_nodate, sizeof(*vbt_id))) + best = i; + } + + return best; +} + +static int fallback_get_panel_type(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) { return 0; } @@ -626,14 +693,19 @@ static int fallback_get_panel_type(struct drm_i915_private *i915) enum panel_type { PANEL_TYPE_OPREGION, PANEL_TYPE_VBT, + PANEL_TYPE_PNPID, PANEL_TYPE_FALLBACK, }; -static int get_panel_type(struct drm_i915_private *i915) +static int get_panel_type(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) { struct { const char *name; - int (*get_panel_type)(struct drm_i915_private *i915); + int (*get_panel_type)(struct drm_i915_private *i915, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid); int panel_type; } panel_types[] = { [PANEL_TYPE_OPREGION] = { @@ -644,6 +716,10 @@ static int get_panel_type(struct drm_i915_private *i915) .name = "VBT", .get_panel_type = vbt_get_panel_type, }, + [PANEL_TYPE_PNPID] = { + .name = "PNPID", + .get_panel_type = pnpid_get_panel_type, + }, [PANEL_TYPE_FALLBACK] = { .name = "fallback", .get_panel_type = fallback_get_panel_type, @@ -652,9 +728,10 @@ static int get_panel_type(struct drm_i915_private *i915) int i; for (i = 0; i < ARRAY_SIZE(panel_types); i++) { - panel_types[i].panel_type = panel_types[i].get_panel_type(i915); + panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata, edid); - drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf); + drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf && + panel_types[i].panel_type != 0xff); if (panel_types[i].panel_type >= 0) drm_dbg_kms(&i915->drm, "Panel type (%s): %d\n", @@ -663,7 +740,11 @@ static int get_panel_type(struct drm_i915_private *i915) if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0) i = PANEL_TYPE_OPREGION; - else if (panel_types[PANEL_TYPE_VBT].panel_type >= 0) + else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff && + panel_types[PANEL_TYPE_PNPID].panel_type >= 0) + i = PANEL_TYPE_PNPID; + else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff && + panel_types[PANEL_TYPE_VBT].panel_type >= 0) i = PANEL_TYPE_VBT; else i = PANEL_TYPE_FALLBACK; @@ -674,26 +755,41 @@ static int get_panel_type(struct drm_i915_private *i915) return panel_types[i].panel_type; } +static unsigned int panel_bits(unsigned int value, int panel_type, int num_bits) +{ + return (value >> (panel_type * num_bits)) & (BIT(num_bits) - 1); +} + +static bool panel_bool(unsigned int value, int panel_type) +{ + return panel_bits(value, panel_type, 1); +} + /* Parse general panel options */ static void -parse_panel_options(struct drm_i915_private *i915) +parse_panel_options(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_lvds_options *lvds_options; - int panel_type; + int panel_type = panel->vbt.panel_type; int drrs_mode; lvds_options = find_section(i915, BDB_LVDS_OPTIONS); if (!lvds_options) return; - i915->vbt.lvds_dither = lvds_options->pixel_dither; - - panel_type = get_panel_type(i915); + panel->vbt.lvds_dither = lvds_options->pixel_dither; - i915->vbt.panel_type = panel_type; + /* + * Empirical evidence indicates the block size can be + * either 4,14,16,24+ bytes. For older VBTs no clear + * relationship between the block size vs. BDB version. + */ + if (get_blocksize(lvds_options) < 16) + return; - drrs_mode = (lvds_options->dps_panel_type_bits - >> (panel_type * 2)) & MODE_MASK; + drrs_mode = panel_bits(lvds_options->dps_panel_type_bits, + panel_type, 2); /* * VBT has static DRRS = 0 and seamless DRRS = 2. * The below piece of code is required to adjust vbt.drrs_type @@ -701,16 +797,16 @@ parse_panel_options(struct drm_i915_private *i915) */ switch (drrs_mode) { case 0: - i915->vbt.drrs_type = DRRS_TYPE_STATIC; + panel->vbt.drrs_type = DRRS_TYPE_STATIC; drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n"); break; case 2: - i915->vbt.drrs_type = DRRS_TYPE_SEAMLESS; + panel->vbt.drrs_type = DRRS_TYPE_SEAMLESS; drm_dbg_kms(&i915->drm, "DRRS supported mode is seamless\n"); break; default: - i915->vbt.drrs_type = DRRS_TYPE_NONE; + panel->vbt.drrs_type = DRRS_TYPE_NONE; drm_dbg_kms(&i915->drm, "DRRS not supported (VBT input)\n"); break; @@ -719,13 +815,14 @@ parse_panel_options(struct drm_i915_private *i915) 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) { const struct lvds_dvo_timing *panel_dvo_timing; const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, lvds_lfp_data_ptrs, @@ -737,7 +834,7 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); - i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; + panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; drm_dbg_kms(&i915->drm, "Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n", @@ -750,20 +847,21 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, /* check the resolution, just to be sure */ if (fp_timing->x_res == panel_fixed_mode->hdisplay && fp_timing->y_res == panel_fixed_mode->vdisplay) { - i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val; + panel->vbt.bios_lvds_val = fp_timing->lvds_reg_val; drm_dbg_kms(&i915->drm, "VBT initial LVDS value %x\n", - i915->vbt.bios_lvds_val); + panel->vbt.bios_lvds_val); } } static void -parse_lfp_data(struct drm_i915_private *i915) +parse_lfp_data(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_lvds_lfp_data *data; const struct bdb_lvds_lfp_data_tail *tail; const struct bdb_lvds_lfp_data_ptrs *ptrs; - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS); if (!ptrs) @@ -773,24 +871,25 @@ parse_lfp_data(struct drm_i915_private *i915) if (!data) return; - if (!i915->vbt.lfp_lvds_vbt_mode) - parse_lfp_panel_dtd(i915, data, ptrs); + if (!panel->vbt.lfp_lvds_vbt_mode) + parse_lfp_panel_dtd(i915, panel, data, ptrs); tail = get_lfp_data_tail(data, ptrs); if (!tail) return; if (i915->vbt.version >= 188) { - i915->vbt.seamless_drrs_min_refresh_rate = + panel->vbt.seamless_drrs_min_refresh_rate = tail->seamless_drrs_min_refresh_rate[panel_type]; drm_dbg_kms(&i915->drm, "Seamless DRRS min refresh rate: %d Hz\n", - i915->vbt.seamless_drrs_min_refresh_rate); + panel->vbt.seamless_drrs_min_refresh_rate); } } static void -parse_generic_dtd(struct drm_i915_private *i915) +parse_generic_dtd(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_generic_dtd *generic_dtd; const struct generic_dtd_entry *dtd; @@ -825,14 +924,14 @@ parse_generic_dtd(struct drm_i915_private *i915) num_dtd = (get_blocksize(generic_dtd) - sizeof(struct bdb_generic_dtd)) / generic_dtd->gdtd_size; - if (i915->vbt.panel_type >= num_dtd) { + if (panel->vbt.panel_type >= num_dtd) { drm_err(&i915->drm, "Panel type %d not found in table of %d DTD's\n", - i915->vbt.panel_type, num_dtd); + panel->vbt.panel_type, num_dtd); return; } - dtd = &generic_dtd->dtd[i915->vbt.panel_type]; + dtd = &generic_dtd->dtd[panel->vbt.panel_type]; panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) @@ -875,15 +974,16 @@ parse_generic_dtd(struct drm_i915_private *i915) "Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n", DRM_MODE_ARG(panel_fixed_mode)); - i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; + panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; } static void -parse_lfp_backlight(struct drm_i915_private *i915) +parse_lfp_backlight(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_lfp_backlight_data *backlight_data; const struct lfp_backlight_data_entry *entry; - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; u16 level; backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT); @@ -899,15 +999,15 @@ parse_lfp_backlight(struct drm_i915_private *i915) entry = &backlight_data->data[panel_type]; - i915->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; - if (!i915->vbt.backlight.present) { + panel->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; + if (!panel->vbt.backlight.present) { drm_dbg_kms(&i915->drm, "PWM backlight not present in VBT (type %u)\n", entry->type); return; } - i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; + panel->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; if (i915->vbt.version >= 191) { size_t exp_size; @@ -922,13 +1022,13 @@ parse_lfp_backlight(struct drm_i915_private *i915) const struct lfp_backlight_control_method *method; method = &backlight_data->backlight_control[panel_type]; - i915->vbt.backlight.type = method->type; - i915->vbt.backlight.controller = method->controller; + panel->vbt.backlight.type = method->type; + panel->vbt.backlight.controller = method->controller; } } - i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; - i915->vbt.backlight.active_low_pwm = entry->active_low_pwm; + panel->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; + panel->vbt.backlight.active_low_pwm = entry->active_low_pwm; if (i915->vbt.version >= 234) { u16 min_level; @@ -949,28 +1049,29 @@ parse_lfp_backlight(struct drm_i915_private *i915) drm_warn(&i915->drm, "Brightness min level > 255\n"); level = 255; } - i915->vbt.backlight.min_brightness = min_level; + panel->vbt.backlight.min_brightness = min_level; - i915->vbt.backlight.brightness_precision_bits = + panel->vbt.backlight.brightness_precision_bits = backlight_data->brightness_precision_bits[panel_type]; } else { level = backlight_data->level[panel_type]; - i915->vbt.backlight.min_brightness = entry->min_brightness; + panel->vbt.backlight.min_brightness = entry->min_brightness; } drm_dbg_kms(&i915->drm, "VBT backlight PWM modulation frequency %u Hz, " "active %s, min brightness %u, level %u, controller %u\n", - i915->vbt.backlight.pwm_freq_hz, - i915->vbt.backlight.active_low_pwm ? "low" : "high", - i915->vbt.backlight.min_brightness, + panel->vbt.backlight.pwm_freq_hz, + panel->vbt.backlight.active_low_pwm ? "low" : "high", + panel->vbt.backlight.min_brightness, level, - i915->vbt.backlight.controller); + panel->vbt.backlight.controller); } /* Try to find sdvo panel data */ static void -parse_sdvo_panel_data(struct drm_i915_private *i915) +parse_sdvo_panel_data(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_sdvo_panel_dtds *dtds; struct drm_display_mode *panel_fixed_mode; @@ -1003,7 +1104,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915) fill_detail_timing_data(panel_fixed_mode, &dtds->dtds[index]); - i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; + panel->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; drm_dbg_kms(&i915->drm, "Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n", @@ -1182,6 +1283,17 @@ parse_driver_features(struct drm_i915_private *i915) driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS) i915->vbt.int_lvds_support = 0; } +} + +static void +parse_panel_driver_features(struct drm_i915_private *i915, + struct intel_panel *panel) +{ + const struct bdb_driver_features *driver; + + driver = find_section(i915, BDB_DRIVER_FEATURES); + if (!driver) + return; if (i915->vbt.version < 228) { drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n", @@ -1192,18 +1304,29 @@ parse_driver_features(struct drm_i915_private *i915) * static DRRS is 0 and DRRS not supported is represented by * driver->drrs_enabled=false */ - if (!driver->drrs_enabled) - i915->vbt.drrs_type = DRRS_TYPE_NONE; + if (!driver->drrs_enabled && panel->vbt.drrs_type != DRRS_TYPE_NONE) { + /* + * FIXME Should DMRRS perhaps be treated as seamless + * but without the automatic downclocking? + */ + if (driver->dmrrs_enabled) + panel->vbt.drrs_type = DRRS_TYPE_STATIC; + else + panel->vbt.drrs_type = DRRS_TYPE_NONE; + } - i915->vbt.psr.enable = driver->psr_enabled; + panel->vbt.psr.enable = driver->psr_enabled; } } static void -parse_power_conservation_features(struct drm_i915_private *i915) +parse_power_conservation_features(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_lfp_power *power; - u8 panel_type = i915->vbt.panel_type; + u8 panel_type = panel->vbt.panel_type; + + panel->vbt.vrr = true; /* matches Windows behaviour */ if (i915->vbt.version < 228) return; @@ -1212,7 +1335,7 @@ parse_power_conservation_features(struct drm_i915_private *i915) if (!power) return; - i915->vbt.psr.enable = power->psr & BIT(panel_type); + panel->vbt.psr.enable = panel_bool(power->psr, panel_type); /* * If DRRS is not supported, drrs_type has to be set to 0. @@ -1220,34 +1343,47 @@ parse_power_conservation_features(struct drm_i915_private *i915) * static DRRS is 0 and DRRS not supported is represented by * power->drrs & BIT(panel_type)=false */ - if (!(power->drrs & BIT(panel_type))) - i915->vbt.drrs_type = DRRS_TYPE_NONE; + if (!panel_bool(power->drrs, panel_type) && panel->vbt.drrs_type != DRRS_TYPE_NONE) { + /* + * FIXME Should DMRRS perhaps be treated as seamless + * but without the automatic downclocking? + */ + if (panel_bool(power->dmrrs, panel_type)) + panel->vbt.drrs_type = DRRS_TYPE_STATIC; + else + panel->vbt.drrs_type = DRRS_TYPE_NONE; + } if (i915->vbt.version >= 232) - i915->vbt.edp.hobl = power->hobl & BIT(panel_type); + panel->vbt.edp.hobl = panel_bool(power->hobl, panel_type); + + if (i915->vbt.version >= 233) + panel->vbt.vrr = panel_bool(power->vrr_feature_enabled, + panel_type); } static void -parse_edp(struct drm_i915_private *i915) +parse_edp(struct drm_i915_private *i915, + struct intel_panel *panel) { 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; + int panel_type = panel->vbt.panel_type; edp = find_section(i915, BDB_EDP); if (!edp) return; - switch ((edp->color_depth >> (panel_type * 2)) & 3) { + switch (panel_bits(edp->color_depth, panel_type, 2)) { case EDP_18BPP: - i915->vbt.edp.bpp = 18; + panel->vbt.edp.bpp = 18; break; case EDP_24BPP: - i915->vbt.edp.bpp = 24; + panel->vbt.edp.bpp = 24; break; case EDP_30BPP: - i915->vbt.edp.bpp = 30; + panel->vbt.edp.bpp = 30; break; } @@ -1255,31 +1391,39 @@ parse_edp(struct drm_i915_private *i915) edp_pps = &edp->power_seqs[panel_type]; edp_link_params = &edp->fast_link_params[panel_type]; - i915->vbt.edp.pps = *edp_pps; + panel->vbt.edp.pps = *edp_pps; - switch (edp_link_params->rate) { - case EDP_RATE_1_62: - i915->vbt.edp.rate = DP_LINK_BW_1_62; - break; - case EDP_RATE_2_7: - i915->vbt.edp.rate = DP_LINK_BW_2_7; - break; - default: - drm_dbg_kms(&i915->drm, - "VBT has unknown eDP link rate value %u\n", - edp_link_params->rate); - break; + if (i915->vbt.version >= 224) { + panel->vbt.edp.rate = + edp->edp_fast_link_training_rate[panel_type] * 20; + } else { + switch (edp_link_params->rate) { + case EDP_RATE_1_62: + panel->vbt.edp.rate = 162000; + break; + case EDP_RATE_2_7: + panel->vbt.edp.rate = 270000; + break; + case EDP_RATE_5_4: + panel->vbt.edp.rate = 540000; + break; + default: + drm_dbg_kms(&i915->drm, + "VBT has unknown eDP link rate value %u\n", + edp_link_params->rate); + break; + } } switch (edp_link_params->lanes) { case EDP_LANE_1: - i915->vbt.edp.lanes = 1; + panel->vbt.edp.lanes = 1; break; case EDP_LANE_2: - i915->vbt.edp.lanes = 2; + panel->vbt.edp.lanes = 2; break; case EDP_LANE_4: - i915->vbt.edp.lanes = 4; + panel->vbt.edp.lanes = 4; break; default: drm_dbg_kms(&i915->drm, @@ -1290,16 +1434,16 @@ parse_edp(struct drm_i915_private *i915) switch (edp_link_params->preemphasis) { case EDP_PREEMPHASIS_NONE: - i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; + panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; break; case EDP_PREEMPHASIS_3_5dB: - i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; + panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; break; case EDP_PREEMPHASIS_6dB: - i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; + panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; break; case EDP_PREEMPHASIS_9_5dB: - i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; + panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; break; default: drm_dbg_kms(&i915->drm, @@ -1310,16 +1454,16 @@ parse_edp(struct drm_i915_private *i915) switch (edp_link_params->vswing) { case EDP_VSWING_0_4V: - i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; + panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; break; case EDP_VSWING_0_6V: - i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; + panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; break; case EDP_VSWING_0_8V: - i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; + panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; break; case EDP_VSWING_1_2V: - i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; + panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; break; default: drm_dbg_kms(&i915->drm, @@ -1333,24 +1477,29 @@ parse_edp(struct drm_i915_private *i915) /* Don't read from VBT if module parameter has valid value*/ if (i915->params.edp_vswing) { - i915->vbt.edp.low_vswing = + panel->vbt.edp.low_vswing = i915->params.edp_vswing == 1; } else { vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; - i915->vbt.edp.low_vswing = vswing == 0; + panel->vbt.edp.low_vswing = vswing == 0; } } - i915->vbt.edp.drrs_msa_timing_delay = - (edp->sdrrs_msa_timing_delay >> (panel_type * 2)) & 3; + panel->vbt.edp.drrs_msa_timing_delay = + panel_bits(edp->sdrrs_msa_timing_delay, panel_type, 2); + + if (i915->vbt.version >= 244) + panel->vbt.edp.max_link_rate = + edp->edp_max_port_link_rate[panel_type] * 20; } static void -parse_psr(struct drm_i915_private *i915) +parse_psr(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_psr *psr; const struct psr_table *psr_table; - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; psr = find_section(i915, BDB_PSR); if (!psr) { @@ -1360,11 +1509,11 @@ parse_psr(struct drm_i915_private *i915) psr_table = &psr->psr_table[panel_type]; - i915->vbt.psr.full_link = psr_table->full_link; - i915->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; + panel->vbt.psr.full_link = psr_table->full_link; + panel->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; /* Allowed VBT values goes from 0 to 15 */ - i915->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : + panel->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames; /* @@ -1375,13 +1524,13 @@ parse_psr(struct drm_i915_private *i915) (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) { switch (psr_table->tp1_wakeup_time) { case 0: - i915->vbt.psr.tp1_wakeup_time_us = 500; + panel->vbt.psr.tp1_wakeup_time_us = 500; break; case 1: - i915->vbt.psr.tp1_wakeup_time_us = 100; + panel->vbt.psr.tp1_wakeup_time_us = 100; break; case 3: - i915->vbt.psr.tp1_wakeup_time_us = 0; + panel->vbt.psr.tp1_wakeup_time_us = 0; break; default: drm_dbg_kms(&i915->drm, @@ -1389,19 +1538,19 @@ parse_psr(struct drm_i915_private *i915) psr_table->tp1_wakeup_time); fallthrough; case 2: - i915->vbt.psr.tp1_wakeup_time_us = 2500; + panel->vbt.psr.tp1_wakeup_time_us = 2500; break; } switch (psr_table->tp2_tp3_wakeup_time) { case 0: - i915->vbt.psr.tp2_tp3_wakeup_time_us = 500; + panel->vbt.psr.tp2_tp3_wakeup_time_us = 500; break; case 1: - i915->vbt.psr.tp2_tp3_wakeup_time_us = 100; + panel->vbt.psr.tp2_tp3_wakeup_time_us = 100; break; case 3: - i915->vbt.psr.tp2_tp3_wakeup_time_us = 0; + panel->vbt.psr.tp2_tp3_wakeup_time_us = 0; break; default: drm_dbg_kms(&i915->drm, @@ -1409,18 +1558,18 @@ parse_psr(struct drm_i915_private *i915) psr_table->tp2_tp3_wakeup_time); fallthrough; case 2: - i915->vbt.psr.tp2_tp3_wakeup_time_us = 2500; + panel->vbt.psr.tp2_tp3_wakeup_time_us = 2500; break; } } else { - i915->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100; - i915->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; + panel->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100; + panel->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; } if (i915->vbt.version >= 226) { u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time; - wakeup_time = (wakeup_time >> (2 * panel_type)) & 0x3; + wakeup_time = panel_bits(wakeup_time, panel_type, 2); switch (wakeup_time) { case 0: wakeup_time = 500; @@ -1436,62 +1585,64 @@ parse_psr(struct drm_i915_private *i915) wakeup_time = 2500; break; } - i915->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time; + panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time; } else { /* Reusing PSR1 wakeup time for PSR2 in older VBTs */ - i915->vbt.psr.psr2_tp2_tp3_wakeup_time_us = i915->vbt.psr.tp2_tp3_wakeup_time_us; + panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = panel->vbt.psr.tp2_tp3_wakeup_time_us; } } static void parse_dsi_backlight_ports(struct drm_i915_private *i915, - u16 version, enum port port) + struct intel_panel *panel, + enum port port) { - if (!i915->vbt.dsi.config->dual_link || version < 197) { - i915->vbt.dsi.bl_ports = BIT(port); - if (i915->vbt.dsi.config->cabc_supported) - i915->vbt.dsi.cabc_ports = BIT(port); + if (!panel->vbt.dsi.config->dual_link || i915->vbt.version < 197) { + panel->vbt.dsi.bl_ports = BIT(port); + if (panel->vbt.dsi.config->cabc_supported) + panel->vbt.dsi.cabc_ports = BIT(port); return; } - switch (i915->vbt.dsi.config->dl_dcs_backlight_ports) { + switch (panel->vbt.dsi.config->dl_dcs_backlight_ports) { case DL_DCS_PORT_A: - i915->vbt.dsi.bl_ports = BIT(PORT_A); + panel->vbt.dsi.bl_ports = BIT(PORT_A); break; case DL_DCS_PORT_C: - i915->vbt.dsi.bl_ports = BIT(PORT_C); + panel->vbt.dsi.bl_ports = BIT(PORT_C); break; default: case DL_DCS_PORT_A_AND_C: - i915->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C); + panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C); break; } - if (!i915->vbt.dsi.config->cabc_supported) + if (!panel->vbt.dsi.config->cabc_supported) return; - switch (i915->vbt.dsi.config->dl_dcs_cabc_ports) { + switch (panel->vbt.dsi.config->dl_dcs_cabc_ports) { case DL_DCS_PORT_A: - i915->vbt.dsi.cabc_ports = BIT(PORT_A); + panel->vbt.dsi.cabc_ports = BIT(PORT_A); break; case DL_DCS_PORT_C: - i915->vbt.dsi.cabc_ports = BIT(PORT_C); + panel->vbt.dsi.cabc_ports = BIT(PORT_C); break; default: case DL_DCS_PORT_A_AND_C: - i915->vbt.dsi.cabc_ports = + panel->vbt.dsi.cabc_ports = BIT(PORT_A) | BIT(PORT_C); break; } } static void -parse_mipi_config(struct drm_i915_private *i915) +parse_mipi_config(struct drm_i915_private *i915, + struct intel_panel *panel) { const struct bdb_mipi_config *start; const struct mipi_config *config; const struct mipi_pps_data *pps; - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; enum port port; /* parse MIPI blocks only if LFP type is MIPI */ @@ -1499,7 +1650,7 @@ parse_mipi_config(struct drm_i915_private *i915) return; /* Initialize this to undefined indicating no generic MIPI support */ - i915->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; + panel->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; /* Block #40 is already parsed and panel_fixed_mode is * stored in i915->lfp_lvds_vbt_mode @@ -1526,17 +1677,17 @@ parse_mipi_config(struct drm_i915_private *i915) pps = &start->pps[panel_type]; /* store as of now full data. Trim when we realise all is not needed */ - i915->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); - if (!i915->vbt.dsi.config) + panel->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); + if (!panel->vbt.dsi.config) return; - i915->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); - if (!i915->vbt.dsi.pps) { - kfree(i915->vbt.dsi.config); + panel->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); + if (!panel->vbt.dsi.pps) { + kfree(panel->vbt.dsi.config); return; } - parse_dsi_backlight_ports(i915, i915->vbt.version, port); + parse_dsi_backlight_ports(i915, panel, port); /* FIXME is the 90 vs. 270 correct? */ switch (config->rotation) { @@ -1545,25 +1696,25 @@ parse_mipi_config(struct drm_i915_private *i915) * Most (all?) VBTs claim 0 degrees despite having * an upside down panel, thus we do not trust this. */ - i915->vbt.dsi.orientation = + panel->vbt.dsi.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; break; case ENABLE_ROTATION_90: - i915->vbt.dsi.orientation = + panel->vbt.dsi.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; break; case ENABLE_ROTATION_180: - i915->vbt.dsi.orientation = + panel->vbt.dsi.orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; break; case ENABLE_ROTATION_270: - i915->vbt.dsi.orientation = + panel->vbt.dsi.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; break; } /* We have mandatory mipi config blocks. Initialize as generic panel */ - i915->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; + panel->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; } /* Find the sequence block and size for the given panel. */ @@ -1726,13 +1877,14 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total) * Get len of pre-fixed deassert fragment from a v1 init OTP sequence, * skip all delay + gpio operands and stop at the first DSI packet op. */ -static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915) +static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915, + struct intel_panel *panel) { - const u8 *data = i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; + const u8 *data = panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; int index, len; if (drm_WARN_ON(&i915->drm, - !data || i915->vbt.dsi.seq_version != 1)) + !data || panel->vbt.dsi.seq_version != 1)) return 0; /* index = 1 to skip sequence byte */ @@ -1760,7 +1912,8 @@ static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915) * these devices we split the init OTP sequence into a deassert sequence and * the actual init OTP part. */ -static void fixup_mipi_sequences(struct drm_i915_private *i915) +static void fixup_mipi_sequences(struct drm_i915_private *i915, + struct intel_panel *panel) { u8 *init_otp; int len; @@ -1770,18 +1923,18 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915) return; /* Limit this to v1 vid-mode sequences */ - if (i915->vbt.dsi.config->is_cmd_mode || - i915->vbt.dsi.seq_version != 1) + if (panel->vbt.dsi.config->is_cmd_mode || + panel->vbt.dsi.seq_version != 1) return; /* Only do this if there are otp and assert seqs and no deassert seq */ - if (!i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || - !i915->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || - i915->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) + if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || + !panel->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || + panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) return; /* The deassert-sequence ends at the first DSI packet */ - len = get_init_otp_deassert_fragment_len(i915); + len = get_init_otp_deassert_fragment_len(i915, panel); if (!len) return; @@ -1789,25 +1942,26 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915) "Using init OTP fragment to deassert reset\n"); /* Copy the fragment, update seq byte and terminate it */ - init_otp = (u8 *)i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; - i915->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); - if (!i915->vbt.dsi.deassert_seq) + init_otp = (u8 *)panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; + panel->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); + if (!panel->vbt.dsi.deassert_seq) return; - i915->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; - i915->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; + panel->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; + panel->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; /* Use the copy for deassert */ - i915->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = - i915->vbt.dsi.deassert_seq; + panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = + panel->vbt.dsi.deassert_seq; /* Replace the last byte of the fragment with init OTP seq byte */ init_otp[len - 1] = MIPI_SEQ_INIT_OTP; /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */ - i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; + panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; } static void -parse_mipi_sequence(struct drm_i915_private *i915) +parse_mipi_sequence(struct drm_i915_private *i915, + struct intel_panel *panel) { - int panel_type = i915->vbt.panel_type; + int panel_type = panel->vbt.panel_type; const struct bdb_mipi_sequence *sequence; const u8 *seq_data; u32 seq_size; @@ -1815,7 +1969,7 @@ parse_mipi_sequence(struct drm_i915_private *i915) int index = 0; /* Only our generic panel driver uses the sequence block. */ - if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) + if (panel->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) return; sequence = find_section(i915, BDB_MIPI_SEQUENCE); @@ -1861,7 +2015,7 @@ parse_mipi_sequence(struct drm_i915_private *i915) drm_dbg_kms(&i915->drm, "Unsupported sequence %u\n", seq_id); - i915->vbt.dsi.sequence[seq_id] = data + index; + panel->vbt.dsi.sequence[seq_id] = data + index; if (sequence->version >= 3) index = goto_next_sequence_v3(data, index, seq_size); @@ -1874,18 +2028,18 @@ parse_mipi_sequence(struct drm_i915_private *i915) } } - i915->vbt.dsi.data = data; - i915->vbt.dsi.size = seq_size; - i915->vbt.dsi.seq_version = sequence->version; + panel->vbt.dsi.data = data; + panel->vbt.dsi.size = seq_size; + panel->vbt.dsi.seq_version = sequence->version; - fixup_mipi_sequences(i915); + fixup_mipi_sequences(i915, panel); drm_dbg(&i915->drm, "MIPI related VBT parsing complete\n"); return; err: kfree(data); - memset(i915->vbt.dsi.sequence, 0, sizeof(i915->vbt.dsi.sequence)); + memset(panel->vbt.dsi.sequence, 0, sizeof(panel->vbt.dsi.sequence)); } static void @@ -2344,10 +2498,10 @@ static void sanitize_device_type(struct intel_bios_encoder_data *devdata, if (port != PORT_A || DISPLAY_VER(i915) >= 12) return; - if (!(devdata->child.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING)) + if (!intel_bios_encoder_supports_dvi(devdata)) return; - is_hdmi = !(devdata->child.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT); + is_hdmi = intel_bios_encoder_supports_hdmi(devdata); drm_dbg_kms(&i915->drm, "VBT claims port A supports DVI%s, ignoring\n", is_hdmi ? "/HDMI" : ""); @@ -2433,33 +2587,13 @@ static bool is_port_valid(struct drm_i915_private *i915, enum port port) return true; } -static void parse_ddi_port(struct drm_i915_private *i915, - struct intel_bios_encoder_data *devdata) +static void print_ddi_port(const struct intel_bios_encoder_data *devdata, + enum port port) { + struct drm_i915_private *i915 = devdata->i915; const struct child_device_config *child = &devdata->child; bool is_dvi, is_hdmi, is_dp, is_edp, is_crt, supports_typec_usb, supports_tbt; int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock; - enum port port; - - port = dvo_port_to_port(i915, child->dvo_port); - if (port == PORT_NONE) - return; - - if (!is_port_valid(i915, port)) { - drm_dbg_kms(&i915->drm, - "VBT reports port %c as supported, but that can't be true: skipping\n", - port_name(port)); - return; - } - - if (i915->vbt.ports[port]) { - drm_dbg_kms(&i915->drm, - "More than one child device for port %c in VBT, using the first.\n", - port_name(port)); - return; - } - - sanitize_device_type(devdata, port); is_dvi = intel_bios_encoder_supports_dvi(devdata); is_dp = intel_bios_encoder_supports_dp(devdata); @@ -2477,12 +2611,6 @@ static void parse_ddi_port(struct drm_i915_private *i915, supports_typec_usb, supports_tbt, devdata->dsc != NULL); - if (is_dvi) - sanitize_ddc_pin(devdata, port); - - if (is_dp) - sanitize_aux_ch(devdata, port); - hdmi_level_shift = _intel_bios_hdmi_level_shift(devdata); if (hdmi_level_shift >= 0) { drm_dbg_kms(&i915->drm, @@ -2514,6 +2642,41 @@ static void parse_ddi_port(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "Port %c VBT DP max link rate: %d\n", port_name(port), dp_max_link_rate); +} + +static void parse_ddi_port(struct intel_bios_encoder_data *devdata) +{ + struct drm_i915_private *i915 = devdata->i915; + const struct child_device_config *child = &devdata->child; + enum port port; + + port = dvo_port_to_port(i915, child->dvo_port); + if (port == PORT_NONE) + return; + + if (!is_port_valid(i915, port)) { + drm_dbg_kms(&i915->drm, + "VBT reports port %c as supported, but that can't be true: skipping\n", + port_name(port)); + return; + } + + if (i915->vbt.ports[port]) { + drm_dbg_kms(&i915->drm, + "More than one child device for port %c in VBT, using the first.\n", + port_name(port)); + return; + } + + sanitize_device_type(devdata, port); + + print_ddi_port(devdata, port); + + if (intel_bios_encoder_supports_dvi(devdata)) + sanitize_ddc_pin(devdata, port); + + if (intel_bios_encoder_supports_dp(devdata)) + sanitize_aux_ch(devdata, port); i915->vbt.ports[port] = devdata; } @@ -2531,7 +2694,7 @@ static void parse_ddi_ports(struct drm_i915_private *i915) return; list_for_each_entry(devdata, &i915->vbt.display_devices, node) - parse_ddi_port(i915, devdata); + parse_ddi_port(devdata); } static void @@ -2639,15 +2802,6 @@ init_vbt_defaults(struct drm_i915_private *i915) { i915->vbt.crt_ddc_pin = GMBUS_PIN_VGADDC; - /* Default to having backlight */ - i915->vbt.backlight.present = true; - - /* LFP panel data */ - i915->vbt.lvds_dither = 1; - - /* SDVO panel data */ - i915->vbt.sdvo_lvds_vbt_mode = NULL; - /* general features */ i915->vbt.int_tv_support = 1; i915->vbt.int_crt_support = 1; @@ -2667,6 +2821,17 @@ init_vbt_defaults(struct drm_i915_private *i915) i915->vbt.lvds_ssc_freq); } +/* Common defaults which may be overridden by VBT. */ +static void +init_vbt_panel_defaults(struct intel_panel *panel) +{ + /* Default to having backlight */ + panel->vbt.backlight.present = true; + + /* LFP panel data */ + panel->vbt.lvds_dither = true; +} + /* Defaults to initialize only if there is no VBT. */ static void init_vbt_missing_defaults(struct drm_i915_private *i915) @@ -2953,17 +3118,7 @@ void intel_bios_init(struct drm_i915_private *i915) /* Grab useful general definitions */ parse_general_features(i915); parse_general_definitions(i915); - parse_panel_options(i915); - parse_generic_dtd(i915); - parse_lfp_data(i915); - 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); @@ -2982,6 +3137,28 @@ out: kfree(oprom_vbt); } +void intel_bios_init_panel(struct drm_i915_private *i915, + struct intel_panel *panel, + const struct intel_bios_encoder_data *devdata, + const struct edid *edid) +{ + init_vbt_panel_defaults(panel); + + panel->vbt.panel_type = get_panel_type(i915, devdata, edid); + + parse_panel_options(i915, panel); + parse_generic_dtd(i915, panel); + parse_lfp_data(i915, panel); + parse_lfp_backlight(i915, panel); + parse_sdvo_panel_data(i915, panel); + parse_panel_driver_features(i915, panel); + parse_power_conservation_features(i915, panel); + parse_edp(i915, panel); + parse_psr(i915, panel); + parse_mipi_config(i915, panel); + parse_mipi_sequence(i915, panel); +} + /** * intel_bios_driver_remove - Free any resources allocated by intel_bios_init() * @i915: i915 device instance @@ -3001,19 +3178,22 @@ void intel_bios_driver_remove(struct drm_i915_private *i915) 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); - i915->vbt.lfp_lvds_vbt_mode = NULL; - kfree(i915->vbt.dsi.data); - i915->vbt.dsi.data = NULL; - kfree(i915->vbt.dsi.pps); - i915->vbt.dsi.pps = NULL; - kfree(i915->vbt.dsi.config); - i915->vbt.dsi.config = NULL; - kfree(i915->vbt.dsi.deassert_seq); - i915->vbt.dsi.deassert_seq = NULL; +void intel_bios_fini_panel(struct intel_panel *panel) +{ + kfree(panel->vbt.sdvo_lvds_vbt_mode); + panel->vbt.sdvo_lvds_vbt_mode = NULL; + kfree(panel->vbt.lfp_lvds_vbt_mode); + panel->vbt.lfp_lvds_vbt_mode = NULL; + kfree(panel->vbt.dsi.data); + panel->vbt.dsi.data = NULL; + kfree(panel->vbt.dsi.pps); + panel->vbt.dsi.pps = NULL; + kfree(panel->vbt.dsi.config); + panel->vbt.dsi.config = NULL; + kfree(panel->vbt.dsi.deassert_seq); + panel->vbt.dsi.deassert_seq = NULL; } /** |