1a61127c2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f910b411SAlan Cox /*
3f910b411SAlan Cox  * Copyright (c) 2006 Intel Corporation
4f910b411SAlan Cox  *
5f910b411SAlan Cox  * Authors:
6f910b411SAlan Cox  *    Eric Anholt <eric@anholt.net>
7f910b411SAlan Cox  */
8*da68386dSThomas Zimmermann 
9*da68386dSThomas Zimmermann #include <drm/display/drm_dp_helper.h>
10f910b411SAlan Cox #include <drm/drm.h>
11d825c565SSam Ravnborg 
120c7b178aSSam Ravnborg #include "intel_bios.h"
13f910b411SAlan Cox #include "psb_drv.h"
14f910b411SAlan Cox #include "psb_intel_drv.h"
15f910b411SAlan Cox #include "psb_intel_reg.h"
16f910b411SAlan Cox 
171fb28e9eSAlan Cox #define	SLAVE_ADDR1	0x70
181fb28e9eSAlan Cox #define	SLAVE_ADDR2	0x72
19f910b411SAlan Cox 
find_section(struct bdb_header * bdb,int section_id)20f910b411SAlan Cox static void *find_section(struct bdb_header *bdb, int section_id)
21f910b411SAlan Cox {
22f910b411SAlan Cox 	u8 *base = (u8 *)bdb;
23f910b411SAlan Cox 	int index = 0;
24f910b411SAlan Cox 	u16 total, current_size;
25f910b411SAlan Cox 	u8 current_id;
26f910b411SAlan Cox 
27f910b411SAlan Cox 	/* skip to first section */
28f910b411SAlan Cox 	index += bdb->header_size;
29f910b411SAlan Cox 	total = bdb->bdb_size;
30f910b411SAlan Cox 
31f910b411SAlan Cox 	/* walk the sections looking for section_id */
32f910b411SAlan Cox 	while (index < total) {
33f910b411SAlan Cox 		current_id = *(base + index);
34f910b411SAlan Cox 		index++;
35f910b411SAlan Cox 		current_size = *((u16 *)(base + index));
36f910b411SAlan Cox 		index += 2;
37f910b411SAlan Cox 		if (current_id == section_id)
38f910b411SAlan Cox 			return base + index;
39f910b411SAlan Cox 		index += current_size;
40f910b411SAlan Cox 	}
41f910b411SAlan Cox 
42f910b411SAlan Cox 	return NULL;
43f910b411SAlan Cox }
44f910b411SAlan Cox 
45d112a816SZhao Yakui static void
parse_edp(struct drm_psb_private * dev_priv,struct bdb_header * bdb)46d112a816SZhao Yakui parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
47d112a816SZhao Yakui {
48d112a816SZhao Yakui 	struct bdb_edp *edp;
49d112a816SZhao Yakui 	struct edp_power_seq *edp_pps;
50d112a816SZhao Yakui 	struct edp_link_params *edp_link_params;
51d112a816SZhao Yakui 	uint8_t	panel_type;
52d112a816SZhao Yakui 
53d112a816SZhao Yakui 	edp = find_section(bdb, BDB_EDP);
54d112a816SZhao Yakui 
55d112a816SZhao Yakui 	dev_priv->edp.bpp = 18;
56d112a816SZhao Yakui 	if (!edp) {
57d112a816SZhao Yakui 		if (dev_priv->edp.support) {
58d112a816SZhao Yakui 			DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported, assume %dbpp panel color depth.\n",
59d112a816SZhao Yakui 				      dev_priv->edp.bpp);
60d112a816SZhao Yakui 		}
61d112a816SZhao Yakui 		return;
62d112a816SZhao Yakui 	}
63d112a816SZhao Yakui 
64d112a816SZhao Yakui 	panel_type = dev_priv->panel_type;
65d112a816SZhao Yakui 	switch ((edp->color_depth >> (panel_type * 2)) & 3) {
66d112a816SZhao Yakui 	case EDP_18BPP:
67d112a816SZhao Yakui 		dev_priv->edp.bpp = 18;
68d112a816SZhao Yakui 		break;
69d112a816SZhao Yakui 	case EDP_24BPP:
70d112a816SZhao Yakui 		dev_priv->edp.bpp = 24;
71d112a816SZhao Yakui 		break;
72d112a816SZhao Yakui 	case EDP_30BPP:
73d112a816SZhao Yakui 		dev_priv->edp.bpp = 30;
74d112a816SZhao Yakui 		break;
75d112a816SZhao Yakui 	}
76d112a816SZhao Yakui 
77d112a816SZhao Yakui 	/* Get the eDP sequencing and link info */
78d112a816SZhao Yakui 	edp_pps = &edp->power_seqs[panel_type];
79d112a816SZhao Yakui 	edp_link_params = &edp->link_params[panel_type];
80d112a816SZhao Yakui 
81d112a816SZhao Yakui 	dev_priv->edp.pps = *edp_pps;
82d112a816SZhao Yakui 
83d112a816SZhao Yakui 	DRM_DEBUG_KMS("EDP timing in vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
84d112a816SZhao Yakui 				dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8,
85d112a816SZhao Yakui 				dev_priv->edp.pps.t9, dev_priv->edp.pps.t10,
86d112a816SZhao Yakui 				dev_priv->edp.pps.t11_t12);
87d112a816SZhao Yakui 
88d112a816SZhao Yakui 	dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
89d112a816SZhao Yakui 		DP_LINK_BW_1_62;
90d112a816SZhao Yakui 	switch (edp_link_params->lanes) {
91d112a816SZhao Yakui 	case 0:
92d112a816SZhao Yakui 		dev_priv->edp.lanes = 1;
93d112a816SZhao Yakui 		break;
94d112a816SZhao Yakui 	case 1:
95d112a816SZhao Yakui 		dev_priv->edp.lanes = 2;
96d112a816SZhao Yakui 		break;
97d112a816SZhao Yakui 	case 3:
98d112a816SZhao Yakui 	default:
99d112a816SZhao Yakui 		dev_priv->edp.lanes = 4;
100d112a816SZhao Yakui 		break;
101d112a816SZhao Yakui 	}
102d112a816SZhao Yakui 	DRM_DEBUG_KMS("VBT reports EDP: Lane_count %d, Lane_rate %d, Bpp %d\n",
103d112a816SZhao Yakui 			dev_priv->edp.lanes, dev_priv->edp.rate, dev_priv->edp.bpp);
104d112a816SZhao Yakui 
105d112a816SZhao Yakui 	switch (edp_link_params->preemphasis) {
106d112a816SZhao Yakui 	case 0:
10731160006SSonika Jindal 		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
108d112a816SZhao Yakui 		break;
109d112a816SZhao Yakui 	case 1:
11031160006SSonika Jindal 		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
111d112a816SZhao Yakui 		break;
112d112a816SZhao Yakui 	case 2:
11331160006SSonika Jindal 		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
114d112a816SZhao Yakui 		break;
115d112a816SZhao Yakui 	case 3:
11631160006SSonika Jindal 		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
117d112a816SZhao Yakui 		break;
118d112a816SZhao Yakui 	}
119d112a816SZhao Yakui 	switch (edp_link_params->vswing) {
120d112a816SZhao Yakui 	case 0:
12131160006SSonika Jindal 		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
122d112a816SZhao Yakui 		break;
123d112a816SZhao Yakui 	case 1:
12431160006SSonika Jindal 		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
125d112a816SZhao Yakui 		break;
126d112a816SZhao Yakui 	case 2:
12731160006SSonika Jindal 		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
128d112a816SZhao Yakui 		break;
129d112a816SZhao Yakui 	case 3:
13031160006SSonika Jindal 		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
131d112a816SZhao Yakui 		break;
132d112a816SZhao Yakui 	}
133d112a816SZhao Yakui 	DRM_DEBUG_KMS("VBT reports EDP: VSwing  %d, Preemph %d\n",
134d112a816SZhao Yakui 			dev_priv->edp.vswing, dev_priv->edp.preemphasis);
135d112a816SZhao Yakui }
136d112a816SZhao Yakui 
1371fb28e9eSAlan Cox static u16
get_blocksize(void * p)1381fb28e9eSAlan Cox get_blocksize(void *p)
1391fb28e9eSAlan Cox {
1401fb28e9eSAlan Cox 	u16 *block_ptr, block_size;
1411fb28e9eSAlan Cox 
1421fb28e9eSAlan Cox 	block_ptr = (u16 *)((char *)p - 2);
1431fb28e9eSAlan Cox 	block_size = *block_ptr;
1441fb28e9eSAlan Cox 	return block_size;
1451fb28e9eSAlan Cox }
1461fb28e9eSAlan Cox 
fill_detail_timing_data(struct drm_display_mode * panel_fixed_mode,struct lvds_dvo_timing * dvo_timing)147f910b411SAlan Cox static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
148f910b411SAlan Cox 			struct lvds_dvo_timing *dvo_timing)
149f910b411SAlan Cox {
150f910b411SAlan Cox 	panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
151f910b411SAlan Cox 		dvo_timing->hactive_lo;
152f910b411SAlan Cox 	panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
153f910b411SAlan Cox 		((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
154f910b411SAlan Cox 	panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
155f910b411SAlan Cox 		dvo_timing->hsync_pulse_width;
156f910b411SAlan Cox 	panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
157f910b411SAlan Cox 		((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
158f910b411SAlan Cox 
159f910b411SAlan Cox 	panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
160f910b411SAlan Cox 		dvo_timing->vactive_lo;
161f910b411SAlan Cox 	panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
162f910b411SAlan Cox 		dvo_timing->vsync_off;
163f910b411SAlan Cox 	panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
164f910b411SAlan Cox 		dvo_timing->vsync_pulse_width;
165f910b411SAlan Cox 	panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
166f910b411SAlan Cox 		((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
167f910b411SAlan Cox 	panel_fixed_mode->clock = dvo_timing->clock * 10;
168f910b411SAlan Cox 	panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
169f910b411SAlan Cox 
1701fb28e9eSAlan Cox 	if (dvo_timing->hsync_positive)
1711fb28e9eSAlan Cox 		panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
1721fb28e9eSAlan Cox 	else
1731fb28e9eSAlan Cox 		panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
1741fb28e9eSAlan Cox 
1751fb28e9eSAlan Cox 	if (dvo_timing->vsync_positive)
1761fb28e9eSAlan Cox 		panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
1771fb28e9eSAlan Cox 	else
1781fb28e9eSAlan Cox 		panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
1791fb28e9eSAlan Cox 
180f910b411SAlan Cox 	/* Some VBTs have bogus h/vtotal values */
181f910b411SAlan Cox 	if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
182f910b411SAlan Cox 		panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
183f910b411SAlan Cox 	if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
184f910b411SAlan Cox 		panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
185f910b411SAlan Cox 
186f910b411SAlan Cox 	drm_mode_set_name(panel_fixed_mode);
187f910b411SAlan Cox }
188f910b411SAlan Cox 
parse_backlight_data(struct drm_psb_private * dev_priv,struct bdb_header * bdb)189f910b411SAlan Cox static void parse_backlight_data(struct drm_psb_private *dev_priv,
190f910b411SAlan Cox 				struct bdb_header *bdb)
191f910b411SAlan Cox {
192f910b411SAlan Cox 	struct bdb_lvds_backlight *vbt_lvds_bl = NULL;
193f910b411SAlan Cox 	struct bdb_lvds_backlight *lvds_bl;
194f910b411SAlan Cox 	u8 p_type = 0;
195f910b411SAlan Cox 	void *bl_start = NULL;
196f910b411SAlan Cox 	struct bdb_lvds_options *lvds_opts
197f910b411SAlan Cox 				= find_section(bdb, BDB_LVDS_OPTIONS);
198f910b411SAlan Cox 
199f910b411SAlan Cox 	dev_priv->lvds_bl = NULL;
200f910b411SAlan Cox 
201f910b411SAlan Cox 	if (lvds_opts)
202f910b411SAlan Cox 		p_type = lvds_opts->panel_type;
203f910b411SAlan Cox 	else
204f910b411SAlan Cox 		return;
205f910b411SAlan Cox 
206f910b411SAlan Cox 	bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT);
207f910b411SAlan Cox 	vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type;
208f910b411SAlan Cox 
209bc6a5419SAlexandru Gheorghiu 	lvds_bl = kmemdup(vbt_lvds_bl, sizeof(*vbt_lvds_bl), GFP_KERNEL);
210f910b411SAlan Cox 	if (!lvds_bl) {
211c2f17e60SThomas Zimmermann 		dev_err(dev_priv->dev.dev, "out of memory for backlight data\n");
212f910b411SAlan Cox 		return;
213f910b411SAlan Cox 	}
214f910b411SAlan Cox 	dev_priv->lvds_bl = lvds_bl;
215f910b411SAlan Cox }
216f910b411SAlan Cox 
217f910b411SAlan Cox /* Try to find integrated panel data */
parse_lfp_panel_data(struct drm_psb_private * dev_priv,struct bdb_header * bdb)218f910b411SAlan Cox static void parse_lfp_panel_data(struct drm_psb_private *dev_priv,
219f910b411SAlan Cox 			    struct bdb_header *bdb)
220f910b411SAlan Cox {
221f910b411SAlan Cox 	struct bdb_lvds_options *lvds_options;
222f910b411SAlan Cox 	struct bdb_lvds_lfp_data *lvds_lfp_data;
223f910b411SAlan Cox 	struct bdb_lvds_lfp_data_entry *entry;
224f910b411SAlan Cox 	struct lvds_dvo_timing *dvo_timing;
225f910b411SAlan Cox 	struct drm_display_mode *panel_fixed_mode;
226f910b411SAlan Cox 
227f910b411SAlan Cox 	/* Defaults if we can't find VBT info */
228f910b411SAlan Cox 	dev_priv->lvds_dither = 0;
229f910b411SAlan Cox 	dev_priv->lvds_vbt = 0;
230f910b411SAlan Cox 
231f910b411SAlan Cox 	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
232f910b411SAlan Cox 	if (!lvds_options)
233f910b411SAlan Cox 		return;
234f910b411SAlan Cox 
235f910b411SAlan Cox 	dev_priv->lvds_dither = lvds_options->pixel_dither;
236d112a816SZhao Yakui 	dev_priv->panel_type = lvds_options->panel_type;
237d112a816SZhao Yakui 
238f910b411SAlan Cox 	if (lvds_options->panel_type == 0xff)
239f910b411SAlan Cox 		return;
240f910b411SAlan Cox 
241f910b411SAlan Cox 	lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
242f910b411SAlan Cox 	if (!lvds_lfp_data)
243f910b411SAlan Cox 		return;
244f910b411SAlan Cox 
245f910b411SAlan Cox 
246f910b411SAlan Cox 	entry = &lvds_lfp_data->data[lvds_options->panel_type];
247f910b411SAlan Cox 	dvo_timing = &entry->dvo_timing;
248f910b411SAlan Cox 
249f910b411SAlan Cox 	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode),
250f910b411SAlan Cox 				      GFP_KERNEL);
251f910b411SAlan Cox 	if (panel_fixed_mode == NULL) {
252c2f17e60SThomas Zimmermann 		dev_err(dev_priv->dev.dev, "out of memory for fixed panel mode\n");
253f910b411SAlan Cox 		return;
254f910b411SAlan Cox 	}
255f910b411SAlan Cox 
256f910b411SAlan Cox 	dev_priv->lvds_vbt = 1;
257f910b411SAlan Cox 	fill_detail_timing_data(panel_fixed_mode, dvo_timing);
258f910b411SAlan Cox 
259f910b411SAlan Cox 	if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) {
260f910b411SAlan Cox 		dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
261f910b411SAlan Cox 		drm_mode_debug_printmodeline(panel_fixed_mode);
262f910b411SAlan Cox 	} else {
263c2f17e60SThomas Zimmermann 		dev_dbg(dev_priv->dev.dev, "ignoring invalid LVDS VBT\n");
264f910b411SAlan Cox 		dev_priv->lvds_vbt = 0;
265f910b411SAlan Cox 		kfree(panel_fixed_mode);
266f910b411SAlan Cox 	}
267f910b411SAlan Cox 	return;
268f910b411SAlan Cox }
269f910b411SAlan Cox 
270f910b411SAlan Cox /* Try to find sdvo panel data */
parse_sdvo_panel_data(struct drm_psb_private * dev_priv,struct bdb_header * bdb)271f910b411SAlan Cox static void parse_sdvo_panel_data(struct drm_psb_private *dev_priv,
272f910b411SAlan Cox 		      struct bdb_header *bdb)
273f910b411SAlan Cox {
274f910b411SAlan Cox 	struct bdb_sdvo_lvds_options *sdvo_lvds_options;
275f910b411SAlan Cox 	struct lvds_dvo_timing *dvo_timing;
276f910b411SAlan Cox 	struct drm_display_mode *panel_fixed_mode;
277f910b411SAlan Cox 
278f910b411SAlan Cox 	dev_priv->sdvo_lvds_vbt_mode = NULL;
279f910b411SAlan Cox 
280f910b411SAlan Cox 	sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
281f910b411SAlan Cox 	if (!sdvo_lvds_options)
282f910b411SAlan Cox 		return;
283f910b411SAlan Cox 
284f910b411SAlan Cox 	dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS);
285f910b411SAlan Cox 	if (!dvo_timing)
286f910b411SAlan Cox 		return;
287f910b411SAlan Cox 
288f910b411SAlan Cox 	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
289f910b411SAlan Cox 
290f910b411SAlan Cox 	if (!panel_fixed_mode)
291f910b411SAlan Cox 		return;
292f910b411SAlan Cox 
293f910b411SAlan Cox 	fill_detail_timing_data(panel_fixed_mode,
294f910b411SAlan Cox 			dvo_timing + sdvo_lvds_options->panel_type);
295f910b411SAlan Cox 
296f910b411SAlan Cox 	dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
297f910b411SAlan Cox 
298f910b411SAlan Cox 	return;
299f910b411SAlan Cox }
300f910b411SAlan Cox 
parse_general_features(struct drm_psb_private * dev_priv,struct bdb_header * bdb)301f910b411SAlan Cox static void parse_general_features(struct drm_psb_private *dev_priv,
302f910b411SAlan Cox 		       struct bdb_header *bdb)
303f910b411SAlan Cox {
304f910b411SAlan Cox 	struct bdb_general_features *general;
305f910b411SAlan Cox 
306f910b411SAlan Cox 	/* Set sensible defaults in case we can't find the general block */
307f910b411SAlan Cox 	dev_priv->int_tv_support = 1;
308f910b411SAlan Cox 	dev_priv->int_crt_support = 1;
309f910b411SAlan Cox 
310f910b411SAlan Cox 	general = find_section(bdb, BDB_GENERAL_FEATURES);
311f910b411SAlan Cox 	if (general) {
312f910b411SAlan Cox 		dev_priv->int_tv_support = general->int_tv_support;
313f910b411SAlan Cox 		dev_priv->int_crt_support = general->int_crt_support;
314f910b411SAlan Cox 		dev_priv->lvds_use_ssc = general->enable_ssc;
315f910b411SAlan Cox 
316f910b411SAlan Cox 		if (dev_priv->lvds_use_ssc) {
317f910b411SAlan Cox 			dev_priv->lvds_ssc_freq
318f910b411SAlan Cox 				= general->ssc_freq ? 100 : 96;
319f910b411SAlan Cox 		}
320f910b411SAlan Cox 	}
321f910b411SAlan Cox }
322f910b411SAlan Cox 
323642c52fcSAlan Cox static void
parse_sdvo_device_mapping(struct drm_psb_private * dev_priv,struct bdb_header * bdb)3241fb28e9eSAlan Cox parse_sdvo_device_mapping(struct drm_psb_private *dev_priv,
3251fb28e9eSAlan Cox 			  struct bdb_header *bdb)
3261fb28e9eSAlan Cox {
3271fb28e9eSAlan Cox 	struct sdvo_device_mapping *p_mapping;
3281fb28e9eSAlan Cox 	struct bdb_general_definitions *p_defs;
3291fb28e9eSAlan Cox 	struct child_device_config *p_child;
3301fb28e9eSAlan Cox 	int i, child_device_num, count;
3311fb28e9eSAlan Cox 	u16	block_size;
3321fb28e9eSAlan Cox 
3331fb28e9eSAlan Cox 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
3341fb28e9eSAlan Cox 	if (!p_defs) {
3351fb28e9eSAlan Cox 		DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
3361fb28e9eSAlan Cox 		return;
3371fb28e9eSAlan Cox 	}
3381fb28e9eSAlan Cox 	/* judge whether the size of child device meets the requirements.
3391fb28e9eSAlan Cox 	 * If the child device size obtained from general definition block
3401fb28e9eSAlan Cox 	 * is different with sizeof(struct child_device_config), skip the
3411fb28e9eSAlan Cox 	 * parsing of sdvo device info
3421fb28e9eSAlan Cox 	 */
3431fb28e9eSAlan Cox 	if (p_defs->child_dev_size != sizeof(*p_child)) {
3441fb28e9eSAlan Cox 		/* different child dev size . Ignore it */
3451fb28e9eSAlan Cox 		DRM_DEBUG_KMS("different child size is found. Invalid.\n");
3461fb28e9eSAlan Cox 		return;
3471fb28e9eSAlan Cox 	}
3481fb28e9eSAlan Cox 	/* get the block size of general definitions */
3491fb28e9eSAlan Cox 	block_size = get_blocksize(p_defs);
3501fb28e9eSAlan Cox 	/* get the number of child device */
3511fb28e9eSAlan Cox 	child_device_num = (block_size - sizeof(*p_defs)) /
3521fb28e9eSAlan Cox 				sizeof(*p_child);
3531fb28e9eSAlan Cox 	count = 0;
3541fb28e9eSAlan Cox 	for (i = 0; i < child_device_num; i++) {
3551fb28e9eSAlan Cox 		p_child = &(p_defs->devices[i]);
3561fb28e9eSAlan Cox 		if (!p_child->device_type) {
3571fb28e9eSAlan Cox 			/* skip the device block if device type is invalid */
3581fb28e9eSAlan Cox 			continue;
3591fb28e9eSAlan Cox 		}
3601fb28e9eSAlan Cox 		if (p_child->slave_addr != SLAVE_ADDR1 &&
3611fb28e9eSAlan Cox 			p_child->slave_addr != SLAVE_ADDR2) {
3621fb28e9eSAlan Cox 			/*
3631fb28e9eSAlan Cox 			 * If the slave address is neither 0x70 nor 0x72,
3641fb28e9eSAlan Cox 			 * it is not a SDVO device. Skip it.
3651fb28e9eSAlan Cox 			 */
3661fb28e9eSAlan Cox 			continue;
3671fb28e9eSAlan Cox 		}
3681fb28e9eSAlan Cox 		if (p_child->dvo_port != DEVICE_PORT_DVOB &&
3691fb28e9eSAlan Cox 			p_child->dvo_port != DEVICE_PORT_DVOC) {
3701fb28e9eSAlan Cox 			/* skip the incorrect SDVO port */
3711fb28e9eSAlan Cox 			DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n");
3721fb28e9eSAlan Cox 			continue;
3731fb28e9eSAlan Cox 		}
3741fb28e9eSAlan Cox 		DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
3751fb28e9eSAlan Cox 				" %s port\n",
3761fb28e9eSAlan Cox 				p_child->slave_addr,
3771fb28e9eSAlan Cox 				(p_child->dvo_port == DEVICE_PORT_DVOB) ?
3781fb28e9eSAlan Cox 					"SDVOB" : "SDVOC");
3791fb28e9eSAlan Cox 		p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
3801fb28e9eSAlan Cox 		if (!p_mapping->initialized) {
3811fb28e9eSAlan Cox 			p_mapping->dvo_port = p_child->dvo_port;
3821fb28e9eSAlan Cox 			p_mapping->slave_addr = p_child->slave_addr;
3831fb28e9eSAlan Cox 			p_mapping->dvo_wiring = p_child->dvo_wiring;
3841fb28e9eSAlan Cox 			p_mapping->ddc_pin = p_child->ddc_pin;
3851fb28e9eSAlan Cox 			p_mapping->i2c_pin = p_child->i2c_pin;
3861fb28e9eSAlan Cox 			p_mapping->initialized = 1;
3871fb28e9eSAlan Cox 			DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
3881fb28e9eSAlan Cox 				      p_mapping->dvo_port,
3891fb28e9eSAlan Cox 				      p_mapping->slave_addr,
3901fb28e9eSAlan Cox 				      p_mapping->dvo_wiring,
3911fb28e9eSAlan Cox 				      p_mapping->ddc_pin,
3921fb28e9eSAlan Cox 				      p_mapping->i2c_pin);
3931fb28e9eSAlan Cox 		} else {
3941fb28e9eSAlan Cox 			DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
3951fb28e9eSAlan Cox 					 "two SDVO device.\n");
3961fb28e9eSAlan Cox 		}
3971fb28e9eSAlan Cox 		if (p_child->slave2_addr) {
3981fb28e9eSAlan Cox 			/* Maybe this is a SDVO device with multiple inputs */
3991fb28e9eSAlan Cox 			/* And the mapping info is not added */
4001fb28e9eSAlan Cox 			DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
4011fb28e9eSAlan Cox 				" is a SDVO device with multiple inputs.\n");
4021fb28e9eSAlan Cox 		}
4031fb28e9eSAlan Cox 		count++;
4041fb28e9eSAlan Cox 	}
4051fb28e9eSAlan Cox 
4061fb28e9eSAlan Cox 	if (!count) {
4071fb28e9eSAlan Cox 		/* No SDVO device info is found */
4081fb28e9eSAlan Cox 		DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
4091fb28e9eSAlan Cox 	}
4101fb28e9eSAlan Cox 	return;
4111fb28e9eSAlan Cox }
4121fb28e9eSAlan Cox 
4131fb28e9eSAlan Cox 
4141fb28e9eSAlan Cox static void
parse_driver_features(struct drm_psb_private * dev_priv,struct bdb_header * bdb)415642c52fcSAlan Cox parse_driver_features(struct drm_psb_private *dev_priv,
416642c52fcSAlan Cox 		      struct bdb_header *bdb)
417642c52fcSAlan Cox {
418642c52fcSAlan Cox 	struct bdb_driver_features *driver;
419642c52fcSAlan Cox 
420642c52fcSAlan Cox 	driver = find_section(bdb, BDB_DRIVER_FEATURES);
421642c52fcSAlan Cox 	if (!driver)
422642c52fcSAlan Cox 		return;
423642c52fcSAlan Cox 
424d112a816SZhao Yakui 	if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
425d112a816SZhao Yakui 		dev_priv->edp.support = 1;
426d112a816SZhao Yakui 
4277c420636SPatrik Jakobsson 	dev_priv->lvds_enabled_in_vbt = driver->lvds_config != 0;
4287c420636SPatrik Jakobsson 	DRM_DEBUG_KMS("LVDS VBT config bits: 0x%x\n", driver->lvds_config);
4297c420636SPatrik Jakobsson 
430642c52fcSAlan Cox 	/* This bit means to use 96Mhz for DPLL_A or not */
431642c52fcSAlan Cox 	if (driver->primary_lfp_id)
432642c52fcSAlan Cox 		dev_priv->dplla_96mhz = true;
433642c52fcSAlan Cox 	else
434642c52fcSAlan Cox 		dev_priv->dplla_96mhz = false;
435642c52fcSAlan Cox }
436642c52fcSAlan Cox 
4371fb28e9eSAlan Cox static void
parse_device_mapping(struct drm_psb_private * dev_priv,struct bdb_header * bdb)4381fb28e9eSAlan Cox parse_device_mapping(struct drm_psb_private *dev_priv,
4391fb28e9eSAlan Cox 		       struct bdb_header *bdb)
4401fb28e9eSAlan Cox {
4411fb28e9eSAlan Cox 	struct bdb_general_definitions *p_defs;
4421fb28e9eSAlan Cox 	struct child_device_config *p_child, *child_dev_ptr;
4431fb28e9eSAlan Cox 	int i, child_device_num, count;
4441fb28e9eSAlan Cox 	u16	block_size;
4451fb28e9eSAlan Cox 
4461fb28e9eSAlan Cox 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
4471fb28e9eSAlan Cox 	if (!p_defs) {
4481fb28e9eSAlan Cox 		DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
4491fb28e9eSAlan Cox 		return;
4501fb28e9eSAlan Cox 	}
4511fb28e9eSAlan Cox 	/* judge whether the size of child device meets the requirements.
4521fb28e9eSAlan Cox 	 * If the child device size obtained from general definition block
4531fb28e9eSAlan Cox 	 * is different with sizeof(struct child_device_config), skip the
4541fb28e9eSAlan Cox 	 * parsing of sdvo device info
4551fb28e9eSAlan Cox 	 */
4561fb28e9eSAlan Cox 	if (p_defs->child_dev_size != sizeof(*p_child)) {
4571fb28e9eSAlan Cox 		/* different child dev size . Ignore it */
4581fb28e9eSAlan Cox 		DRM_DEBUG_KMS("different child size is found. Invalid.\n");
4591fb28e9eSAlan Cox 		return;
4601fb28e9eSAlan Cox 	}
4611fb28e9eSAlan Cox 	/* get the block size of general definitions */
4621fb28e9eSAlan Cox 	block_size = get_blocksize(p_defs);
4631fb28e9eSAlan Cox 	/* get the number of child device */
4641fb28e9eSAlan Cox 	child_device_num = (block_size - sizeof(*p_defs)) /
4651fb28e9eSAlan Cox 				sizeof(*p_child);
4661fb28e9eSAlan Cox 	count = 0;
4671fb28e9eSAlan Cox 	/* get the number of child devices that are present */
4681fb28e9eSAlan Cox 	for (i = 0; i < child_device_num; i++) {
4691fb28e9eSAlan Cox 		p_child = &(p_defs->devices[i]);
4701fb28e9eSAlan Cox 		if (!p_child->device_type) {
4711fb28e9eSAlan Cox 			/* skip the device block if device type is invalid */
4721fb28e9eSAlan Cox 			continue;
4731fb28e9eSAlan Cox 		}
4741fb28e9eSAlan Cox 		count++;
4751fb28e9eSAlan Cox 	}
4761fb28e9eSAlan Cox 	if (!count) {
4771fb28e9eSAlan Cox 		DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
4781fb28e9eSAlan Cox 		return;
4791fb28e9eSAlan Cox 	}
4801fb28e9eSAlan Cox 	dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
4811fb28e9eSAlan Cox 	if (!dev_priv->child_dev) {
4821fb28e9eSAlan Cox 		DRM_DEBUG_KMS("No memory space for child devices\n");
4831fb28e9eSAlan Cox 		return;
4841fb28e9eSAlan Cox 	}
4851fb28e9eSAlan Cox 
4861fb28e9eSAlan Cox 	dev_priv->child_dev_num = count;
4871fb28e9eSAlan Cox 	count = 0;
4881fb28e9eSAlan Cox 	for (i = 0; i < child_device_num; i++) {
4891fb28e9eSAlan Cox 		p_child = &(p_defs->devices[i]);
4901fb28e9eSAlan Cox 		if (!p_child->device_type) {
4911fb28e9eSAlan Cox 			/* skip the device block if device type is invalid */
4921fb28e9eSAlan Cox 			continue;
4931fb28e9eSAlan Cox 		}
4941fb28e9eSAlan Cox 		child_dev_ptr = dev_priv->child_dev + count;
4951fb28e9eSAlan Cox 		count++;
4961fb28e9eSAlan Cox 		memcpy((void *)child_dev_ptr, (void *)p_child,
4971fb28e9eSAlan Cox 					sizeof(*p_child));
4981fb28e9eSAlan Cox 	}
4991fb28e9eSAlan Cox 	return;
5001fb28e9eSAlan Cox }
5011fb28e9eSAlan Cox 
5021fb28e9eSAlan Cox 
503f910b411SAlan Cox /**
504f910b411SAlan Cox  * psb_intel_init_bios - initialize VBIOS settings & find VBT
505f910b411SAlan Cox  * @dev: DRM device
506f910b411SAlan Cox  *
507f910b411SAlan Cox  * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
508f910b411SAlan Cox  * to appropriate values.
509f910b411SAlan Cox  *
510f910b411SAlan Cox  * VBT existence is a sanity check that is relied on by other i830_bios.c code.
511f910b411SAlan Cox  * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
512f910b411SAlan Cox  * feed an updated VBT back through that, compared to what we'll fetch using
513f910b411SAlan Cox  * this method of groping around in the BIOS data.
514f910b411SAlan Cox  *
515f910b411SAlan Cox  * Returns 0 on success, nonzero on failure.
516f910b411SAlan Cox  */
psb_intel_init_bios(struct drm_device * dev)5170317c6ceSDan Carpenter int psb_intel_init_bios(struct drm_device *dev)
518f910b411SAlan Cox {
519f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
520a2c68495SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(dev->dev);
521f910b411SAlan Cox 	struct vbt_header *vbt = NULL;
5221fb28e9eSAlan Cox 	struct bdb_header *bdb = NULL;
5231fb28e9eSAlan Cox 	u8 __iomem *bios = NULL;
524f910b411SAlan Cox 	size_t size;
525f910b411SAlan Cox 	int i;
526f910b411SAlan Cox 
527d112a816SZhao Yakui 
528d112a816SZhao Yakui 	dev_priv->panel_type = 0xff;
529d112a816SZhao Yakui 
5301fb28e9eSAlan Cox 	/* XXX Should this validation be moved to intel_opregion.c? */
5311fb28e9eSAlan Cox 	if (dev_priv->opregion.vbt) {
5321fb28e9eSAlan Cox 		struct vbt_header *vbt = dev_priv->opregion.vbt;
5331fb28e9eSAlan Cox 		if (memcmp(vbt->signature, "$VBT", 4) == 0) {
5341fb28e9eSAlan Cox 			DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
5351fb28e9eSAlan Cox 					 vbt->signature);
5361fb28e9eSAlan Cox 			bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
5371fb28e9eSAlan Cox 		} else
5381fb28e9eSAlan Cox 			dev_priv->opregion.vbt = NULL;
5391fb28e9eSAlan Cox 	}
5401fb28e9eSAlan Cox 
5411fb28e9eSAlan Cox 	if (bdb == NULL) {
542f910b411SAlan Cox 		bios = pci_map_rom(pdev, &size);
543f910b411SAlan Cox 		if (!bios)
544f910b411SAlan Cox 			return -1;
545f910b411SAlan Cox 
546f910b411SAlan Cox 		/* Scour memory looking for the VBT signature */
547f910b411SAlan Cox 		for (i = 0; i + 4 < size; i++) {
548f910b411SAlan Cox 			if (!memcmp(bios + i, "$VBT", 4)) {
549f910b411SAlan Cox 				vbt = (struct vbt_header *)(bios + i);
550f910b411SAlan Cox 				break;
551f910b411SAlan Cox 			}
552f910b411SAlan Cox 		}
553f910b411SAlan Cox 
554f910b411SAlan Cox 		if (!vbt) {
555f910b411SAlan Cox 			dev_err(dev->dev, "VBT signature missing\n");
556f910b411SAlan Cox 			pci_unmap_rom(pdev, bios);
557f910b411SAlan Cox 			return -1;
558f910b411SAlan Cox 		}
559f910b411SAlan Cox 		bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
5601fb28e9eSAlan Cox 	}
561f910b411SAlan Cox 
5621fb28e9eSAlan Cox 	/* Grab useful general dxefinitions */
563f910b411SAlan Cox 	parse_general_features(dev_priv, bdb);
564642c52fcSAlan Cox 	parse_driver_features(dev_priv, bdb);
565f910b411SAlan Cox 	parse_lfp_panel_data(dev_priv, bdb);
566f910b411SAlan Cox 	parse_sdvo_panel_data(dev_priv, bdb);
5671fb28e9eSAlan Cox 	parse_sdvo_device_mapping(dev_priv, bdb);
5681fb28e9eSAlan Cox 	parse_device_mapping(dev_priv, bdb);
569f910b411SAlan Cox 	parse_backlight_data(dev_priv, bdb);
570d112a816SZhao Yakui 	parse_edp(dev_priv, bdb);
571f910b411SAlan Cox 
5721fb28e9eSAlan Cox 	if (bios)
573f910b411SAlan Cox 		pci_unmap_rom(pdev, bios);
574f910b411SAlan Cox 
575f910b411SAlan Cox 	return 0;
576f910b411SAlan Cox }
577f910b411SAlan Cox 
5788dd680ccSLee Jones /*
579f910b411SAlan Cox  * Destroy and free VBT data
580f910b411SAlan Cox  */
psb_intel_destroy_bios(struct drm_device * dev)581f910b411SAlan Cox void psb_intel_destroy_bios(struct drm_device *dev)
582f910b411SAlan Cox {
583f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
584f910b411SAlan Cox 
5854ab2c7f1SAlan Cox 	kfree(dev_priv->sdvo_lvds_vbt_mode);
5864ab2c7f1SAlan Cox 	kfree(dev_priv->lfp_lvds_vbt_mode);
5874ab2c7f1SAlan Cox 	kfree(dev_priv->lvds_bl);
588f910b411SAlan Cox }
589