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