Rev 2327 | Rev 2338 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2327 | Rev 2330 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright © 2006 Intel Corporation |
2 | * Copyright © 2006 Intel Corporation |
3 | * |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
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 |
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: |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
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 |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
13 | * Software. |
14 | * |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
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, |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
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 |
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, |
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 |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | * SOFTWARE. |
21 | * SOFTWARE. |
22 | * |
22 | * |
23 | * Authors: |
23 | * Authors: |
24 | * Eric Anholt |
24 | * Eric Anholt |
25 | * |
25 | * |
26 | */ |
26 | */ |
27 | #include |
27 | #include |
28 | #include "drmP.h" |
28 | #include "drmP.h" |
29 | #include "drm.h" |
29 | #include "drm.h" |
30 | //#include "i915_drm.h" |
30 | #include "i915_drm.h" |
31 | #include "i915_drv.h" |
31 | #include "i915_drv.h" |
32 | #include "intel_bios.h" |
32 | #include "intel_bios.h" |
33 | - | ||
34 | #include |
- | |
35 | 33 | ||
36 | #define SLAVE_ADDR1 0x70 |
34 | #define SLAVE_ADDR1 0x70 |
37 | #define SLAVE_ADDR2 0x72 |
35 | #define SLAVE_ADDR2 0x72 |
38 | 36 | ||
39 | static int panel_type; |
37 | static int panel_type; |
40 | 38 | ||
41 | static void * |
39 | static void * |
42 | find_section(struct bdb_header *bdb, int section_id) |
40 | find_section(struct bdb_header *bdb, int section_id) |
43 | { |
41 | { |
44 | u8 *base = (u8 *)bdb; |
42 | u8 *base = (u8 *)bdb; |
45 | int index = 0; |
43 | int index = 0; |
46 | u16 total, current_size; |
44 | u16 total, current_size; |
47 | u8 current_id; |
45 | u8 current_id; |
48 | 46 | ||
49 | /* skip to first section */ |
47 | /* skip to first section */ |
50 | index += bdb->header_size; |
48 | index += bdb->header_size; |
51 | total = bdb->bdb_size; |
49 | total = bdb->bdb_size; |
52 | 50 | ||
53 | /* walk the sections looking for section_id */ |
51 | /* walk the sections looking for section_id */ |
54 | while (index < total) { |
52 | while (index < total) { |
55 | current_id = *(base + index); |
53 | current_id = *(base + index); |
56 | index++; |
54 | index++; |
57 | current_size = *((u16 *)(base + index)); |
55 | current_size = *((u16 *)(base + index)); |
58 | index += 2; |
56 | index += 2; |
59 | if (current_id == section_id) |
57 | if (current_id == section_id) |
60 | return base + index; |
58 | return base + index; |
61 | index += current_size; |
59 | index += current_size; |
62 | } |
60 | } |
63 | 61 | ||
64 | return NULL; |
62 | return NULL; |
65 | } |
63 | } |
66 | 64 | ||
67 | static u16 |
65 | static u16 |
68 | get_blocksize(void *p) |
66 | get_blocksize(void *p) |
69 | { |
67 | { |
70 | u16 *block_ptr, block_size; |
68 | u16 *block_ptr, block_size; |
71 | 69 | ||
72 | block_ptr = (u16 *)((char *)p - 2); |
70 | block_ptr = (u16 *)((char *)p - 2); |
73 | block_size = *block_ptr; |
71 | block_size = *block_ptr; |
74 | return block_size; |
72 | return block_size; |
75 | } |
73 | } |
76 | 74 | ||
77 | static void |
75 | static void |
78 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
76 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
79 | const struct lvds_dvo_timing *dvo_timing) |
77 | const struct lvds_dvo_timing *dvo_timing) |
80 | { |
78 | { |
81 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
79 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
82 | dvo_timing->hactive_lo; |
80 | dvo_timing->hactive_lo; |
83 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
81 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
84 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
82 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
85 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
83 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
86 | dvo_timing->hsync_pulse_width; |
84 | dvo_timing->hsync_pulse_width; |
87 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
85 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
88 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
86 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
89 | 87 | ||
90 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
88 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
91 | dvo_timing->vactive_lo; |
89 | dvo_timing->vactive_lo; |
92 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
90 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
93 | dvo_timing->vsync_off; |
91 | dvo_timing->vsync_off; |
94 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
92 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
95 | dvo_timing->vsync_pulse_width; |
93 | dvo_timing->vsync_pulse_width; |
96 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
94 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
97 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
95 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
98 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
96 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
99 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
97 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
100 | 98 | ||
101 | if (dvo_timing->hsync_positive) |
99 | if (dvo_timing->hsync_positive) |
102 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
100 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
103 | else |
101 | else |
104 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
102 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
105 | 103 | ||
106 | if (dvo_timing->vsync_positive) |
104 | if (dvo_timing->vsync_positive) |
107 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
105 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
108 | else |
106 | else |
109 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
107 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
110 | 108 | ||
111 | /* Some VBTs have bogus h/vtotal values */ |
109 | /* Some VBTs have bogus h/vtotal values */ |
112 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
110 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
113 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
111 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
114 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
112 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
115 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
113 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
116 | 114 | ||
117 | drm_mode_set_name(panel_fixed_mode); |
115 | drm_mode_set_name(panel_fixed_mode); |
118 | } |
116 | } |
119 | 117 | ||
120 | static bool |
118 | static bool |
121 | lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, |
119 | lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, |
122 | const struct lvds_dvo_timing *b) |
120 | const struct lvds_dvo_timing *b) |
123 | { |
121 | { |
124 | if (a->hactive_hi != b->hactive_hi || |
122 | if (a->hactive_hi != b->hactive_hi || |
125 | a->hactive_lo != b->hactive_lo) |
123 | a->hactive_lo != b->hactive_lo) |
126 | return false; |
124 | return false; |
127 | 125 | ||
128 | if (a->hsync_off_hi != b->hsync_off_hi || |
126 | if (a->hsync_off_hi != b->hsync_off_hi || |
129 | a->hsync_off_lo != b->hsync_off_lo) |
127 | a->hsync_off_lo != b->hsync_off_lo) |
130 | return false; |
128 | return false; |
131 | 129 | ||
132 | if (a->hsync_pulse_width != b->hsync_pulse_width) |
130 | if (a->hsync_pulse_width != b->hsync_pulse_width) |
133 | return false; |
131 | return false; |
134 | 132 | ||
135 | if (a->hblank_hi != b->hblank_hi || |
133 | if (a->hblank_hi != b->hblank_hi || |
136 | a->hblank_lo != b->hblank_lo) |
134 | a->hblank_lo != b->hblank_lo) |
137 | return false; |
135 | return false; |
138 | 136 | ||
139 | if (a->vactive_hi != b->vactive_hi || |
137 | if (a->vactive_hi != b->vactive_hi || |
140 | a->vactive_lo != b->vactive_lo) |
138 | a->vactive_lo != b->vactive_lo) |
141 | return false; |
139 | return false; |
142 | 140 | ||
143 | if (a->vsync_off != b->vsync_off) |
141 | if (a->vsync_off != b->vsync_off) |
144 | return false; |
142 | return false; |
145 | 143 | ||
146 | if (a->vsync_pulse_width != b->vsync_pulse_width) |
144 | if (a->vsync_pulse_width != b->vsync_pulse_width) |
147 | return false; |
145 | return false; |
148 | 146 | ||
149 | if (a->vblank_hi != b->vblank_hi || |
147 | if (a->vblank_hi != b->vblank_hi || |
150 | a->vblank_lo != b->vblank_lo) |
148 | a->vblank_lo != b->vblank_lo) |
151 | return false; |
149 | return false; |
152 | 150 | ||
153 | return true; |
151 | return true; |
154 | } |
152 | } |
155 | 153 | ||
156 | static const struct lvds_dvo_timing * |
154 | static const struct lvds_dvo_timing * |
157 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
155 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
158 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
156 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
159 | int index) |
157 | int index) |
160 | { |
158 | { |
161 | /* |
159 | /* |
162 | * the size of fp_timing varies on the different platform. |
160 | * the size of fp_timing varies on the different platform. |
163 | * So calculate the DVO timing relative offset in LVDS data |
161 | * So calculate the DVO timing relative offset in LVDS data |
164 | * entry to get the DVO timing entry |
162 | * entry to get the DVO timing entry |
165 | */ |
163 | */ |
166 | 164 | ||
167 | int lfp_data_size = |
165 | int lfp_data_size = |
168 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
166 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
169 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
167 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
170 | int dvo_timing_offset = |
168 | int dvo_timing_offset = |
171 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
169 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
172 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
170 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
173 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
171 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
174 | 172 | ||
175 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
173 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
176 | } |
174 | } |
177 | 175 | ||
178 | /* Try to find integrated panel data */ |
176 | /* Try to find integrated panel data */ |
179 | static void |
177 | static void |
180 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
178 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
181 | struct bdb_header *bdb) |
179 | struct bdb_header *bdb) |
182 | { |
180 | { |
183 | const struct bdb_lvds_options *lvds_options; |
181 | const struct bdb_lvds_options *lvds_options; |
184 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
182 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
185 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
183 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
186 | const struct lvds_dvo_timing *panel_dvo_timing; |
184 | const struct lvds_dvo_timing *panel_dvo_timing; |
187 | struct drm_display_mode *panel_fixed_mode; |
185 | struct drm_display_mode *panel_fixed_mode; |
188 | int i, downclock; |
186 | int i, downclock; |
189 | 187 | ||
190 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
188 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
191 | if (!lvds_options) |
189 | if (!lvds_options) |
192 | return; |
190 | return; |
193 | 191 | ||
194 | dev_priv->lvds_dither = lvds_options->pixel_dither; |
192 | dev_priv->lvds_dither = lvds_options->pixel_dither; |
195 | if (lvds_options->panel_type == 0xff) |
193 | if (lvds_options->panel_type == 0xff) |
196 | return; |
194 | return; |
197 | 195 | ||
198 | panel_type = lvds_options->panel_type; |
196 | panel_type = lvds_options->panel_type; |
199 | 197 | ||
200 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
198 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
201 | if (!lvds_lfp_data) |
199 | if (!lvds_lfp_data) |
202 | return; |
200 | return; |
203 | 201 | ||
204 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
202 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
205 | if (!lvds_lfp_data_ptrs) |
203 | if (!lvds_lfp_data_ptrs) |
206 | return; |
204 | return; |
207 | 205 | ||
208 | dev_priv->lvds_vbt = 1; |
206 | dev_priv->lvds_vbt = 1; |
209 | 207 | ||
210 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
208 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
211 | lvds_lfp_data_ptrs, |
209 | lvds_lfp_data_ptrs, |
212 | lvds_options->panel_type); |
210 | lvds_options->panel_type); |
213 | 211 | ||
214 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
212 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
215 | if (!panel_fixed_mode) |
213 | if (!panel_fixed_mode) |
216 | return; |
214 | return; |
217 | 215 | ||
218 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
216 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
219 | 217 | ||
220 | dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; |
218 | dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; |
221 | 219 | ||
222 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
220 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
223 | drm_mode_debug_printmodeline(panel_fixed_mode); |
221 | drm_mode_debug_printmodeline(panel_fixed_mode); |
224 | 222 | ||
225 | /* |
223 | /* |
226 | * Iterate over the LVDS panel timing info to find the lowest clock |
224 | * Iterate over the LVDS panel timing info to find the lowest clock |
227 | * for the native resolution. |
225 | * for the native resolution. |
228 | */ |
226 | */ |
229 | downclock = panel_dvo_timing->clock; |
227 | downclock = panel_dvo_timing->clock; |
230 | for (i = 0; i < 16; i++) { |
228 | for (i = 0; i < 16; i++) { |
231 | const struct lvds_dvo_timing *dvo_timing; |
229 | const struct lvds_dvo_timing *dvo_timing; |
232 | 230 | ||
233 | dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
231 | dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
234 | lvds_lfp_data_ptrs, |
232 | lvds_lfp_data_ptrs, |
235 | i); |
233 | i); |
236 | if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && |
234 | if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && |
237 | dvo_timing->clock < downclock) |
235 | dvo_timing->clock < downclock) |
238 | downclock = dvo_timing->clock; |
236 | downclock = dvo_timing->clock; |
239 | } |
237 | } |
240 | 238 | ||
241 | if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) { |
239 | if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) { |
242 | dev_priv->lvds_downclock_avail = 1; |
240 | dev_priv->lvds_downclock_avail = 1; |
243 | dev_priv->lvds_downclock = downclock * 10; |
241 | dev_priv->lvds_downclock = downclock * 10; |
244 | DRM_DEBUG_KMS("LVDS downclock is found in VBT. " |
242 | DRM_DEBUG_KMS("LVDS downclock is found in VBT. " |
245 | "Normal Clock %dKHz, downclock %dKHz\n", |
243 | "Normal Clock %dKHz, downclock %dKHz\n", |
246 | panel_fixed_mode->clock, 10*downclock); |
244 | panel_fixed_mode->clock, 10*downclock); |
247 | } |
245 | } |
248 | } |
246 | } |
249 | 247 | ||
250 | /* Try to find sdvo panel data */ |
248 | /* Try to find sdvo panel data */ |
251 | static void |
249 | static void |
252 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
250 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
253 | struct bdb_header *bdb) |
251 | struct bdb_header *bdb) |
254 | { |
252 | { |
255 | struct lvds_dvo_timing *dvo_timing; |
253 | struct lvds_dvo_timing *dvo_timing; |
256 | struct drm_display_mode *panel_fixed_mode; |
254 | struct drm_display_mode *panel_fixed_mode; |
257 | int index; |
255 | int index; |
258 | 256 | ||
259 | index = i915_vbt_sdvo_panel_type; |
257 | index = i915_vbt_sdvo_panel_type; |
260 | if (index == -1) { |
258 | if (index == -1) { |
261 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
259 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
262 | 260 | ||
263 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
261 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
264 | if (!sdvo_lvds_options) |
262 | if (!sdvo_lvds_options) |
265 | return; |
263 | return; |
266 | 264 | ||
267 | index = sdvo_lvds_options->panel_type; |
265 | index = sdvo_lvds_options->panel_type; |
268 | } |
266 | } |
269 | 267 | ||
270 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
268 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
271 | if (!dvo_timing) |
269 | if (!dvo_timing) |
272 | return; |
270 | return; |
273 | 271 | ||
274 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
272 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
275 | if (!panel_fixed_mode) |
273 | if (!panel_fixed_mode) |
276 | return; |
274 | return; |
277 | 275 | ||
278 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
276 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
279 | 277 | ||
280 | dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; |
278 | dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; |
281 | 279 | ||
282 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
280 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
283 | drm_mode_debug_printmodeline(panel_fixed_mode); |
281 | drm_mode_debug_printmodeline(panel_fixed_mode); |
284 | } |
282 | } |
285 | 283 | ||
286 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
284 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
287 | bool alternate) |
285 | bool alternate) |
288 | { |
286 | { |
289 | switch (INTEL_INFO(dev)->gen) { |
287 | switch (INTEL_INFO(dev)->gen) { |
290 | case 2: |
288 | case 2: |
291 | return alternate ? 66 : 48; |
289 | return alternate ? 66 : 48; |
292 | case 3: |
290 | case 3: |
293 | case 4: |
291 | case 4: |
294 | return alternate ? 100 : 96; |
292 | return alternate ? 100 : 96; |
295 | default: |
293 | default: |
296 | return alternate ? 100 : 120; |
294 | return alternate ? 100 : 120; |
297 | } |
295 | } |
298 | } |
296 | } |
299 | 297 | ||
300 | static void |
298 | static void |
301 | parse_general_features(struct drm_i915_private *dev_priv, |
299 | parse_general_features(struct drm_i915_private *dev_priv, |
302 | struct bdb_header *bdb) |
300 | struct bdb_header *bdb) |
303 | { |
301 | { |
304 | struct drm_device *dev = dev_priv->dev; |
302 | struct drm_device *dev = dev_priv->dev; |
305 | struct bdb_general_features *general; |
303 | struct bdb_general_features *general; |
306 | 304 | ||
307 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
305 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
308 | if (general) { |
306 | if (general) { |
309 | dev_priv->int_tv_support = general->int_tv_support; |
307 | dev_priv->int_tv_support = general->int_tv_support; |
310 | dev_priv->int_crt_support = general->int_crt_support; |
308 | dev_priv->int_crt_support = general->int_crt_support; |
311 | dev_priv->lvds_use_ssc = general->enable_ssc; |
309 | dev_priv->lvds_use_ssc = general->enable_ssc; |
312 | dev_priv->lvds_ssc_freq = |
310 | dev_priv->lvds_ssc_freq = |
313 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
311 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
314 | } |
312 | } |
315 | } |
313 | } |
316 | 314 | ||
317 | static void |
315 | static void |
318 | parse_general_definitions(struct drm_i915_private *dev_priv, |
316 | parse_general_definitions(struct drm_i915_private *dev_priv, |
319 | struct bdb_header *bdb) |
317 | struct bdb_header *bdb) |
320 | { |
318 | { |
321 | struct bdb_general_definitions *general; |
319 | struct bdb_general_definitions *general; |
322 | 320 | ||
323 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
321 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
324 | if (general) { |
322 | if (general) { |
325 | u16 block_size = get_blocksize(general); |
323 | u16 block_size = get_blocksize(general); |
326 | if (block_size >= sizeof(*general)) { |
324 | if (block_size >= sizeof(*general)) { |
327 | int bus_pin = general->crt_ddc_gmbus_pin; |
325 | int bus_pin = general->crt_ddc_gmbus_pin; |
328 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
326 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
329 | if (bus_pin >= 1 && bus_pin <= 6) |
327 | if (bus_pin >= 1 && bus_pin <= 6) |
330 | dev_priv->crt_ddc_pin = bus_pin; |
328 | dev_priv->crt_ddc_pin = bus_pin; |
331 | } else { |
329 | } else { |
332 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
330 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
333 | block_size); |
331 | block_size); |
334 | } |
332 | } |
335 | } |
333 | } |
336 | } |
334 | } |
337 | 335 | ||
338 | static void |
336 | static void |
339 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
337 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
340 | struct bdb_header *bdb) |
338 | struct bdb_header *bdb) |
341 | { |
339 | { |
342 | struct sdvo_device_mapping *p_mapping; |
340 | struct sdvo_device_mapping *p_mapping; |
343 | struct bdb_general_definitions *p_defs; |
341 | struct bdb_general_definitions *p_defs; |
344 | struct child_device_config *p_child; |
342 | struct child_device_config *p_child; |
345 | int i, child_device_num, count; |
343 | int i, child_device_num, count; |
346 | u16 block_size; |
344 | u16 block_size; |
347 | 345 | ||
348 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
346 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
349 | if (!p_defs) { |
347 | if (!p_defs) { |
350 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
348 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
351 | return; |
349 | return; |
352 | } |
350 | } |
353 | /* judge whether the size of child device meets the requirements. |
351 | /* judge whether the size of child device meets the requirements. |
354 | * If the child device size obtained from general definition block |
352 | * If the child device size obtained from general definition block |
355 | * is different with sizeof(struct child_device_config), skip the |
353 | * is different with sizeof(struct child_device_config), skip the |
356 | * parsing of sdvo device info |
354 | * parsing of sdvo device info |
357 | */ |
355 | */ |
358 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
356 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
359 | /* different child dev size . Ignore it */ |
357 | /* different child dev size . Ignore it */ |
360 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
358 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
361 | return; |
359 | return; |
362 | } |
360 | } |
363 | /* get the block size of general definitions */ |
361 | /* get the block size of general definitions */ |
364 | block_size = get_blocksize(p_defs); |
362 | block_size = get_blocksize(p_defs); |
365 | /* get the number of child device */ |
363 | /* get the number of child device */ |
366 | child_device_num = (block_size - sizeof(*p_defs)) / |
364 | child_device_num = (block_size - sizeof(*p_defs)) / |
367 | sizeof(*p_child); |
365 | sizeof(*p_child); |
368 | count = 0; |
366 | count = 0; |
369 | for (i = 0; i < child_device_num; i++) { |
367 | for (i = 0; i < child_device_num; i++) { |
370 | p_child = &(p_defs->devices[i]); |
368 | p_child = &(p_defs->devices[i]); |
371 | if (!p_child->device_type) { |
369 | if (!p_child->device_type) { |
372 | /* skip the device block if device type is invalid */ |
370 | /* skip the device block if device type is invalid */ |
373 | continue; |
371 | continue; |
374 | } |
372 | } |
375 | if (p_child->slave_addr != SLAVE_ADDR1 && |
373 | if (p_child->slave_addr != SLAVE_ADDR1 && |
376 | p_child->slave_addr != SLAVE_ADDR2) { |
374 | p_child->slave_addr != SLAVE_ADDR2) { |
377 | /* |
375 | /* |
378 | * If the slave address is neither 0x70 nor 0x72, |
376 | * If the slave address is neither 0x70 nor 0x72, |
379 | * it is not a SDVO device. Skip it. |
377 | * it is not a SDVO device. Skip it. |
380 | */ |
378 | */ |
381 | continue; |
379 | continue; |
382 | } |
380 | } |
383 | if (p_child->dvo_port != DEVICE_PORT_DVOB && |
381 | if (p_child->dvo_port != DEVICE_PORT_DVOB && |
384 | p_child->dvo_port != DEVICE_PORT_DVOC) { |
382 | p_child->dvo_port != DEVICE_PORT_DVOC) { |
385 | /* skip the incorrect SDVO port */ |
383 | /* skip the incorrect SDVO port */ |
386 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it \n"); |
384 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it \n"); |
387 | continue; |
385 | continue; |
388 | } |
386 | } |
389 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
387 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
390 | " %s port\n", |
388 | " %s port\n", |
391 | p_child->slave_addr, |
389 | p_child->slave_addr, |
392 | (p_child->dvo_port == DEVICE_PORT_DVOB) ? |
390 | (p_child->dvo_port == DEVICE_PORT_DVOB) ? |
393 | "SDVOB" : "SDVOC"); |
391 | "SDVOB" : "SDVOC"); |
394 | p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); |
392 | p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); |
395 | if (!p_mapping->initialized) { |
393 | if (!p_mapping->initialized) { |
396 | p_mapping->dvo_port = p_child->dvo_port; |
394 | p_mapping->dvo_port = p_child->dvo_port; |
397 | p_mapping->slave_addr = p_child->slave_addr; |
395 | p_mapping->slave_addr = p_child->slave_addr; |
398 | p_mapping->dvo_wiring = p_child->dvo_wiring; |
396 | p_mapping->dvo_wiring = p_child->dvo_wiring; |
399 | p_mapping->ddc_pin = p_child->ddc_pin; |
397 | p_mapping->ddc_pin = p_child->ddc_pin; |
400 | p_mapping->i2c_pin = p_child->i2c_pin; |
398 | p_mapping->i2c_pin = p_child->i2c_pin; |
401 | p_mapping->i2c_speed = p_child->i2c_speed; |
399 | p_mapping->i2c_speed = p_child->i2c_speed; |
402 | p_mapping->initialized = 1; |
400 | p_mapping->initialized = 1; |
403 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n", |
401 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n", |
404 | p_mapping->dvo_port, |
402 | p_mapping->dvo_port, |
405 | p_mapping->slave_addr, |
403 | p_mapping->slave_addr, |
406 | p_mapping->dvo_wiring, |
404 | p_mapping->dvo_wiring, |
407 | p_mapping->ddc_pin, |
405 | p_mapping->ddc_pin, |
408 | p_mapping->i2c_pin, |
406 | p_mapping->i2c_pin, |
409 | p_mapping->i2c_speed); |
407 | p_mapping->i2c_speed); |
410 | } else { |
408 | } else { |
411 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
409 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
412 | "two SDVO device.\n"); |
410 | "two SDVO device.\n"); |
413 | } |
411 | } |
414 | if (p_child->slave2_addr) { |
412 | if (p_child->slave2_addr) { |
415 | /* Maybe this is a SDVO device with multiple inputs */ |
413 | /* Maybe this is a SDVO device with multiple inputs */ |
416 | /* And the mapping info is not added */ |
414 | /* And the mapping info is not added */ |
417 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
415 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
418 | " is a SDVO device with multiple inputs.\n"); |
416 | " is a SDVO device with multiple inputs.\n"); |
419 | } |
417 | } |
420 | count++; |
418 | count++; |
421 | } |
419 | } |
422 | 420 | ||
423 | if (!count) { |
421 | if (!count) { |
424 | /* No SDVO device info is found */ |
422 | /* No SDVO device info is found */ |
425 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
423 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
426 | } |
424 | } |
427 | return; |
425 | return; |
428 | } |
426 | } |
429 | 427 | ||
430 | static void |
428 | static void |
431 | parse_driver_features(struct drm_i915_private *dev_priv, |
429 | parse_driver_features(struct drm_i915_private *dev_priv, |
432 | struct bdb_header *bdb) |
430 | struct bdb_header *bdb) |
433 | { |
431 | { |
434 | struct drm_device *dev = dev_priv->dev; |
432 | struct drm_device *dev = dev_priv->dev; |
435 | struct bdb_driver_features *driver; |
433 | struct bdb_driver_features *driver; |
436 | 434 | ||
437 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
435 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
438 | if (!driver) |
436 | if (!driver) |
439 | return; |
437 | return; |
440 | 438 | ||
441 | if (SUPPORTS_EDP(dev) && |
439 | if (SUPPORTS_EDP(dev) && |
442 | driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
440 | driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
443 | dev_priv->edp.support = 1; |
441 | dev_priv->edp.support = 1; |
444 | 442 | ||
445 | if (driver->dual_frequency) |
443 | if (driver->dual_frequency) |
446 | dev_priv->render_reclock_avail = true; |
444 | dev_priv->render_reclock_avail = true; |
447 | } |
445 | } |
448 | 446 | ||
449 | static void |
447 | static void |
450 | parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
448 | parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
451 | { |
449 | { |
452 | struct bdb_edp *edp; |
450 | struct bdb_edp *edp; |
453 | struct edp_power_seq *edp_pps; |
451 | struct edp_power_seq *edp_pps; |
454 | struct edp_link_params *edp_link_params; |
452 | struct edp_link_params *edp_link_params; |
455 | 453 | ||
456 | edp = find_section(bdb, BDB_EDP); |
454 | edp = find_section(bdb, BDB_EDP); |
457 | if (!edp) { |
455 | if (!edp) { |
458 | if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { |
456 | if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { |
459 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel " |
457 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel " |
460 | "supported, assume %dbpp panel color " |
458 | "supported, assume %dbpp panel color " |
461 | "depth.\n", |
459 | "depth.\n", |
462 | dev_priv->edp.bpp); |
460 | dev_priv->edp.bpp); |
463 | } |
461 | } |
464 | return; |
462 | return; |
465 | } |
463 | } |
466 | 464 | ||
467 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
465 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
468 | case EDP_18BPP: |
466 | case EDP_18BPP: |
469 | dev_priv->edp.bpp = 18; |
467 | dev_priv->edp.bpp = 18; |
470 | break; |
468 | break; |
471 | case EDP_24BPP: |
469 | case EDP_24BPP: |
472 | dev_priv->edp.bpp = 24; |
470 | dev_priv->edp.bpp = 24; |
473 | break; |
471 | break; |
474 | case EDP_30BPP: |
472 | case EDP_30BPP: |
475 | dev_priv->edp.bpp = 30; |
473 | dev_priv->edp.bpp = 30; |
476 | break; |
474 | break; |
477 | } |
475 | } |
478 | 476 | ||
479 | /* Get the eDP sequencing and link info */ |
477 | /* Get the eDP sequencing and link info */ |
480 | edp_pps = &edp->power_seqs[panel_type]; |
478 | edp_pps = &edp->power_seqs[panel_type]; |
481 | edp_link_params = &edp->link_params[panel_type]; |
479 | edp_link_params = &edp->link_params[panel_type]; |
482 | 480 | ||
483 | dev_priv->edp.pps = *edp_pps; |
481 | dev_priv->edp.pps = *edp_pps; |
484 | 482 | ||
485 | dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 : |
483 | dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 : |
486 | DP_LINK_BW_1_62; |
484 | DP_LINK_BW_1_62; |
487 | switch (edp_link_params->lanes) { |
485 | switch (edp_link_params->lanes) { |
488 | case 0: |
486 | case 0: |
489 | dev_priv->edp.lanes = 1; |
487 | dev_priv->edp.lanes = 1; |
490 | break; |
488 | break; |
491 | case 1: |
489 | case 1: |
492 | dev_priv->edp.lanes = 2; |
490 | dev_priv->edp.lanes = 2; |
493 | break; |
491 | break; |
494 | case 3: |
492 | case 3: |
495 | default: |
493 | default: |
496 | dev_priv->edp.lanes = 4; |
494 | dev_priv->edp.lanes = 4; |
497 | break; |
495 | break; |
498 | } |
496 | } |
499 | switch (edp_link_params->preemphasis) { |
497 | switch (edp_link_params->preemphasis) { |
500 | case 0: |
498 | case 0: |
501 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0; |
499 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0; |
502 | break; |
500 | break; |
503 | case 1: |
501 | case 1: |
504 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; |
502 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; |
505 | break; |
503 | break; |
506 | case 2: |
504 | case 2: |
507 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6; |
505 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6; |
508 | break; |
506 | break; |
509 | case 3: |
507 | case 3: |
510 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; |
508 | dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; |
511 | break; |
509 | break; |
512 | } |
510 | } |
513 | switch (edp_link_params->vswing) { |
511 | switch (edp_link_params->vswing) { |
514 | case 0: |
512 | case 0: |
515 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400; |
513 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400; |
516 | break; |
514 | break; |
517 | case 1: |
515 | case 1: |
518 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600; |
516 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600; |
519 | break; |
517 | break; |
520 | case 2: |
518 | case 2: |
521 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800; |
519 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800; |
522 | break; |
520 | break; |
523 | case 3: |
521 | case 3: |
524 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200; |
522 | dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200; |
525 | break; |
523 | break; |
526 | } |
524 | } |
527 | } |
525 | } |
528 | 526 | ||
529 | static void |
527 | static void |
530 | parse_device_mapping(struct drm_i915_private *dev_priv, |
528 | parse_device_mapping(struct drm_i915_private *dev_priv, |
531 | struct bdb_header *bdb) |
529 | struct bdb_header *bdb) |
532 | { |
530 | { |
533 | struct bdb_general_definitions *p_defs; |
531 | struct bdb_general_definitions *p_defs; |
534 | struct child_device_config *p_child, *child_dev_ptr; |
532 | struct child_device_config *p_child, *child_dev_ptr; |
535 | int i, child_device_num, count; |
533 | int i, child_device_num, count; |
536 | u16 block_size; |
534 | u16 block_size; |
537 | 535 | ||
538 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
536 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
539 | if (!p_defs) { |
537 | if (!p_defs) { |
540 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
538 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
541 | return; |
539 | return; |
542 | } |
540 | } |
543 | /* judge whether the size of child device meets the requirements. |
541 | /* judge whether the size of child device meets the requirements. |
544 | * If the child device size obtained from general definition block |
542 | * If the child device size obtained from general definition block |
545 | * is different with sizeof(struct child_device_config), skip the |
543 | * is different with sizeof(struct child_device_config), skip the |
546 | * parsing of sdvo device info |
544 | * parsing of sdvo device info |
547 | */ |
545 | */ |
548 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
546 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
549 | /* different child dev size . Ignore it */ |
547 | /* different child dev size . Ignore it */ |
550 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
548 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
551 | return; |
549 | return; |
552 | } |
550 | } |
553 | /* get the block size of general definitions */ |
551 | /* get the block size of general definitions */ |
554 | block_size = get_blocksize(p_defs); |
552 | block_size = get_blocksize(p_defs); |
555 | /* get the number of child device */ |
553 | /* get the number of child device */ |
556 | child_device_num = (block_size - sizeof(*p_defs)) / |
554 | child_device_num = (block_size - sizeof(*p_defs)) / |
557 | sizeof(*p_child); |
555 | sizeof(*p_child); |
558 | count = 0; |
556 | count = 0; |
559 | /* get the number of child device that is present */ |
557 | /* get the number of child device that is present */ |
560 | for (i = 0; i < child_device_num; i++) { |
558 | for (i = 0; i < child_device_num; i++) { |
561 | p_child = &(p_defs->devices[i]); |
559 | p_child = &(p_defs->devices[i]); |
562 | if (!p_child->device_type) { |
560 | if (!p_child->device_type) { |
563 | /* skip the device block if device type is invalid */ |
561 | /* skip the device block if device type is invalid */ |
564 | continue; |
562 | continue; |
565 | } |
563 | } |
566 | count++; |
564 | count++; |
567 | } |
565 | } |
568 | if (!count) { |
566 | if (!count) { |
569 | DRM_DEBUG_KMS("no child dev is parsed from VBT \n"); |
567 | DRM_DEBUG_KMS("no child dev is parsed from VBT \n"); |
570 | return; |
568 | return; |
571 | } |
569 | } |
572 | dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL); |
570 | dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL); |
573 | if (!dev_priv->child_dev) { |
571 | if (!dev_priv->child_dev) { |
574 | DRM_DEBUG_KMS("No memory space for child device\n"); |
572 | DRM_DEBUG_KMS("No memory space for child device\n"); |
575 | return; |
573 | return; |
576 | } |
574 | } |
577 | 575 | ||
578 | dev_priv->child_dev_num = count; |
576 | dev_priv->child_dev_num = count; |
579 | count = 0; |
577 | count = 0; |
580 | for (i = 0; i < child_device_num; i++) { |
578 | for (i = 0; i < child_device_num; i++) { |
581 | p_child = &(p_defs->devices[i]); |
579 | p_child = &(p_defs->devices[i]); |
582 | if (!p_child->device_type) { |
580 | if (!p_child->device_type) { |
583 | /* skip the device block if device type is invalid */ |
581 | /* skip the device block if device type is invalid */ |
584 | continue; |
582 | continue; |
585 | } |
583 | } |
586 | child_dev_ptr = dev_priv->child_dev + count; |
584 | child_dev_ptr = dev_priv->child_dev + count; |
587 | count++; |
585 | count++; |
588 | memcpy((void *)child_dev_ptr, (void *)p_child, |
586 | memcpy((void *)child_dev_ptr, (void *)p_child, |
589 | sizeof(*p_child)); |
587 | sizeof(*p_child)); |
590 | } |
588 | } |
591 | return; |
589 | return; |
592 | } |
590 | } |
593 | 591 | ||
594 | static void |
592 | static void |
595 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
593 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
596 | { |
594 | { |
597 | struct drm_device *dev = dev_priv->dev; |
595 | struct drm_device *dev = dev_priv->dev; |
598 | 596 | ||
599 | dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; |
597 | dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; |
600 | 598 | ||
601 | /* LFP panel data */ |
599 | /* LFP panel data */ |
602 | dev_priv->lvds_dither = 1; |
600 | dev_priv->lvds_dither = 1; |
603 | dev_priv->lvds_vbt = 0; |
601 | dev_priv->lvds_vbt = 0; |
604 | 602 | ||
605 | /* SDVO panel data */ |
603 | /* SDVO panel data */ |
606 | dev_priv->sdvo_lvds_vbt_mode = NULL; |
604 | dev_priv->sdvo_lvds_vbt_mode = NULL; |
607 | 605 | ||
608 | /* general features */ |
606 | /* general features */ |
609 | dev_priv->int_tv_support = 1; |
607 | dev_priv->int_tv_support = 1; |
610 | dev_priv->int_crt_support = 1; |
608 | dev_priv->int_crt_support = 1; |
611 | 609 | ||
612 | /* Default to using SSC */ |
610 | /* Default to using SSC */ |
613 | dev_priv->lvds_use_ssc = 1; |
611 | dev_priv->lvds_use_ssc = 1; |
614 | dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); |
612 | dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); |
615 | DRM_DEBUG("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); |
613 | DRM_DEBUG("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); |
616 | 614 | ||
617 | /* eDP data */ |
615 | /* eDP data */ |
618 | dev_priv->edp.bpp = 18; |
616 | dev_priv->edp.bpp = 18; |
619 | } |
617 | } |
620 | 618 | ||
621 | /** |
619 | /** |
622 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
620 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
623 | * @dev: DRM device |
621 | * @dev: DRM device |
624 | * |
622 | * |
625 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
623 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
626 | * to appropriate values. |
624 | * to appropriate values. |
627 | * |
625 | * |
628 | * Returns 0 on success, nonzero on failure. |
626 | * Returns 0 on success, nonzero on failure. |
629 | */ |
627 | */ |
630 | bool |
628 | bool |
631 | intel_parse_bios(struct drm_device *dev) |
629 | intel_parse_bios(struct drm_device *dev) |
632 | { |
630 | { |
633 | struct drm_i915_private *dev_priv = dev->dev_private; |
631 | struct drm_i915_private *dev_priv = dev->dev_private; |
634 | struct pci_dev *pdev = dev->pdev; |
632 | struct pci_dev *pdev = dev->pdev; |
635 | struct bdb_header *bdb = NULL; |
633 | struct bdb_header *bdb = NULL; |
636 | u8 __iomem *bios = NULL; |
634 | u8 __iomem *bios = NULL; |
637 | 635 | ||
638 | ENTER(); |
636 | ENTER(); |
639 | 637 | ||
640 | init_vbt_defaults(dev_priv); |
638 | init_vbt_defaults(dev_priv); |
641 | 639 | ||
642 | /* XXX Should this validation be moved to intel_opregion.c? */ |
640 | /* XXX Should this validation be moved to intel_opregion.c? */ |
643 | if (dev_priv->opregion.vbt) { |
641 | if (dev_priv->opregion.vbt) { |
644 | struct vbt_header *vbt = dev_priv->opregion.vbt; |
642 | struct vbt_header *vbt = dev_priv->opregion.vbt; |
645 | if (memcmp(vbt->signature, "$VBT", 4) == 0) { |
643 | if (memcmp(vbt->signature, "$VBT", 4) == 0) { |
646 | DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n", |
644 | DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n", |
647 | vbt->signature); |
645 | vbt->signature); |
648 | bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); |
646 | bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); |
649 | } else |
647 | } else |
650 | dev_priv->opregion.vbt = NULL; |
648 | dev_priv->opregion.vbt = NULL; |
651 | } |
649 | } |
652 | 650 | ||
653 | if (bdb == NULL) { |
651 | if (bdb == NULL) { |
654 | struct vbt_header *vbt = NULL; |
652 | struct vbt_header *vbt = NULL; |
655 | size_t size; |
653 | size_t size; |
656 | int i; |
654 | int i; |
657 | 655 | ||
658 | bios = pci_map_rom(pdev, &size); |
656 | bios = pci_map_rom(pdev, &size); |
659 | if (!bios) |
657 | if (!bios) |
660 | return -1; |
658 | return -1; |
661 | 659 | ||
662 | /* Scour memory looking for the VBT signature */ |
660 | /* Scour memory looking for the VBT signature */ |
663 | for (i = 0; i + 4 < size; i++) { |
661 | for (i = 0; i + 4 < size; i++) { |
664 | if (!memcmp(bios + i, "$VBT", 4)) { |
662 | if (!memcmp(bios + i, "$VBT", 4)) { |
665 | vbt = (struct vbt_header *)(bios + i); |
663 | vbt = (struct vbt_header *)(bios + i); |
666 | break; |
664 | break; |
667 | } |
665 | } |
668 | } |
666 | } |
669 | 667 | ||
670 | if (!vbt) { |
668 | if (!vbt) { |
671 | DRM_ERROR("VBT signature missing\n"); |
669 | DRM_ERROR("VBT signature missing\n"); |
672 | pci_unmap_rom(pdev, bios); |
670 | pci_unmap_rom(pdev, bios); |
673 | return -1; |
671 | return -1; |
674 | } |
672 | } |
675 | 673 | ||
676 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); |
674 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); |
677 | } |
675 | } |
678 | 676 | ||
679 | /* Grab useful general definitions */ |
677 | /* Grab useful general definitions */ |
680 | parse_general_features(dev_priv, bdb); |
678 | parse_general_features(dev_priv, bdb); |
681 | parse_general_definitions(dev_priv, bdb); |
679 | parse_general_definitions(dev_priv, bdb); |
682 | parse_lfp_panel_data(dev_priv, bdb); |
680 | parse_lfp_panel_data(dev_priv, bdb); |
683 | parse_sdvo_panel_data(dev_priv, bdb); |
681 | parse_sdvo_panel_data(dev_priv, bdb); |
684 | parse_sdvo_device_mapping(dev_priv, bdb); |
682 | parse_sdvo_device_mapping(dev_priv, bdb); |
685 | parse_device_mapping(dev_priv, bdb); |
683 | parse_device_mapping(dev_priv, bdb); |
686 | parse_driver_features(dev_priv, bdb); |
684 | parse_driver_features(dev_priv, bdb); |
687 | parse_edp(dev_priv, bdb); |
685 | parse_edp(dev_priv, bdb); |
688 | 686 | ||
689 | if (bios) |
687 | if (bios) |
690 | pci_unmap_rom(pdev, bios); |
688 | pci_unmap_rom(pdev, bios); |
691 | 689 | ||
692 | LEAVE(); |
690 | LEAVE(); |
693 | 691 | ||
694 | return 0; |
692 | return 0; |
695 | } |
693 | } |
696 | 694 | ||
697 | /* Ensure that vital registers have been initialised, even if the BIOS |
695 | /* Ensure that vital registers have been initialised, even if the BIOS |
698 | * is absent or just failing to do its job. |
696 | * is absent or just failing to do its job. |
699 | */ |
697 | */ |
700 | void intel_setup_bios(struct drm_device *dev) |
698 | void intel_setup_bios(struct drm_device *dev) |
701 | { |
699 | { |
702 | struct drm_i915_private *dev_priv = dev->dev_private; |
700 | struct drm_i915_private *dev_priv = dev->dev_private; |
703 | 701 | ||
704 | /* Set the Panel Power On/Off timings if uninitialized. */ |
702 | /* Set the Panel Power On/Off timings if uninitialized. */ |
705 | if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) { |
703 | if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) { |
706 | /* Set T2 to 40ms and T5 to 200ms */ |
704 | /* Set T2 to 40ms and T5 to 200ms */ |
707 | I915_WRITE(PP_ON_DELAYS, 0x019007d0); |
705 | I915_WRITE(PP_ON_DELAYS, 0x019007d0); |
708 | 706 | ||
709 | /* Set T3 to 35ms and Tx to 200ms */ |
707 | /* Set T3 to 35ms and Tx to 200ms */ |
710 | I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); |
708 | I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); |
711 | } |
709 | } |
712 | }>>>>=>>>>><>><>><>><>><>> |
710 | }>>>>=>>>>><>><>><>><>><>> |