2 * Copyright © 2006 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * Eric Anholt <eric@anholt.net>
31 #include "intel_bios.h"
35 find_section(struct bdb_header
*bdb
, int section_id
)
39 u16 total
, current_size
;
42 /* skip to first section */
43 index
+= bdb
->header_size
;
44 total
= bdb
->bdb_size
;
46 /* walk the sections looking for section_id */
47 while (index
< total
) {
48 current_id
= *(base
+ index
);
50 current_size
= *((u16
*)(base
+ index
));
52 if (current_id
== section_id
)
54 index
+= current_size
;
60 /* Try to find panel data */
62 parse_panel_data(struct drm_i915_private
*dev_priv
, struct bdb_header
*bdb
)
64 struct bdb_lvds_options
*lvds_options
;
65 struct bdb_lvds_lfp_data
*lvds_lfp_data
;
66 struct bdb_lvds_lfp_data_entry
*entry
;
67 struct lvds_dvo_timing
*dvo_timing
;
68 struct drm_display_mode
*panel_fixed_mode
;
70 /* Defaults if we can't find VBT info */
71 dev_priv
->lvds_dither
= 0;
72 dev_priv
->lvds_vbt
= 0;
74 lvds_options
= find_section(bdb
, BDB_LVDS_OPTIONS
);
78 dev_priv
->lvds_dither
= lvds_options
->pixel_dither
;
79 if (lvds_options
->panel_type
== 0xff)
82 lvds_lfp_data
= find_section(bdb
, BDB_LVDS_LFP_DATA
);
86 dev_priv
->lvds_vbt
= 1;
88 entry
= &lvds_lfp_data
->data
[lvds_options
->panel_type
];
89 dvo_timing
= &entry
->dvo_timing
;
91 panel_fixed_mode
= drm_calloc(1, sizeof(*panel_fixed_mode
),
94 panel_fixed_mode
->hdisplay
= (dvo_timing
->hactive_hi
<< 8) |
95 dvo_timing
->hactive_lo
;
96 panel_fixed_mode
->hsync_start
= panel_fixed_mode
->hdisplay
+
97 ((dvo_timing
->hsync_off_hi
<< 8) | dvo_timing
->hsync_off_lo
);
98 panel_fixed_mode
->hsync_end
= panel_fixed_mode
->hsync_start
+
99 dvo_timing
->hsync_pulse_width
;
100 panel_fixed_mode
->htotal
= panel_fixed_mode
->hdisplay
+
101 ((dvo_timing
->hblank_hi
<< 8) | dvo_timing
->hblank_lo
);
103 panel_fixed_mode
->vdisplay
= (dvo_timing
->vactive_hi
<< 8) |
104 dvo_timing
->vactive_lo
;
105 panel_fixed_mode
->vsync_start
= panel_fixed_mode
->vdisplay
+
106 dvo_timing
->vsync_off
;
107 panel_fixed_mode
->vsync_end
= panel_fixed_mode
->vsync_start
+
108 dvo_timing
->vsync_pulse_width
;
109 panel_fixed_mode
->vtotal
= panel_fixed_mode
->vdisplay
+
110 ((dvo_timing
->vblank_hi
<< 8) | dvo_timing
->vblank_lo
);
111 panel_fixed_mode
->clock
= dvo_timing
->clock
* 10;
112 panel_fixed_mode
->type
= DRM_MODE_TYPE_PREFERRED
;
114 /* Some VBTs have bogus h/vtotal values */
115 if (panel_fixed_mode
->hsync_end
> panel_fixed_mode
->htotal
)
116 panel_fixed_mode
->htotal
= panel_fixed_mode
->hsync_end
+ 1;
117 if (panel_fixed_mode
->vsync_end
> panel_fixed_mode
->vtotal
)
118 panel_fixed_mode
->vtotal
= panel_fixed_mode
->vsync_end
+ 1;
120 drm_mode_set_name(panel_fixed_mode
);
122 dev_priv
->vbt_mode
= panel_fixed_mode
;
124 DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
125 drm_mode_debug_printmodeline(panel_fixed_mode
);
131 parse_general_features(struct drm_i915_private
*dev_priv
,
132 struct bdb_header
*bdb
)
134 struct bdb_general_features
*general
;
136 /* Set sensible defaults in case we can't find the general block */
137 dev_priv
->int_tv_support
= 1;
138 dev_priv
->int_crt_support
= 1;
140 general
= find_section(bdb
, BDB_GENERAL_FEATURES
);
142 dev_priv
->int_tv_support
= general
->int_tv_support
;
143 dev_priv
->int_crt_support
= general
->int_crt_support
;
144 dev_priv
->lvds_use_ssc
= general
->enable_ssc
;
146 if (dev_priv
->lvds_use_ssc
) {
147 if (IS_I855(dev_priv
->dev
))
148 dev_priv
->lvds_ssc_freq
= general
->ssc_freq
? 66 : 48;
150 dev_priv
->lvds_ssc_freq
= general
->ssc_freq
? 100 : 96;
156 * intel_init_bios - initialize VBIOS settings & find VBT
159 * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
160 * to appropriate values.
162 * VBT existence is a sanity check that is relied on by other i830_bios.c code.
163 * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
164 * feed an updated VBT back through that, compared to what we'll fetch using
165 * this method of groping around in the BIOS data.
167 * Returns 0 on success, nonzero on failure.
170 intel_init_bios(struct drm_device
*dev
)
172 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
173 struct pci_dev
*pdev
= dev
->pdev
;
174 struct vbt_header
*vbt
= NULL
;
175 struct bdb_header
*bdb
;
180 bios
= pci_map_rom(pdev
, &size
);
184 /* Scour memory looking for the VBT signature */
185 for (i
= 0; i
+ 4 < size
; i
++) {
186 if (!memcmp(bios
+ i
, "$VBT", 4)) {
187 vbt
= (struct vbt_header
*)(bios
+ i
);
193 DRM_ERROR("VBT signature missing\n");
194 pci_unmap_rom(pdev
, bios
);
198 bdb
= (struct bdb_header
*)(bios
+ i
+ vbt
->bdb_offset
);
200 /* Grab useful general definitions */
201 parse_general_features(dev_priv
, bdb
);
202 parse_panel_data(dev_priv
, bdb
);
204 pci_unmap_rom(pdev
, bios
);