Rev 5097 | Rev 6084 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5097 | Rev 5354 | ||
---|---|---|---|
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 |
30 | #include |
31 | #include "i915_drv.h" |
31 | #include "i915_drv.h" |
32 | #include "intel_bios.h" |
32 | #include "intel_bios.h" |
33 | 33 | ||
34 | #define SLAVE_ADDR1 0x70 |
34 | #define SLAVE_ADDR1 0x70 |
35 | #define SLAVE_ADDR2 0x72 |
35 | #define SLAVE_ADDR2 0x72 |
36 | 36 | ||
37 | static int panel_type; |
37 | static int panel_type; |
38 | 38 | ||
39 | static void * |
39 | static void * |
40 | find_section(struct bdb_header *bdb, int section_id) |
40 | find_section(struct bdb_header *bdb, int section_id) |
41 | { |
41 | { |
42 | u8 *base = (u8 *)bdb; |
42 | u8 *base = (u8 *)bdb; |
43 | int index = 0; |
43 | int index = 0; |
44 | u16 total, current_size; |
44 | u16 total, current_size; |
45 | u8 current_id; |
45 | u8 current_id; |
46 | 46 | ||
47 | /* skip to first section */ |
47 | /* skip to first section */ |
48 | index += bdb->header_size; |
48 | index += bdb->header_size; |
49 | total = bdb->bdb_size; |
49 | total = bdb->bdb_size; |
50 | 50 | ||
51 | /* walk the sections looking for section_id */ |
51 | /* walk the sections looking for section_id */ |
52 | while (index + 3 < total) { |
52 | while (index + 3 < total) { |
53 | current_id = *(base + index); |
53 | current_id = *(base + index); |
54 | index++; |
54 | index++; |
55 | 55 | ||
56 | current_size = *((u16 *)(base + index)); |
56 | current_size = *((u16 *)(base + index)); |
57 | index += 2; |
57 | index += 2; |
58 | 58 | ||
59 | if (index + current_size > total) |
59 | if (index + current_size > total) |
60 | return NULL; |
60 | return NULL; |
61 | 61 | ||
62 | if (current_id == section_id) |
62 | if (current_id == section_id) |
63 | return base + index; |
63 | return base + index; |
64 | 64 | ||
65 | index += current_size; |
65 | index += current_size; |
66 | } |
66 | } |
67 | 67 | ||
68 | return NULL; |
68 | return NULL; |
69 | } |
69 | } |
70 | 70 | ||
71 | static u16 |
71 | static u16 |
72 | get_blocksize(void *p) |
72 | get_blocksize(void *p) |
73 | { |
73 | { |
74 | u16 *block_ptr, block_size; |
74 | u16 *block_ptr, block_size; |
75 | 75 | ||
76 | block_ptr = (u16 *)((char *)p - 2); |
76 | block_ptr = (u16 *)((char *)p - 2); |
77 | block_size = *block_ptr; |
77 | block_size = *block_ptr; |
78 | return block_size; |
78 | return block_size; |
79 | } |
79 | } |
80 | 80 | ||
81 | static void |
81 | static void |
82 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
82 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
83 | const struct lvds_dvo_timing *dvo_timing) |
83 | const struct lvds_dvo_timing *dvo_timing) |
84 | { |
84 | { |
85 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
85 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
86 | dvo_timing->hactive_lo; |
86 | dvo_timing->hactive_lo; |
87 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
87 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
88 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
88 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
89 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
89 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
90 | dvo_timing->hsync_pulse_width; |
90 | dvo_timing->hsync_pulse_width; |
91 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
91 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
92 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
92 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
93 | 93 | ||
94 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
94 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
95 | dvo_timing->vactive_lo; |
95 | dvo_timing->vactive_lo; |
96 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
96 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
97 | dvo_timing->vsync_off; |
97 | dvo_timing->vsync_off; |
98 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
98 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
99 | dvo_timing->vsync_pulse_width; |
99 | dvo_timing->vsync_pulse_width; |
100 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
100 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
101 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
101 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
102 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
102 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
103 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
103 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
104 | 104 | ||
105 | if (dvo_timing->hsync_positive) |
105 | if (dvo_timing->hsync_positive) |
106 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
106 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
107 | else |
107 | else |
108 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
108 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
109 | 109 | ||
110 | if (dvo_timing->vsync_positive) |
110 | if (dvo_timing->vsync_positive) |
111 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
111 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
112 | else |
112 | else |
113 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
113 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
114 | 114 | ||
115 | /* Some VBTs have bogus h/vtotal values */ |
115 | /* Some VBTs have bogus h/vtotal values */ |
116 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
116 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
117 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
117 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
118 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
118 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
119 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
119 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
120 | 120 | ||
121 | drm_mode_set_name(panel_fixed_mode); |
121 | drm_mode_set_name(panel_fixed_mode); |
122 | } |
122 | } |
123 | 123 | ||
124 | static bool |
124 | static bool |
125 | lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, |
125 | lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, |
126 | const struct lvds_dvo_timing *b) |
126 | const struct lvds_dvo_timing *b) |
127 | { |
127 | { |
128 | if (a->hactive_hi != b->hactive_hi || |
128 | if (a->hactive_hi != b->hactive_hi || |
129 | a->hactive_lo != b->hactive_lo) |
129 | a->hactive_lo != b->hactive_lo) |
130 | return false; |
130 | return false; |
131 | 131 | ||
132 | if (a->hsync_off_hi != b->hsync_off_hi || |
132 | if (a->hsync_off_hi != b->hsync_off_hi || |
133 | a->hsync_off_lo != b->hsync_off_lo) |
133 | a->hsync_off_lo != b->hsync_off_lo) |
134 | return false; |
134 | return false; |
135 | 135 | ||
136 | if (a->hsync_pulse_width != b->hsync_pulse_width) |
136 | if (a->hsync_pulse_width != b->hsync_pulse_width) |
137 | return false; |
137 | return false; |
138 | 138 | ||
139 | if (a->hblank_hi != b->hblank_hi || |
139 | if (a->hblank_hi != b->hblank_hi || |
140 | a->hblank_lo != b->hblank_lo) |
140 | a->hblank_lo != b->hblank_lo) |
141 | return false; |
141 | return false; |
142 | 142 | ||
143 | if (a->vactive_hi != b->vactive_hi || |
143 | if (a->vactive_hi != b->vactive_hi || |
144 | a->vactive_lo != b->vactive_lo) |
144 | a->vactive_lo != b->vactive_lo) |
145 | return false; |
145 | return false; |
146 | 146 | ||
147 | if (a->vsync_off != b->vsync_off) |
147 | if (a->vsync_off != b->vsync_off) |
148 | return false; |
148 | return false; |
149 | 149 | ||
150 | if (a->vsync_pulse_width != b->vsync_pulse_width) |
150 | if (a->vsync_pulse_width != b->vsync_pulse_width) |
151 | return false; |
151 | return false; |
152 | 152 | ||
153 | if (a->vblank_hi != b->vblank_hi || |
153 | if (a->vblank_hi != b->vblank_hi || |
154 | a->vblank_lo != b->vblank_lo) |
154 | a->vblank_lo != b->vblank_lo) |
155 | return false; |
155 | return false; |
156 | 156 | ||
157 | return true; |
157 | return true; |
158 | } |
158 | } |
159 | 159 | ||
160 | static const struct lvds_dvo_timing * |
160 | static const struct lvds_dvo_timing * |
161 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
161 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
162 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
162 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
163 | int index) |
163 | int index) |
164 | { |
164 | { |
165 | /* |
165 | /* |
166 | * the size of fp_timing varies on the different platform. |
166 | * the size of fp_timing varies on the different platform. |
167 | * So calculate the DVO timing relative offset in LVDS data |
167 | * So calculate the DVO timing relative offset in LVDS data |
168 | * entry to get the DVO timing entry |
168 | * entry to get the DVO timing entry |
169 | */ |
169 | */ |
170 | 170 | ||
171 | int lfp_data_size = |
171 | int lfp_data_size = |
172 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
172 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
173 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
173 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
174 | int dvo_timing_offset = |
174 | int dvo_timing_offset = |
175 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
175 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
176 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
176 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
177 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
177 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
178 | 178 | ||
179 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
179 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
180 | } |
180 | } |
181 | 181 | ||
182 | /* get lvds_fp_timing entry |
182 | /* get lvds_fp_timing entry |
183 | * this function may return NULL if the corresponding entry is invalid |
183 | * this function may return NULL if the corresponding entry is invalid |
184 | */ |
184 | */ |
185 | static const struct lvds_fp_timing * |
185 | static const struct lvds_fp_timing * |
186 | get_lvds_fp_timing(const struct bdb_header *bdb, |
186 | get_lvds_fp_timing(const struct bdb_header *bdb, |
187 | const struct bdb_lvds_lfp_data *data, |
187 | const struct bdb_lvds_lfp_data *data, |
188 | const struct bdb_lvds_lfp_data_ptrs *ptrs, |
188 | const struct bdb_lvds_lfp_data_ptrs *ptrs, |
189 | int index) |
189 | int index) |
190 | { |
190 | { |
191 | size_t data_ofs = (const u8 *)data - (const u8 *)bdb; |
191 | size_t data_ofs = (const u8 *)data - (const u8 *)bdb; |
192 | u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ |
192 | u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ |
193 | size_t ofs; |
193 | size_t ofs; |
194 | 194 | ||
195 | if (index >= ARRAY_SIZE(ptrs->ptr)) |
195 | if (index >= ARRAY_SIZE(ptrs->ptr)) |
196 | return NULL; |
196 | return NULL; |
197 | ofs = ptrs->ptr[index].fp_timing_offset; |
197 | ofs = ptrs->ptr[index].fp_timing_offset; |
198 | if (ofs < data_ofs || |
198 | if (ofs < data_ofs || |
199 | ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) |
199 | ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) |
200 | return NULL; |
200 | return NULL; |
201 | return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); |
201 | return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); |
202 | } |
202 | } |
203 | 203 | ||
204 | /* Try to find integrated panel data */ |
204 | /* Try to find integrated panel data */ |
205 | static void |
205 | static void |
206 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
206 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
207 | struct bdb_header *bdb) |
207 | struct bdb_header *bdb) |
208 | { |
208 | { |
209 | const struct bdb_lvds_options *lvds_options; |
209 | const struct bdb_lvds_options *lvds_options; |
210 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
210 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
211 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
211 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
212 | const struct lvds_dvo_timing *panel_dvo_timing; |
212 | const struct lvds_dvo_timing *panel_dvo_timing; |
213 | const struct lvds_fp_timing *fp_timing; |
213 | const struct lvds_fp_timing *fp_timing; |
214 | struct drm_display_mode *panel_fixed_mode; |
214 | struct drm_display_mode *panel_fixed_mode; |
215 | int i, downclock, drrs_mode; |
215 | int i, downclock, drrs_mode; |
216 | 216 | ||
217 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
217 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
218 | if (!lvds_options) |
218 | if (!lvds_options) |
219 | return; |
219 | return; |
220 | 220 | ||
221 | dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; |
221 | dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; |
222 | if (lvds_options->panel_type == 0xff) |
222 | if (lvds_options->panel_type == 0xff) |
223 | return; |
223 | return; |
224 | 224 | ||
225 | panel_type = lvds_options->panel_type; |
225 | panel_type = lvds_options->panel_type; |
226 | 226 | ||
227 | drrs_mode = (lvds_options->dps_panel_type_bits |
227 | drrs_mode = (lvds_options->dps_panel_type_bits |
228 | >> (panel_type * 2)) & MODE_MASK; |
228 | >> (panel_type * 2)) & MODE_MASK; |
229 | /* |
229 | /* |
230 | * VBT has static DRRS = 0 and seamless DRRS = 2. |
230 | * VBT has static DRRS = 0 and seamless DRRS = 2. |
231 | * The below piece of code is required to adjust vbt.drrs_type |
231 | * The below piece of code is required to adjust vbt.drrs_type |
232 | * to match the enum drrs_support_type. |
232 | * to match the enum drrs_support_type. |
233 | */ |
233 | */ |
234 | switch (drrs_mode) { |
234 | switch (drrs_mode) { |
235 | case 0: |
235 | case 0: |
236 | dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; |
236 | dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; |
237 | DRM_DEBUG_KMS("DRRS supported mode is static\n"); |
237 | DRM_DEBUG_KMS("DRRS supported mode is static\n"); |
238 | break; |
238 | break; |
239 | case 2: |
239 | case 2: |
240 | dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; |
240 | dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; |
241 | DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); |
241 | DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); |
242 | break; |
242 | break; |
243 | default: |
243 | default: |
244 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
244 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
245 | DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); |
245 | DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); |
246 | break; |
246 | break; |
247 | } |
247 | } |
248 | 248 | ||
249 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
249 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
250 | if (!lvds_lfp_data) |
250 | if (!lvds_lfp_data) |
251 | return; |
251 | return; |
252 | 252 | ||
253 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
253 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
254 | if (!lvds_lfp_data_ptrs) |
254 | if (!lvds_lfp_data_ptrs) |
255 | return; |
255 | return; |
256 | 256 | ||
257 | dev_priv->vbt.lvds_vbt = 1; |
257 | dev_priv->vbt.lvds_vbt = 1; |
258 | 258 | ||
259 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
259 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
260 | lvds_lfp_data_ptrs, |
260 | lvds_lfp_data_ptrs, |
261 | lvds_options->panel_type); |
261 | lvds_options->panel_type); |
262 | 262 | ||
263 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
263 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
264 | if (!panel_fixed_mode) |
264 | if (!panel_fixed_mode) |
265 | return; |
265 | return; |
266 | 266 | ||
267 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
267 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
268 | 268 | ||
269 | dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; |
269 | dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; |
270 | 270 | ||
271 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
271 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
272 | drm_mode_debug_printmodeline(panel_fixed_mode); |
272 | drm_mode_debug_printmodeline(panel_fixed_mode); |
273 | 273 | ||
274 | /* |
274 | /* |
275 | * Iterate over the LVDS panel timing info to find the lowest clock |
275 | * Iterate over the LVDS panel timing info to find the lowest clock |
276 | * for the native resolution. |
276 | * for the native resolution. |
277 | */ |
277 | */ |
278 | downclock = panel_dvo_timing->clock; |
278 | downclock = panel_dvo_timing->clock; |
279 | for (i = 0; i < 16; i++) { |
279 | for (i = 0; i < 16; i++) { |
280 | const struct lvds_dvo_timing *dvo_timing; |
280 | const struct lvds_dvo_timing *dvo_timing; |
281 | 281 | ||
282 | dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
282 | dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
283 | lvds_lfp_data_ptrs, |
283 | lvds_lfp_data_ptrs, |
284 | i); |
284 | i); |
285 | if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && |
285 | if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && |
286 | dvo_timing->clock < downclock) |
286 | dvo_timing->clock < downclock) |
287 | downclock = dvo_timing->clock; |
287 | downclock = dvo_timing->clock; |
288 | } |
288 | } |
289 | 289 | ||
290 | if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) { |
290 | if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) { |
291 | dev_priv->lvds_downclock_avail = 1; |
291 | dev_priv->lvds_downclock_avail = 1; |
292 | dev_priv->lvds_downclock = downclock * 10; |
292 | dev_priv->lvds_downclock = downclock * 10; |
293 | DRM_DEBUG_KMS("LVDS downclock is found in VBT. " |
293 | DRM_DEBUG_KMS("LVDS downclock is found in VBT. " |
294 | "Normal Clock %dKHz, downclock %dKHz\n", |
294 | "Normal Clock %dKHz, downclock %dKHz\n", |
295 | panel_fixed_mode->clock, 10*downclock); |
295 | panel_fixed_mode->clock, 10*downclock); |
296 | } |
296 | } |
297 | 297 | ||
298 | fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, |
298 | fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, |
299 | lvds_lfp_data_ptrs, |
299 | lvds_lfp_data_ptrs, |
300 | lvds_options->panel_type); |
300 | lvds_options->panel_type); |
301 | if (fp_timing) { |
301 | if (fp_timing) { |
302 | /* check the resolution, just to be sure */ |
302 | /* check the resolution, just to be sure */ |
303 | if (fp_timing->x_res == panel_fixed_mode->hdisplay && |
303 | if (fp_timing->x_res == panel_fixed_mode->hdisplay && |
304 | fp_timing->y_res == panel_fixed_mode->vdisplay) { |
304 | fp_timing->y_res == panel_fixed_mode->vdisplay) { |
305 | dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; |
305 | dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; |
306 | DRM_DEBUG_KMS("VBT initial LVDS value %x\n", |
306 | DRM_DEBUG_KMS("VBT initial LVDS value %x\n", |
307 | dev_priv->vbt.bios_lvds_val); |
307 | dev_priv->vbt.bios_lvds_val); |
308 | } |
308 | } |
309 | } |
309 | } |
310 | } |
310 | } |
311 | 311 | ||
312 | static void |
312 | static void |
313 | parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
313 | parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
314 | { |
314 | { |
315 | const struct bdb_lfp_backlight_data *backlight_data; |
315 | const struct bdb_lfp_backlight_data *backlight_data; |
316 | const struct bdb_lfp_backlight_data_entry *entry; |
316 | const struct bdb_lfp_backlight_data_entry *entry; |
317 | 317 | ||
318 | backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); |
318 | backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); |
319 | if (!backlight_data) |
319 | if (!backlight_data) |
320 | return; |
320 | return; |
321 | 321 | ||
322 | if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { |
322 | if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { |
323 | DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", |
323 | DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", |
324 | backlight_data->entry_size); |
324 | backlight_data->entry_size); |
325 | return; |
325 | return; |
326 | } |
326 | } |
327 | 327 | ||
328 | entry = &backlight_data->data[panel_type]; |
328 | entry = &backlight_data->data[panel_type]; |
329 | 329 | ||
330 | dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; |
330 | dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; |
331 | if (!dev_priv->vbt.backlight.present) { |
331 | if (!dev_priv->vbt.backlight.present) { |
332 | DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", |
332 | DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", |
333 | entry->type); |
333 | entry->type); |
334 | return; |
334 | return; |
335 | } |
335 | } |
336 | 336 | ||
337 | dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; |
337 | dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; |
338 | dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; |
338 | dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; |
339 | dev_priv->vbt.backlight.min_brightness = entry->min_brightness; |
339 | dev_priv->vbt.backlight.min_brightness = entry->min_brightness; |
340 | DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " |
340 | DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " |
341 | "active %s, min brightness %u, level %u\n", |
341 | "active %s, min brightness %u, level %u\n", |
342 | dev_priv->vbt.backlight.pwm_freq_hz, |
342 | dev_priv->vbt.backlight.pwm_freq_hz, |
343 | dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", |
343 | dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", |
344 | dev_priv->vbt.backlight.min_brightness, |
344 | dev_priv->vbt.backlight.min_brightness, |
345 | backlight_data->level[panel_type]); |
345 | backlight_data->level[panel_type]); |
346 | } |
346 | } |
347 | 347 | ||
348 | /* Try to find sdvo panel data */ |
348 | /* Try to find sdvo panel data */ |
349 | static void |
349 | static void |
350 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
350 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
351 | struct bdb_header *bdb) |
351 | struct bdb_header *bdb) |
352 | { |
352 | { |
353 | struct lvds_dvo_timing *dvo_timing; |
353 | struct lvds_dvo_timing *dvo_timing; |
354 | struct drm_display_mode *panel_fixed_mode; |
354 | struct drm_display_mode *panel_fixed_mode; |
355 | int index; |
355 | int index; |
356 | 356 | ||
357 | index = i915.vbt_sdvo_panel_type; |
357 | index = i915.vbt_sdvo_panel_type; |
358 | if (index == -2) { |
358 | if (index == -2) { |
359 | DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); |
359 | DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); |
360 | return; |
360 | return; |
361 | } |
361 | } |
362 | 362 | ||
363 | if (index == -1) { |
363 | if (index == -1) { |
364 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
364 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
365 | 365 | ||
366 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
366 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
367 | if (!sdvo_lvds_options) |
367 | if (!sdvo_lvds_options) |
368 | return; |
368 | return; |
369 | 369 | ||
370 | index = sdvo_lvds_options->panel_type; |
370 | index = sdvo_lvds_options->panel_type; |
371 | } |
371 | } |
372 | 372 | ||
373 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
373 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
374 | if (!dvo_timing) |
374 | if (!dvo_timing) |
375 | return; |
375 | return; |
376 | 376 | ||
377 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
377 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
378 | if (!panel_fixed_mode) |
378 | if (!panel_fixed_mode) |
379 | return; |
379 | return; |
380 | 380 | ||
381 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
381 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
382 | 382 | ||
383 | dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; |
383 | dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; |
384 | 384 | ||
385 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
385 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
386 | drm_mode_debug_printmodeline(panel_fixed_mode); |
386 | drm_mode_debug_printmodeline(panel_fixed_mode); |
387 | } |
387 | } |
388 | 388 | ||
389 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
389 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
390 | bool alternate) |
390 | bool alternate) |
391 | { |
391 | { |
392 | switch (INTEL_INFO(dev)->gen) { |
392 | switch (INTEL_INFO(dev)->gen) { |
393 | case 2: |
393 | case 2: |
394 | return alternate ? 66667 : 48000; |
394 | return alternate ? 66667 : 48000; |
395 | case 3: |
395 | case 3: |
396 | case 4: |
396 | case 4: |
397 | return alternate ? 100000 : 96000; |
397 | return alternate ? 100000 : 96000; |
398 | default: |
398 | default: |
399 | return alternate ? 100000 : 120000; |
399 | return alternate ? 100000 : 120000; |
400 | } |
400 | } |
401 | } |
401 | } |
402 | 402 | ||
403 | static void |
403 | static void |
404 | parse_general_features(struct drm_i915_private *dev_priv, |
404 | parse_general_features(struct drm_i915_private *dev_priv, |
405 | struct bdb_header *bdb) |
405 | struct bdb_header *bdb) |
406 | { |
406 | { |
407 | struct drm_device *dev = dev_priv->dev; |
407 | struct drm_device *dev = dev_priv->dev; |
408 | struct bdb_general_features *general; |
408 | struct bdb_general_features *general; |
409 | 409 | ||
410 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
410 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
411 | if (general) { |
411 | if (general) { |
412 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
412 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
413 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
413 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
414 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
414 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
415 | dev_priv->vbt.lvds_ssc_freq = |
415 | dev_priv->vbt.lvds_ssc_freq = |
416 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
416 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
417 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
417 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
418 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
418 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
419 | 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 fdi_rx_polarity_inverted %d\n", |
419 | 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 fdi_rx_polarity_inverted %d\n", |
420 | dev_priv->vbt.int_tv_support, |
420 | dev_priv->vbt.int_tv_support, |
421 | dev_priv->vbt.int_crt_support, |
421 | dev_priv->vbt.int_crt_support, |
422 | dev_priv->vbt.lvds_use_ssc, |
422 | dev_priv->vbt.lvds_use_ssc, |
423 | dev_priv->vbt.lvds_ssc_freq, |
423 | dev_priv->vbt.lvds_ssc_freq, |
424 | dev_priv->vbt.display_clock_mode, |
424 | dev_priv->vbt.display_clock_mode, |
425 | dev_priv->vbt.fdi_rx_polarity_inverted); |
425 | dev_priv->vbt.fdi_rx_polarity_inverted); |
426 | } |
426 | } |
427 | } |
427 | } |
428 | 428 | ||
429 | static void |
429 | static void |
430 | parse_general_definitions(struct drm_i915_private *dev_priv, |
430 | parse_general_definitions(struct drm_i915_private *dev_priv, |
431 | struct bdb_header *bdb) |
431 | struct bdb_header *bdb) |
432 | { |
432 | { |
433 | struct bdb_general_definitions *general; |
433 | struct bdb_general_definitions *general; |
434 | 434 | ||
435 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
435 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
436 | if (general) { |
436 | if (general) { |
437 | u16 block_size = get_blocksize(general); |
437 | u16 block_size = get_blocksize(general); |
438 | if (block_size >= sizeof(*general)) { |
438 | if (block_size >= sizeof(*general)) { |
439 | int bus_pin = general->crt_ddc_gmbus_pin; |
439 | int bus_pin = general->crt_ddc_gmbus_pin; |
440 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
440 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
441 | if (intel_gmbus_is_port_valid(bus_pin)) |
441 | if (intel_gmbus_is_port_valid(bus_pin)) |
442 | dev_priv->vbt.crt_ddc_pin = bus_pin; |
442 | dev_priv->vbt.crt_ddc_pin = bus_pin; |
443 | } else { |
443 | } else { |
444 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
444 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
445 | block_size); |
445 | block_size); |
446 | } |
446 | } |
447 | } |
447 | } |
448 | } |
448 | } |
449 | 449 | ||
450 | static void |
450 | static void |
451 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
451 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
452 | struct bdb_header *bdb) |
452 | struct bdb_header *bdb) |
453 | { |
453 | { |
454 | struct sdvo_device_mapping *p_mapping; |
454 | struct sdvo_device_mapping *p_mapping; |
455 | struct bdb_general_definitions *p_defs; |
455 | struct bdb_general_definitions *p_defs; |
456 | union child_device_config *p_child; |
456 | union child_device_config *p_child; |
457 | int i, child_device_num, count; |
457 | int i, child_device_num, count; |
458 | u16 block_size; |
458 | u16 block_size; |
459 | 459 | ||
460 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
460 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
461 | if (!p_defs) { |
461 | if (!p_defs) { |
462 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
462 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
463 | return; |
463 | return; |
464 | } |
464 | } |
465 | /* judge whether the size of child device meets the requirements. |
465 | /* judge whether the size of child device meets the requirements. |
466 | * If the child device size obtained from general definition block |
466 | * If the child device size obtained from general definition block |
467 | * is different with sizeof(struct child_device_config), skip the |
467 | * is different with sizeof(struct child_device_config), skip the |
468 | * parsing of sdvo device info |
468 | * parsing of sdvo device info |
469 | */ |
469 | */ |
470 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
470 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
471 | /* different child dev size . Ignore it */ |
471 | /* different child dev size . Ignore it */ |
472 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
472 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
473 | return; |
473 | return; |
474 | } |
474 | } |
475 | /* get the block size of general definitions */ |
475 | /* get the block size of general definitions */ |
476 | block_size = get_blocksize(p_defs); |
476 | block_size = get_blocksize(p_defs); |
477 | /* get the number of child device */ |
477 | /* get the number of child device */ |
478 | child_device_num = (block_size - sizeof(*p_defs)) / |
478 | child_device_num = (block_size - sizeof(*p_defs)) / |
479 | sizeof(*p_child); |
479 | sizeof(*p_child); |
480 | count = 0; |
480 | count = 0; |
481 | for (i = 0; i < child_device_num; i++) { |
481 | for (i = 0; i < child_device_num; i++) { |
482 | p_child = &(p_defs->devices[i]); |
482 | p_child = &(p_defs->devices[i]); |
483 | if (!p_child->old.device_type) { |
483 | if (!p_child->old.device_type) { |
484 | /* skip the device block if device type is invalid */ |
484 | /* skip the device block if device type is invalid */ |
485 | continue; |
485 | continue; |
486 | } |
486 | } |
487 | if (p_child->old.slave_addr != SLAVE_ADDR1 && |
487 | if (p_child->old.slave_addr != SLAVE_ADDR1 && |
488 | p_child->old.slave_addr != SLAVE_ADDR2) { |
488 | p_child->old.slave_addr != SLAVE_ADDR2) { |
489 | /* |
489 | /* |
490 | * If the slave address is neither 0x70 nor 0x72, |
490 | * If the slave address is neither 0x70 nor 0x72, |
491 | * it is not a SDVO device. Skip it. |
491 | * it is not a SDVO device. Skip it. |
492 | */ |
492 | */ |
493 | continue; |
493 | continue; |
494 | } |
494 | } |
495 | if (p_child->old.dvo_port != DEVICE_PORT_DVOB && |
495 | if (p_child->old.dvo_port != DEVICE_PORT_DVOB && |
496 | p_child->old.dvo_port != DEVICE_PORT_DVOC) { |
496 | p_child->old.dvo_port != DEVICE_PORT_DVOC) { |
497 | /* skip the incorrect SDVO port */ |
497 | /* skip the incorrect SDVO port */ |
498 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); |
498 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); |
499 | continue; |
499 | continue; |
500 | } |
500 | } |
501 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
501 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
502 | " %s port\n", |
502 | " %s port\n", |
503 | p_child->old.slave_addr, |
503 | p_child->old.slave_addr, |
504 | (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? |
504 | (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? |
505 | "SDVOB" : "SDVOC"); |
505 | "SDVOB" : "SDVOC"); |
506 | p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); |
506 | p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); |
507 | if (!p_mapping->initialized) { |
507 | if (!p_mapping->initialized) { |
508 | p_mapping->dvo_port = p_child->old.dvo_port; |
508 | p_mapping->dvo_port = p_child->old.dvo_port; |
509 | p_mapping->slave_addr = p_child->old.slave_addr; |
509 | p_mapping->slave_addr = p_child->old.slave_addr; |
510 | p_mapping->dvo_wiring = p_child->old.dvo_wiring; |
510 | p_mapping->dvo_wiring = p_child->old.dvo_wiring; |
511 | p_mapping->ddc_pin = p_child->old.ddc_pin; |
511 | p_mapping->ddc_pin = p_child->old.ddc_pin; |
512 | p_mapping->i2c_pin = p_child->old.i2c_pin; |
512 | p_mapping->i2c_pin = p_child->old.i2c_pin; |
513 | p_mapping->initialized = 1; |
513 | p_mapping->initialized = 1; |
514 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", |
514 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", |
515 | p_mapping->dvo_port, |
515 | p_mapping->dvo_port, |
516 | p_mapping->slave_addr, |
516 | p_mapping->slave_addr, |
517 | p_mapping->dvo_wiring, |
517 | p_mapping->dvo_wiring, |
518 | p_mapping->ddc_pin, |
518 | p_mapping->ddc_pin, |
519 | p_mapping->i2c_pin); |
519 | p_mapping->i2c_pin); |
520 | } else { |
520 | } else { |
521 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
521 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
522 | "two SDVO device.\n"); |
522 | "two SDVO device.\n"); |
523 | } |
523 | } |
524 | if (p_child->old.slave2_addr) { |
524 | if (p_child->old.slave2_addr) { |
525 | /* Maybe this is a SDVO device with multiple inputs */ |
525 | /* Maybe this is a SDVO device with multiple inputs */ |
526 | /* And the mapping info is not added */ |
526 | /* And the mapping info is not added */ |
527 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
527 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
528 | " is a SDVO device with multiple inputs.\n"); |
528 | " is a SDVO device with multiple inputs.\n"); |
529 | } |
529 | } |
530 | count++; |
530 | count++; |
531 | } |
531 | } |
532 | 532 | ||
533 | if (!count) { |
533 | if (!count) { |
534 | /* No SDVO device info is found */ |
534 | /* No SDVO device info is found */ |
535 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
535 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
536 | } |
536 | } |
537 | return; |
537 | return; |
538 | } |
538 | } |
539 | 539 | ||
540 | static void |
540 | static void |
541 | parse_driver_features(struct drm_i915_private *dev_priv, |
541 | parse_driver_features(struct drm_i915_private *dev_priv, |
542 | struct bdb_header *bdb) |
542 | struct bdb_header *bdb) |
543 | { |
543 | { |
544 | struct bdb_driver_features *driver; |
544 | struct bdb_driver_features *driver; |
545 | 545 | ||
546 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
546 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
547 | if (!driver) |
547 | if (!driver) |
548 | return; |
548 | return; |
549 | 549 | ||
550 | if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
550 | if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
551 | dev_priv->vbt.edp_support = 1; |
551 | dev_priv->vbt.edp_support = 1; |
552 | 552 | ||
553 | if (driver->dual_frequency) |
553 | if (driver->dual_frequency) |
554 | dev_priv->render_reclock_avail = true; |
554 | dev_priv->render_reclock_avail = true; |
555 | 555 | ||
556 | DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); |
556 | DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); |
557 | /* |
557 | /* |
558 | * If DRRS is not supported, drrs_type has to be set to 0. |
558 | * If DRRS is not supported, drrs_type has to be set to 0. |
559 | * This is because, VBT is configured in such a way that |
559 | * This is because, VBT is configured in such a way that |
560 | * static DRRS is 0 and DRRS not supported is represented by |
560 | * static DRRS is 0 and DRRS not supported is represented by |
561 | * driver->drrs_enabled=false |
561 | * driver->drrs_enabled=false |
562 | */ |
562 | */ |
563 | if (!driver->drrs_enabled) |
563 | if (!driver->drrs_enabled) |
564 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
564 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
565 | } |
565 | } |
566 | 566 | ||
567 | static void |
567 | static void |
568 | parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
568 | parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
569 | { |
569 | { |
570 | struct bdb_edp *edp; |
570 | struct bdb_edp *edp; |
571 | struct edp_power_seq *edp_pps; |
571 | struct edp_power_seq *edp_pps; |
572 | struct edp_link_params *edp_link_params; |
572 | struct edp_link_params *edp_link_params; |
573 | 573 | ||
574 | edp = find_section(bdb, BDB_EDP); |
574 | edp = find_section(bdb, BDB_EDP); |
575 | if (!edp) { |
575 | if (!edp) { |
576 | if (dev_priv->vbt.edp_support) |
576 | if (dev_priv->vbt.edp_support) |
577 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); |
577 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); |
578 | return; |
578 | return; |
579 | } |
579 | } |
580 | 580 | ||
581 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
581 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
582 | case EDP_18BPP: |
582 | case EDP_18BPP: |
583 | dev_priv->vbt.edp_bpp = 18; |
583 | dev_priv->vbt.edp_bpp = 18; |
584 | break; |
584 | break; |
585 | case EDP_24BPP: |
585 | case EDP_24BPP: |
586 | dev_priv->vbt.edp_bpp = 24; |
586 | dev_priv->vbt.edp_bpp = 24; |
587 | break; |
587 | break; |
588 | case EDP_30BPP: |
588 | case EDP_30BPP: |
589 | dev_priv->vbt.edp_bpp = 30; |
589 | dev_priv->vbt.edp_bpp = 30; |
590 | break; |
590 | break; |
591 | } |
591 | } |
592 | 592 | ||
593 | /* Get the eDP sequencing and link info */ |
593 | /* Get the eDP sequencing and link info */ |
594 | edp_pps = &edp->power_seqs[panel_type]; |
594 | edp_pps = &edp->power_seqs[panel_type]; |
595 | edp_link_params = &edp->link_params[panel_type]; |
595 | edp_link_params = &edp->link_params[panel_type]; |
596 | 596 | ||
597 | dev_priv->vbt.edp_pps = *edp_pps; |
597 | dev_priv->vbt.edp_pps = *edp_pps; |
598 | 598 | ||
599 | switch (edp_link_params->rate) { |
599 | switch (edp_link_params->rate) { |
600 | case EDP_RATE_1_62: |
600 | case EDP_RATE_1_62: |
601 | dev_priv->vbt.edp_rate = DP_LINK_BW_1_62; |
601 | dev_priv->vbt.edp_rate = DP_LINK_BW_1_62; |
602 | break; |
602 | break; |
603 | case EDP_RATE_2_7: |
603 | case EDP_RATE_2_7: |
604 | dev_priv->vbt.edp_rate = DP_LINK_BW_2_7; |
604 | dev_priv->vbt.edp_rate = DP_LINK_BW_2_7; |
605 | break; |
605 | break; |
606 | default: |
606 | default: |
607 | DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n", |
607 | DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n", |
608 | edp_link_params->rate); |
608 | edp_link_params->rate); |
609 | break; |
609 | break; |
610 | } |
610 | } |
611 | 611 | ||
612 | switch (edp_link_params->lanes) { |
612 | switch (edp_link_params->lanes) { |
613 | case EDP_LANE_1: |
613 | case EDP_LANE_1: |
614 | dev_priv->vbt.edp_lanes = 1; |
614 | dev_priv->vbt.edp_lanes = 1; |
615 | break; |
615 | break; |
616 | case EDP_LANE_2: |
616 | case EDP_LANE_2: |
617 | dev_priv->vbt.edp_lanes = 2; |
617 | dev_priv->vbt.edp_lanes = 2; |
618 | break; |
618 | break; |
619 | case EDP_LANE_4: |
619 | case EDP_LANE_4: |
620 | dev_priv->vbt.edp_lanes = 4; |
620 | dev_priv->vbt.edp_lanes = 4; |
621 | break; |
621 | break; |
622 | default: |
622 | default: |
623 | DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n", |
623 | DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n", |
624 | edp_link_params->lanes); |
624 | edp_link_params->lanes); |
625 | break; |
625 | break; |
626 | } |
626 | } |
627 | 627 | ||
628 | switch (edp_link_params->preemphasis) { |
628 | switch (edp_link_params->preemphasis) { |
629 | case EDP_PREEMPHASIS_NONE: |
629 | case EDP_PREEMPHASIS_NONE: |
630 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0; |
630 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; |
631 | break; |
631 | break; |
632 | case EDP_PREEMPHASIS_3_5dB: |
632 | case EDP_PREEMPHASIS_3_5dB: |
633 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; |
633 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; |
634 | break; |
634 | break; |
635 | case EDP_PREEMPHASIS_6dB: |
635 | case EDP_PREEMPHASIS_6dB: |
636 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6; |
636 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; |
637 | break; |
637 | break; |
638 | case EDP_PREEMPHASIS_9_5dB: |
638 | case EDP_PREEMPHASIS_9_5dB: |
639 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; |
639 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; |
640 | break; |
640 | break; |
641 | default: |
641 | default: |
642 | DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n", |
642 | DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n", |
643 | edp_link_params->preemphasis); |
643 | edp_link_params->preemphasis); |
644 | break; |
644 | break; |
645 | } |
645 | } |
646 | 646 | ||
647 | switch (edp_link_params->vswing) { |
647 | switch (edp_link_params->vswing) { |
648 | case EDP_VSWING_0_4V: |
648 | case EDP_VSWING_0_4V: |
649 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400; |
649 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; |
650 | break; |
650 | break; |
651 | case EDP_VSWING_0_6V: |
651 | case EDP_VSWING_0_6V: |
652 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600; |
652 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; |
653 | break; |
653 | break; |
654 | case EDP_VSWING_0_8V: |
654 | case EDP_VSWING_0_8V: |
655 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800; |
655 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; |
656 | break; |
656 | break; |
657 | case EDP_VSWING_1_2V: |
657 | case EDP_VSWING_1_2V: |
658 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200; |
658 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; |
659 | break; |
659 | break; |
660 | default: |
660 | default: |
661 | DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n", |
661 | DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n", |
662 | edp_link_params->vswing); |
662 | edp_link_params->vswing); |
663 | break; |
663 | break; |
664 | } |
664 | } |
665 | } |
665 | } |
666 | 666 | ||
667 | static u8 *goto_next_sequence(u8 *data, int *size) |
667 | static u8 *goto_next_sequence(u8 *data, int *size) |
668 | { |
668 | { |
669 | u16 len; |
669 | u16 len; |
670 | int tmp = *size; |
670 | int tmp = *size; |
671 | 671 | ||
672 | if (--tmp < 0) |
672 | if (--tmp < 0) |
673 | return NULL; |
673 | return NULL; |
674 | 674 | ||
675 | /* goto first element */ |
675 | /* goto first element */ |
676 | data++; |
676 | data++; |
677 | while (1) { |
677 | while (1) { |
678 | switch (*data) { |
678 | switch (*data) { |
679 | case MIPI_SEQ_ELEM_SEND_PKT: |
679 | case MIPI_SEQ_ELEM_SEND_PKT: |
680 | /* |
680 | /* |
681 | * skip by this element payload size |
681 | * skip by this element payload size |
682 | * skip elem id, command flag and data type |
682 | * skip elem id, command flag and data type |
683 | */ |
683 | */ |
684 | tmp -= 5; |
684 | tmp -= 5; |
685 | if (tmp < 0) |
685 | if (tmp < 0) |
686 | return NULL; |
686 | return NULL; |
687 | 687 | ||
688 | data += 3; |
688 | data += 3; |
689 | len = *((u16 *)data); |
689 | len = *((u16 *)data); |
690 | 690 | ||
691 | tmp -= len; |
691 | tmp -= len; |
692 | if (tmp < 0) |
692 | if (tmp < 0) |
693 | return NULL; |
693 | return NULL; |
694 | 694 | ||
695 | /* skip by len */ |
695 | /* skip by len */ |
696 | data = data + 2 + len; |
696 | data = data + 2 + len; |
697 | break; |
697 | break; |
698 | case MIPI_SEQ_ELEM_DELAY: |
698 | case MIPI_SEQ_ELEM_DELAY: |
699 | /* skip by elem id, and delay is 4 bytes */ |
699 | /* skip by elem id, and delay is 4 bytes */ |
700 | tmp -= 5; |
700 | tmp -= 5; |
701 | if (tmp < 0) |
701 | if (tmp < 0) |
702 | return NULL; |
702 | return NULL; |
703 | 703 | ||
704 | data += 5; |
704 | data += 5; |
705 | break; |
705 | break; |
706 | case MIPI_SEQ_ELEM_GPIO: |
706 | case MIPI_SEQ_ELEM_GPIO: |
707 | tmp -= 3; |
707 | tmp -= 3; |
708 | if (tmp < 0) |
708 | if (tmp < 0) |
709 | return NULL; |
709 | return NULL; |
710 | 710 | ||
711 | data += 3; |
711 | data += 3; |
712 | break; |
712 | break; |
713 | default: |
713 | default: |
714 | DRM_ERROR("Unknown element\n"); |
714 | DRM_ERROR("Unknown element\n"); |
715 | return NULL; |
715 | return NULL; |
716 | } |
716 | } |
717 | 717 | ||
718 | /* end of sequence ? */ |
718 | /* end of sequence ? */ |
719 | if (*data == 0) |
719 | if (*data == 0) |
720 | break; |
720 | break; |
721 | } |
721 | } |
722 | 722 | ||
723 | /* goto next sequence or end of block byte */ |
723 | /* goto next sequence or end of block byte */ |
724 | if (--tmp < 0) |
724 | if (--tmp < 0) |
725 | return NULL; |
725 | return NULL; |
726 | 726 | ||
727 | data++; |
727 | data++; |
728 | 728 | ||
729 | /* update amount of data left for the sequence block to be parsed */ |
729 | /* update amount of data left for the sequence block to be parsed */ |
730 | *size = tmp; |
730 | *size = tmp; |
731 | return data; |
731 | return data; |
732 | } |
732 | } |
733 | 733 | ||
734 | static void |
734 | static void |
735 | parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
735 | parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
736 | { |
736 | { |
737 | struct bdb_mipi_config *start; |
737 | struct bdb_mipi_config *start; |
738 | struct bdb_mipi_sequence *sequence; |
738 | struct bdb_mipi_sequence *sequence; |
739 | struct mipi_config *config; |
739 | struct mipi_config *config; |
740 | struct mipi_pps_data *pps; |
740 | struct mipi_pps_data *pps; |
741 | u8 *data, *seq_data; |
741 | u8 *data, *seq_data; |
742 | int i, panel_id, seq_size; |
742 | int i, panel_id, seq_size; |
743 | u16 block_size; |
743 | u16 block_size; |
744 | 744 | ||
745 | /* parse MIPI blocks only if LFP type is MIPI */ |
745 | /* parse MIPI blocks only if LFP type is MIPI */ |
746 | if (!dev_priv->vbt.has_mipi) |
746 | if (!dev_priv->vbt.has_mipi) |
747 | return; |
747 | return; |
748 | 748 | ||
749 | /* Initialize this to undefined indicating no generic MIPI support */ |
749 | /* Initialize this to undefined indicating no generic MIPI support */ |
750 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; |
750 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; |
751 | 751 | ||
752 | /* Block #40 is already parsed and panel_fixed_mode is |
752 | /* Block #40 is already parsed and panel_fixed_mode is |
753 | * stored in dev_priv->lfp_lvds_vbt_mode |
753 | * stored in dev_priv->lfp_lvds_vbt_mode |
754 | * resuse this when needed |
754 | * resuse this when needed |
755 | */ |
755 | */ |
756 | 756 | ||
757 | /* Parse #52 for panel index used from panel_type already |
757 | /* Parse #52 for panel index used from panel_type already |
758 | * parsed |
758 | * parsed |
759 | */ |
759 | */ |
760 | start = find_section(bdb, BDB_MIPI_CONFIG); |
760 | start = find_section(bdb, BDB_MIPI_CONFIG); |
761 | if (!start) { |
761 | if (!start) { |
762 | DRM_DEBUG_KMS("No MIPI config BDB found"); |
762 | DRM_DEBUG_KMS("No MIPI config BDB found"); |
763 | return; |
763 | return; |
764 | } |
764 | } |
765 | 765 | ||
766 | DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", |
766 | DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", |
767 | panel_type); |
767 | panel_type); |
768 | 768 | ||
769 | /* |
769 | /* |
770 | * get hold of the correct configuration block and pps data as per |
770 | * get hold of the correct configuration block and pps data as per |
771 | * the panel_type as index |
771 | * the panel_type as index |
772 | */ |
772 | */ |
773 | config = &start->config[panel_type]; |
773 | config = &start->config[panel_type]; |
774 | pps = &start->pps[panel_type]; |
774 | pps = &start->pps[panel_type]; |
775 | 775 | ||
776 | /* store as of now full data. Trim when we realise all is not needed */ |
776 | /* store as of now full data. Trim when we realise all is not needed */ |
777 | dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); |
777 | dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); |
778 | if (!dev_priv->vbt.dsi.config) |
778 | if (!dev_priv->vbt.dsi.config) |
779 | return; |
779 | return; |
780 | 780 | ||
781 | dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); |
781 | dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); |
782 | if (!dev_priv->vbt.dsi.pps) { |
782 | if (!dev_priv->vbt.dsi.pps) { |
783 | kfree(dev_priv->vbt.dsi.config); |
783 | kfree(dev_priv->vbt.dsi.config); |
784 | return; |
784 | return; |
785 | } |
785 | } |
786 | 786 | ||
787 | /* We have mandatory mipi config blocks. Initialize as generic panel */ |
787 | /* We have mandatory mipi config blocks. Initialize as generic panel */ |
788 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; |
788 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; |
789 | 789 | ||
790 | /* Check if we have sequence block as well */ |
790 | /* Check if we have sequence block as well */ |
791 | sequence = find_section(bdb, BDB_MIPI_SEQUENCE); |
791 | sequence = find_section(bdb, BDB_MIPI_SEQUENCE); |
792 | if (!sequence) { |
792 | if (!sequence) { |
793 | DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); |
793 | DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); |
794 | return; |
794 | return; |
795 | } |
795 | } |
796 | 796 | ||
797 | DRM_DEBUG_DRIVER("Found MIPI sequence block\n"); |
797 | DRM_DEBUG_DRIVER("Found MIPI sequence block\n"); |
798 | 798 | ||
799 | block_size = get_blocksize(sequence); |
799 | block_size = get_blocksize(sequence); |
800 | 800 | ||
801 | /* |
801 | /* |
802 | * parse the sequence block for individual sequences |
802 | * parse the sequence block for individual sequences |
803 | */ |
803 | */ |
804 | dev_priv->vbt.dsi.seq_version = sequence->version; |
804 | dev_priv->vbt.dsi.seq_version = sequence->version; |
805 | 805 | ||
806 | seq_data = &sequence->data[0]; |
806 | seq_data = &sequence->data[0]; |
807 | 807 | ||
808 | /* |
808 | /* |
809 | * sequence block is variable length and hence we need to parse and |
809 | * sequence block is variable length and hence we need to parse and |
810 | * get the sequence data for specific panel id |
810 | * get the sequence data for specific panel id |
811 | */ |
811 | */ |
812 | for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) { |
812 | for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) { |
813 | panel_id = *seq_data; |
813 | panel_id = *seq_data; |
814 | seq_size = *((u16 *) (seq_data + 1)); |
814 | seq_size = *((u16 *) (seq_data + 1)); |
815 | if (panel_id == panel_type) |
815 | if (panel_id == panel_type) |
816 | break; |
816 | break; |
817 | 817 | ||
818 | /* skip the sequence including seq header of 3 bytes */ |
818 | /* skip the sequence including seq header of 3 bytes */ |
819 | seq_data = seq_data + 3 + seq_size; |
819 | seq_data = seq_data + 3 + seq_size; |
820 | if ((seq_data - &sequence->data[0]) > block_size) { |
820 | if ((seq_data - &sequence->data[0]) > block_size) { |
821 | DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n"); |
821 | DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n"); |
822 | return; |
822 | return; |
823 | } |
823 | } |
824 | } |
824 | } |
825 | 825 | ||
826 | if (i == MAX_MIPI_CONFIGURATIONS) { |
826 | if (i == MAX_MIPI_CONFIGURATIONS) { |
827 | DRM_ERROR("Sequence block detected but no valid configuration\n"); |
827 | DRM_ERROR("Sequence block detected but no valid configuration\n"); |
828 | return; |
828 | return; |
829 | } |
829 | } |
830 | 830 | ||
831 | /* check if found sequence is completely within the sequence block |
831 | /* check if found sequence is completely within the sequence block |
832 | * just being paranoid */ |
832 | * just being paranoid */ |
833 | if (seq_size > block_size) { |
833 | if (seq_size > block_size) { |
834 | DRM_ERROR("Corrupted sequence/size, bailing out\n"); |
834 | DRM_ERROR("Corrupted sequence/size, bailing out\n"); |
835 | return; |
835 | return; |
836 | } |
836 | } |
837 | 837 | ||
838 | /* skip the panel id(1 byte) and seq size(2 bytes) */ |
838 | /* skip the panel id(1 byte) and seq size(2 bytes) */ |
839 | dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL); |
839 | dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL); |
840 | if (!dev_priv->vbt.dsi.data) |
840 | if (!dev_priv->vbt.dsi.data) |
841 | return; |
841 | return; |
842 | 842 | ||
843 | /* |
843 | /* |
844 | * loop into the sequence data and split into multiple sequneces |
844 | * loop into the sequence data and split into multiple sequneces |
845 | * There are only 5 types of sequences as of now |
845 | * There are only 5 types of sequences as of now |
846 | */ |
846 | */ |
847 | data = dev_priv->vbt.dsi.data; |
847 | data = dev_priv->vbt.dsi.data; |
848 | dev_priv->vbt.dsi.size = seq_size; |
848 | dev_priv->vbt.dsi.size = seq_size; |
849 | 849 | ||
850 | /* two consecutive 0x00 indicate end of all sequences */ |
850 | /* two consecutive 0x00 indicate end of all sequences */ |
851 | while (1) { |
851 | while (1) { |
852 | int seq_id = *data; |
852 | int seq_id = *data; |
853 | if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) { |
853 | if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) { |
854 | dev_priv->vbt.dsi.sequence[seq_id] = data; |
854 | dev_priv->vbt.dsi.sequence[seq_id] = data; |
855 | DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id); |
855 | DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id); |
856 | } else { |
856 | } else { |
857 | DRM_ERROR("undefined sequence\n"); |
857 | DRM_ERROR("undefined sequence\n"); |
858 | goto err; |
858 | goto err; |
859 | } |
859 | } |
860 | 860 | ||
861 | /* partial parsing to skip elements */ |
861 | /* partial parsing to skip elements */ |
862 | data = goto_next_sequence(data, &seq_size); |
862 | data = goto_next_sequence(data, &seq_size); |
863 | 863 | ||
864 | if (data == NULL) { |
864 | if (data == NULL) { |
865 | DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n"); |
865 | DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n"); |
866 | goto err; |
866 | goto err; |
867 | } |
867 | } |
868 | 868 | ||
869 | if (*data == 0) |
869 | if (*data == 0) |
870 | break; /* end of sequence reached */ |
870 | break; /* end of sequence reached */ |
871 | } |
871 | } |
872 | 872 | ||
873 | DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n"); |
873 | DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n"); |
874 | return; |
874 | return; |
875 | err: |
875 | err: |
876 | kfree(dev_priv->vbt.dsi.data); |
876 | kfree(dev_priv->vbt.dsi.data); |
877 | dev_priv->vbt.dsi.data = NULL; |
877 | dev_priv->vbt.dsi.data = NULL; |
878 | 878 | ||
879 | /* error during parsing so set all pointers to null |
879 | /* error during parsing so set all pointers to null |
880 | * because of partial parsing */ |
880 | * because of partial parsing */ |
881 | memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence)); |
881 | memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence)); |
882 | } |
882 | } |
883 | 883 | ||
884 | static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, |
884 | static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, |
885 | struct bdb_header *bdb) |
885 | struct bdb_header *bdb) |
886 | { |
886 | { |
887 | union child_device_config *it, *child = NULL; |
887 | union child_device_config *it, *child = NULL; |
888 | struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; |
888 | struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; |
889 | uint8_t hdmi_level_shift; |
889 | uint8_t hdmi_level_shift; |
890 | int i, j; |
890 | int i, j; |
891 | bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; |
891 | bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; |
892 | uint8_t aux_channel; |
892 | uint8_t aux_channel; |
893 | /* Each DDI port can have more than one value on the "DVO Port" field, |
893 | /* Each DDI port can have more than one value on the "DVO Port" field, |
894 | * so look for all the possible values for each port and abort if more |
894 | * so look for all the possible values for each port and abort if more |
895 | * than one is found. */ |
895 | * than one is found. */ |
896 | int dvo_ports[][2] = { |
896 | int dvo_ports[][2] = { |
897 | {DVO_PORT_HDMIA, DVO_PORT_DPA}, |
897 | {DVO_PORT_HDMIA, DVO_PORT_DPA}, |
898 | {DVO_PORT_HDMIB, DVO_PORT_DPB}, |
898 | {DVO_PORT_HDMIB, DVO_PORT_DPB}, |
899 | {DVO_PORT_HDMIC, DVO_PORT_DPC}, |
899 | {DVO_PORT_HDMIC, DVO_PORT_DPC}, |
900 | {DVO_PORT_HDMID, DVO_PORT_DPD}, |
900 | {DVO_PORT_HDMID, DVO_PORT_DPD}, |
901 | {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, |
901 | {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, |
902 | }; |
902 | }; |
903 | 903 | ||
904 | /* Find the child device to use, abort if more than one found. */ |
904 | /* Find the child device to use, abort if more than one found. */ |
905 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
905 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
906 | it = dev_priv->vbt.child_dev + i; |
906 | it = dev_priv->vbt.child_dev + i; |
907 | 907 | ||
908 | for (j = 0; j < 2; j++) { |
908 | for (j = 0; j < 2; j++) { |
909 | if (dvo_ports[port][j] == -1) |
909 | if (dvo_ports[port][j] == -1) |
910 | break; |
910 | break; |
911 | 911 | ||
912 | if (it->common.dvo_port == dvo_ports[port][j]) { |
912 | if (it->common.dvo_port == dvo_ports[port][j]) { |
913 | if (child) { |
913 | if (child) { |
914 | DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", |
914 | DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", |
915 | port_name(port)); |
915 | port_name(port)); |
916 | return; |
916 | return; |
917 | } |
917 | } |
918 | child = it; |
918 | child = it; |
919 | } |
919 | } |
920 | } |
920 | } |
921 | } |
921 | } |
922 | if (!child) |
922 | if (!child) |
923 | return; |
923 | return; |
924 | 924 | ||
925 | aux_channel = child->raw[25]; |
925 | aux_channel = child->raw[25]; |
926 | 926 | ||
927 | is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; |
927 | is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; |
928 | is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; |
928 | is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; |
929 | is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT; |
929 | is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT; |
930 | is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; |
930 | is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; |
931 | is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); |
931 | is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); |
932 | 932 | ||
933 | info->supports_dvi = is_dvi; |
933 | info->supports_dvi = is_dvi; |
934 | info->supports_hdmi = is_hdmi; |
934 | info->supports_hdmi = is_hdmi; |
935 | info->supports_dp = is_dp; |
935 | info->supports_dp = is_dp; |
936 | 936 | ||
937 | DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", |
937 | DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", |
938 | port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); |
938 | port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); |
939 | 939 | ||
940 | if (is_edp && is_dvi) |
940 | if (is_edp && is_dvi) |
941 | DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", |
941 | DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", |
942 | port_name(port)); |
942 | port_name(port)); |
943 | if (is_crt && port != PORT_E) |
943 | if (is_crt && port != PORT_E) |
944 | DRM_DEBUG_KMS("Port %c is analog\n", port_name(port)); |
944 | DRM_DEBUG_KMS("Port %c is analog\n", port_name(port)); |
945 | if (is_crt && (is_dvi || is_dp)) |
945 | if (is_crt && (is_dvi || is_dp)) |
946 | DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", |
946 | DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", |
947 | port_name(port)); |
947 | port_name(port)); |
948 | if (is_dvi && (port == PORT_A || port == PORT_E)) |
948 | if (is_dvi && (port == PORT_A || port == PORT_E)) |
949 | DRM_DEBUG_KMS("Port %c is TMDS compabile\n", port_name(port)); |
949 | DRM_DEBUG_KMS("Port %c is TMDS compatible\n", port_name(port)); |
950 | if (!is_dvi && !is_dp && !is_crt) |
950 | if (!is_dvi && !is_dp && !is_crt) |
951 | DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", |
951 | DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", |
952 | port_name(port)); |
952 | port_name(port)); |
953 | if (is_edp && (port == PORT_B || port == PORT_C || port == PORT_E)) |
953 | if (is_edp && (port == PORT_B || port == PORT_C || port == PORT_E)) |
954 | DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); |
954 | DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); |
955 | 955 | ||
956 | if (is_dvi) { |
956 | if (is_dvi) { |
957 | if (child->common.ddc_pin == 0x05 && port != PORT_B) |
957 | if (child->common.ddc_pin == 0x05 && port != PORT_B) |
958 | DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); |
958 | DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); |
959 | if (child->common.ddc_pin == 0x04 && port != PORT_C) |
959 | if (child->common.ddc_pin == 0x04 && port != PORT_C) |
960 | DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); |
960 | DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); |
961 | if (child->common.ddc_pin == 0x06 && port != PORT_D) |
961 | if (child->common.ddc_pin == 0x06 && port != PORT_D) |
962 | DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); |
962 | DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); |
963 | } |
963 | } |
964 | 964 | ||
965 | if (is_dp) { |
965 | if (is_dp) { |
966 | if (aux_channel == 0x40 && port != PORT_A) |
966 | if (aux_channel == 0x40 && port != PORT_A) |
967 | DRM_DEBUG_KMS("Unexpected AUX channel for port A\n"); |
967 | DRM_DEBUG_KMS("Unexpected AUX channel for port A\n"); |
968 | if (aux_channel == 0x10 && port != PORT_B) |
968 | if (aux_channel == 0x10 && port != PORT_B) |
969 | DRM_DEBUG_KMS("Unexpected AUX channel for port B\n"); |
969 | DRM_DEBUG_KMS("Unexpected AUX channel for port B\n"); |
970 | if (aux_channel == 0x20 && port != PORT_C) |
970 | if (aux_channel == 0x20 && port != PORT_C) |
971 | DRM_DEBUG_KMS("Unexpected AUX channel for port C\n"); |
971 | DRM_DEBUG_KMS("Unexpected AUX channel for port C\n"); |
972 | if (aux_channel == 0x30 && port != PORT_D) |
972 | if (aux_channel == 0x30 && port != PORT_D) |
973 | DRM_DEBUG_KMS("Unexpected AUX channel for port D\n"); |
973 | DRM_DEBUG_KMS("Unexpected AUX channel for port D\n"); |
974 | } |
974 | } |
975 | 975 | ||
976 | if (bdb->version >= 158) { |
976 | if (bdb->version >= 158) { |
977 | /* The VBT HDMI level shift values match the table we have. */ |
977 | /* The VBT HDMI level shift values match the table we have. */ |
978 | hdmi_level_shift = child->raw[7] & 0xF; |
978 | hdmi_level_shift = child->raw[7] & 0xF; |
979 | if (hdmi_level_shift < 0xC) { |
- | |
980 | DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", |
979 | DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", |
981 | port_name(port), |
980 | port_name(port), |
982 | hdmi_level_shift); |
981 | hdmi_level_shift); |
983 | info->hdmi_level_shift = hdmi_level_shift; |
982 | info->hdmi_level_shift = hdmi_level_shift; |
984 | } |
983 | } |
985 | } |
984 | } |
986 | } |
- | |
987 | 985 | ||
988 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
986 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
989 | struct bdb_header *bdb) |
987 | struct bdb_header *bdb) |
990 | { |
988 | { |
991 | struct drm_device *dev = dev_priv->dev; |
989 | struct drm_device *dev = dev_priv->dev; |
992 | enum port port; |
990 | enum port port; |
993 | 991 | ||
994 | if (!HAS_DDI(dev)) |
992 | if (!HAS_DDI(dev)) |
995 | return; |
993 | return; |
996 | 994 | ||
997 | if (!dev_priv->vbt.child_dev_num) |
995 | if (!dev_priv->vbt.child_dev_num) |
998 | return; |
996 | return; |
999 | 997 | ||
1000 | if (bdb->version < 155) |
998 | if (bdb->version < 155) |
1001 | return; |
999 | return; |
1002 | 1000 | ||
1003 | for (port = PORT_A; port < I915_MAX_PORTS; port++) |
1001 | for (port = PORT_A; port < I915_MAX_PORTS; port++) |
1004 | parse_ddi_port(dev_priv, port, bdb); |
1002 | parse_ddi_port(dev_priv, port, bdb); |
1005 | } |
1003 | } |
1006 | 1004 | ||
1007 | static void |
1005 | static void |
1008 | parse_device_mapping(struct drm_i915_private *dev_priv, |
1006 | parse_device_mapping(struct drm_i915_private *dev_priv, |
1009 | struct bdb_header *bdb) |
1007 | struct bdb_header *bdb) |
1010 | { |
1008 | { |
1011 | struct bdb_general_definitions *p_defs; |
1009 | struct bdb_general_definitions *p_defs; |
1012 | union child_device_config *p_child, *child_dev_ptr; |
1010 | union child_device_config *p_child, *child_dev_ptr; |
1013 | int i, child_device_num, count; |
1011 | int i, child_device_num, count; |
1014 | u16 block_size; |
1012 | u16 block_size; |
1015 | 1013 | ||
1016 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
1014 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
1017 | if (!p_defs) { |
1015 | if (!p_defs) { |
1018 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
1016 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
1019 | return; |
1017 | return; |
1020 | } |
1018 | } |
1021 | /* judge whether the size of child device meets the requirements. |
1019 | /* judge whether the size of child device meets the requirements. |
1022 | * If the child device size obtained from general definition block |
1020 | * If the child device size obtained from general definition block |
1023 | * is different with sizeof(struct child_device_config), skip the |
1021 | * is different with sizeof(struct child_device_config), skip the |
1024 | * parsing of sdvo device info |
1022 | * parsing of sdvo device info |
1025 | */ |
1023 | */ |
1026 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
1024 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
1027 | /* different child dev size . Ignore it */ |
1025 | /* different child dev size . Ignore it */ |
1028 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
1026 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
1029 | return; |
1027 | return; |
1030 | } |
1028 | } |
1031 | /* get the block size of general definitions */ |
1029 | /* get the block size of general definitions */ |
1032 | block_size = get_blocksize(p_defs); |
1030 | block_size = get_blocksize(p_defs); |
1033 | /* get the number of child device */ |
1031 | /* get the number of child device */ |
1034 | child_device_num = (block_size - sizeof(*p_defs)) / |
1032 | child_device_num = (block_size - sizeof(*p_defs)) / |
1035 | sizeof(*p_child); |
1033 | sizeof(*p_child); |
1036 | count = 0; |
1034 | count = 0; |
1037 | /* get the number of child device that is present */ |
1035 | /* get the number of child device that is present */ |
1038 | for (i = 0; i < child_device_num; i++) { |
1036 | for (i = 0; i < child_device_num; i++) { |
1039 | p_child = &(p_defs->devices[i]); |
1037 | p_child = &(p_defs->devices[i]); |
1040 | if (!p_child->common.device_type) { |
1038 | if (!p_child->common.device_type) { |
1041 | /* skip the device block if device type is invalid */ |
1039 | /* skip the device block if device type is invalid */ |
1042 | continue; |
1040 | continue; |
1043 | } |
1041 | } |
1044 | count++; |
1042 | count++; |
1045 | } |
1043 | } |
1046 | if (!count) { |
1044 | if (!count) { |
1047 | DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); |
1045 | DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); |
1048 | return; |
1046 | return; |
1049 | } |
1047 | } |
1050 | dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); |
1048 | dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); |
1051 | if (!dev_priv->vbt.child_dev) { |
1049 | if (!dev_priv->vbt.child_dev) { |
1052 | DRM_DEBUG_KMS("No memory space for child device\n"); |
1050 | DRM_DEBUG_KMS("No memory space for child device\n"); |
1053 | return; |
1051 | return; |
1054 | } |
1052 | } |
1055 | 1053 | ||
1056 | dev_priv->vbt.child_dev_num = count; |
1054 | dev_priv->vbt.child_dev_num = count; |
1057 | count = 0; |
1055 | count = 0; |
1058 | for (i = 0; i < child_device_num; i++) { |
1056 | for (i = 0; i < child_device_num; i++) { |
1059 | p_child = &(p_defs->devices[i]); |
1057 | p_child = &(p_defs->devices[i]); |
1060 | if (!p_child->common.device_type) { |
1058 | if (!p_child->common.device_type) { |
1061 | /* skip the device block if device type is invalid */ |
1059 | /* skip the device block if device type is invalid */ |
1062 | continue; |
1060 | continue; |
1063 | } |
1061 | } |
1064 | 1062 | ||
1065 | if (p_child->common.dvo_port >= DVO_PORT_MIPIA |
1063 | if (p_child->common.dvo_port >= DVO_PORT_MIPIA |
1066 | && p_child->common.dvo_port <= DVO_PORT_MIPID |
1064 | && p_child->common.dvo_port <= DVO_PORT_MIPID |
1067 | &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) { |
1065 | &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) { |
1068 | DRM_DEBUG_KMS("Found MIPI as LFP\n"); |
1066 | DRM_DEBUG_KMS("Found MIPI as LFP\n"); |
1069 | dev_priv->vbt.has_mipi = 1; |
1067 | dev_priv->vbt.has_mipi = 1; |
1070 | dev_priv->vbt.dsi.port = p_child->common.dvo_port; |
1068 | dev_priv->vbt.dsi.port = p_child->common.dvo_port; |
1071 | } |
1069 | } |
1072 | 1070 | ||
1073 | child_dev_ptr = dev_priv->vbt.child_dev + count; |
1071 | child_dev_ptr = dev_priv->vbt.child_dev + count; |
1074 | count++; |
1072 | count++; |
1075 | memcpy((void *)child_dev_ptr, (void *)p_child, |
1073 | memcpy((void *)child_dev_ptr, (void *)p_child, |
1076 | sizeof(*p_child)); |
1074 | sizeof(*p_child)); |
1077 | } |
1075 | } |
1078 | return; |
1076 | return; |
1079 | } |
1077 | } |
1080 | 1078 | ||
1081 | static void |
1079 | static void |
1082 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
1080 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
1083 | { |
1081 | { |
1084 | struct drm_device *dev = dev_priv->dev; |
1082 | struct drm_device *dev = dev_priv->dev; |
1085 | enum port port; |
1083 | enum port port; |
1086 | 1084 | ||
1087 | dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; |
1085 | dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; |
1088 | 1086 | ||
1089 | /* Default to having backlight */ |
1087 | /* Default to having backlight */ |
1090 | dev_priv->vbt.backlight.present = true; |
1088 | dev_priv->vbt.backlight.present = true; |
1091 | 1089 | ||
1092 | /* LFP panel data */ |
1090 | /* LFP panel data */ |
1093 | dev_priv->vbt.lvds_dither = 1; |
1091 | dev_priv->vbt.lvds_dither = 1; |
1094 | dev_priv->vbt.lvds_vbt = 0; |
1092 | dev_priv->vbt.lvds_vbt = 0; |
1095 | 1093 | ||
1096 | /* SDVO panel data */ |
1094 | /* SDVO panel data */ |
1097 | dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; |
1095 | dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; |
1098 | 1096 | ||
1099 | /* general features */ |
1097 | /* general features */ |
1100 | dev_priv->vbt.int_tv_support = 1; |
1098 | dev_priv->vbt.int_tv_support = 1; |
1101 | dev_priv->vbt.int_crt_support = 1; |
1099 | dev_priv->vbt.int_crt_support = 1; |
1102 | 1100 | ||
1103 | /* Default to using SSC */ |
1101 | /* Default to using SSC */ |
1104 | dev_priv->vbt.lvds_use_ssc = 1; |
1102 | dev_priv->vbt.lvds_use_ssc = 1; |
1105 | /* |
1103 | /* |
1106 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
1104 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
1107 | * clock for LVDS. |
1105 | * clock for LVDS. |
1108 | */ |
1106 | */ |
1109 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, |
1107 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, |
1110 | !HAS_PCH_SPLIT(dev)); |
1108 | !HAS_PCH_SPLIT(dev)); |
1111 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
1109 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
1112 | 1110 | ||
1113 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
1111 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
1114 | struct ddi_vbt_port_info *info = |
1112 | struct ddi_vbt_port_info *info = |
1115 | &dev_priv->vbt.ddi_port_info[port]; |
1113 | &dev_priv->vbt.ddi_port_info[port]; |
1116 | - | ||
1117 | /* Recommended BSpec default: 800mV 0dB. */ |
1114 | |
1118 | info->hdmi_level_shift = 6; |
1115 | info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN; |
1119 | 1116 | ||
1120 | info->supports_dvi = (port != PORT_A && port != PORT_E); |
1117 | info->supports_dvi = (port != PORT_A && port != PORT_E); |
1121 | info->supports_hdmi = info->supports_dvi; |
1118 | info->supports_hdmi = info->supports_dvi; |
1122 | info->supports_dp = (port != PORT_E); |
1119 | info->supports_dp = (port != PORT_E); |
1123 | } |
1120 | } |
1124 | } |
1121 | } |
1125 | 1122 | ||
1126 | static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id) |
1123 | static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id) |
1127 | { |
1124 | { |
1128 | DRM_DEBUG_KMS("Falling back to manually reading VBT from " |
1125 | DRM_DEBUG_KMS("Falling back to manually reading VBT from " |
1129 | "VBIOS ROM for %s\n", |
1126 | "VBIOS ROM for %s\n", |
1130 | id->ident); |
1127 | id->ident); |
1131 | return 1; |
1128 | return 1; |
1132 | } |
1129 | } |
1133 | 1130 | ||
1134 | static const struct dmi_system_id intel_no_opregion_vbt[] = { |
1131 | static const struct dmi_system_id intel_no_opregion_vbt[] = { |
1135 | { |
1132 | { |
1136 | .callback = intel_no_opregion_vbt_callback, |
1133 | .callback = intel_no_opregion_vbt_callback, |
1137 | .ident = "ThinkCentre A57", |
1134 | .ident = "ThinkCentre A57", |
1138 | .matches = { |
1135 | .matches = { |
1139 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
1136 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
1140 | DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), |
1137 | DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), |
1141 | }, |
1138 | }, |
1142 | }, |
1139 | }, |
1143 | { } |
1140 | { } |
1144 | }; |
1141 | }; |
1145 | 1142 | ||
1146 | static struct bdb_header *validate_vbt(char *base, size_t size, |
1143 | static struct bdb_header *validate_vbt(char *base, size_t size, |
1147 | struct vbt_header *vbt, |
1144 | struct vbt_header *vbt, |
1148 | const char *source) |
1145 | const char *source) |
1149 | { |
1146 | { |
1150 | size_t offset; |
1147 | size_t offset; |
1151 | struct bdb_header *bdb; |
1148 | struct bdb_header *bdb; |
1152 | 1149 | ||
1153 | if (vbt == NULL) { |
1150 | if (vbt == NULL) { |
1154 | DRM_DEBUG_DRIVER("VBT signature missing\n"); |
1151 | DRM_DEBUG_DRIVER("VBT signature missing\n"); |
1155 | return NULL; |
1152 | return NULL; |
1156 | } |
1153 | } |
1157 | 1154 | ||
1158 | offset = (char *)vbt - base; |
1155 | offset = (char *)vbt - base; |
1159 | if (offset + sizeof(struct vbt_header) > size) { |
1156 | if (offset + sizeof(struct vbt_header) > size) { |
1160 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
1157 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
1161 | return NULL; |
1158 | return NULL; |
1162 | } |
1159 | } |
1163 | 1160 | ||
1164 | if (memcmp(vbt->signature, "$VBT", 4)) { |
1161 | if (memcmp(vbt->signature, "$VBT", 4)) { |
1165 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
1162 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
1166 | return NULL; |
1163 | return NULL; |
1167 | } |
1164 | } |
1168 | 1165 | ||
1169 | offset += vbt->bdb_offset; |
1166 | offset += vbt->bdb_offset; |
1170 | if (offset + sizeof(struct bdb_header) > size) { |
1167 | if (offset + sizeof(struct bdb_header) > size) { |
1171 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
1168 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
1172 | return NULL; |
1169 | return NULL; |
1173 | } |
1170 | } |
1174 | 1171 | ||
1175 | bdb = (struct bdb_header *)(base + offset); |
1172 | bdb = (struct bdb_header *)(base + offset); |
1176 | if (offset + bdb->bdb_size > size) { |
1173 | if (offset + bdb->bdb_size > size) { |
1177 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
1174 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
1178 | return NULL; |
1175 | return NULL; |
1179 | } |
1176 | } |
1180 | 1177 | ||
1181 | DRM_DEBUG_KMS("Using VBT from %s: %20s\n", |
1178 | DRM_DEBUG_KMS("Using VBT from %s: %20s\n", |
1182 | source, vbt->signature); |
1179 | source, vbt->signature); |
1183 | return bdb; |
1180 | return bdb; |
1184 | } |
1181 | } |
1185 | 1182 | ||
1186 | /** |
1183 | /** |
1187 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
1184 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
1188 | * @dev: DRM device |
1185 | * @dev: DRM device |
1189 | * |
1186 | * |
1190 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
1187 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
1191 | * to appropriate values. |
1188 | * to appropriate values. |
1192 | * |
1189 | * |
1193 | * Returns 0 on success, nonzero on failure. |
1190 | * Returns 0 on success, nonzero on failure. |
1194 | */ |
1191 | */ |
1195 | int |
1192 | int |
1196 | intel_parse_bios(struct drm_device *dev) |
1193 | intel_parse_bios(struct drm_device *dev) |
1197 | { |
1194 | { |
1198 | struct drm_i915_private *dev_priv = dev->dev_private; |
1195 | struct drm_i915_private *dev_priv = dev->dev_private; |
1199 | struct pci_dev *pdev = dev->pdev; |
1196 | struct pci_dev *pdev = dev->pdev; |
1200 | struct bdb_header *bdb = NULL; |
1197 | struct bdb_header *bdb = NULL; |
1201 | u8 __iomem *bios = NULL; |
1198 | u8 __iomem *bios = NULL; |
1202 | 1199 | ||
1203 | if (HAS_PCH_NOP(dev)) |
1200 | if (HAS_PCH_NOP(dev)) |
1204 | return -ENODEV; |
1201 | return -ENODEV; |
1205 | 1202 | ||
1206 | init_vbt_defaults(dev_priv); |
1203 | init_vbt_defaults(dev_priv); |
1207 | 1204 | ||
1208 | /* XXX Should this validation be moved to intel_opregion.c? */ |
1205 | /* XXX Should this validation be moved to intel_opregion.c? */ |
1209 | if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) |
1206 | if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) |
1210 | bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE, |
1207 | bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE, |
1211 | (struct vbt_header *)dev_priv->opregion.vbt, |
1208 | (struct vbt_header *)dev_priv->opregion.vbt, |
1212 | "OpRegion"); |
1209 | "OpRegion"); |
1213 | 1210 | ||
1214 | if (bdb == NULL) { |
1211 | if (bdb == NULL) { |
1215 | size_t i, size; |
1212 | size_t i, size; |
1216 | 1213 | ||
1217 | bios = pci_map_rom(pdev, &size); |
1214 | bios = pci_map_rom(pdev, &size); |
1218 | if (!bios) |
1215 | if (!bios) |
1219 | return -1; |
1216 | return -1; |
1220 | 1217 | ||
1221 | /* Scour memory looking for the VBT signature */ |
1218 | /* Scour memory looking for the VBT signature */ |
1222 | for (i = 0; i + 4 < size; i++) { |
1219 | for (i = 0; i + 4 < size; i++) { |
1223 | if (memcmp(bios + i, "$VBT", 4) == 0) { |
1220 | if (memcmp(bios + i, "$VBT", 4) == 0) { |
1224 | bdb = validate_vbt(bios, size, |
1221 | bdb = validate_vbt(bios, size, |
1225 | (struct vbt_header *)(bios + i), |
1222 | (struct vbt_header *)(bios + i), |
1226 | "PCI ROM"); |
1223 | "PCI ROM"); |
1227 | break; |
1224 | break; |
1228 | } |
1225 | } |
1229 | } |
1226 | } |
1230 | 1227 | ||
1231 | if (!bdb) { |
1228 | if (!bdb) { |
1232 | pci_unmap_rom(pdev, bios); |
1229 | pci_unmap_rom(pdev, bios); |
1233 | return -1; |
1230 | return -1; |
1234 | } |
1231 | } |
1235 | } |
1232 | } |
1236 | 1233 | ||
1237 | /* Grab useful general definitions */ |
1234 | /* Grab useful general definitions */ |
1238 | parse_general_features(dev_priv, bdb); |
1235 | parse_general_features(dev_priv, bdb); |
1239 | parse_general_definitions(dev_priv, bdb); |
1236 | parse_general_definitions(dev_priv, bdb); |
1240 | parse_lfp_panel_data(dev_priv, bdb); |
1237 | parse_lfp_panel_data(dev_priv, bdb); |
1241 | parse_lfp_backlight(dev_priv, bdb); |
1238 | parse_lfp_backlight(dev_priv, bdb); |
1242 | parse_sdvo_panel_data(dev_priv, bdb); |
1239 | parse_sdvo_panel_data(dev_priv, bdb); |
1243 | parse_sdvo_device_mapping(dev_priv, bdb); |
1240 | parse_sdvo_device_mapping(dev_priv, bdb); |
1244 | parse_device_mapping(dev_priv, bdb); |
1241 | parse_device_mapping(dev_priv, bdb); |
1245 | parse_driver_features(dev_priv, bdb); |
1242 | parse_driver_features(dev_priv, bdb); |
1246 | parse_edp(dev_priv, bdb); |
1243 | parse_edp(dev_priv, bdb); |
1247 | parse_mipi(dev_priv, bdb); |
1244 | parse_mipi(dev_priv, bdb); |
1248 | parse_ddi_ports(dev_priv, bdb); |
1245 | parse_ddi_ports(dev_priv, bdb); |
1249 | 1246 | ||
1250 | if (bios) |
1247 | if (bios) |
1251 | pci_unmap_rom(pdev, bios); |
1248 | pci_unmap_rom(pdev, bios); |
1252 | 1249 | ||
1253 | return 0; |
1250 | return 0; |
1254 | } |
1251 | } |
1255 | 1252 | ||
1256 | /* Ensure that vital registers have been initialised, even if the BIOS |
1253 | /* Ensure that vital registers have been initialised, even if the BIOS |
1257 | * is absent or just failing to do its job. |
1254 | * is absent or just failing to do its job. |
1258 | */ |
1255 | */ |
1259 | void intel_setup_bios(struct drm_device *dev) |
1256 | void intel_setup_bios(struct drm_device *dev) |
1260 | { |
1257 | { |
1261 | struct drm_i915_private *dev_priv = dev->dev_private; |
1258 | struct drm_i915_private *dev_priv = dev->dev_private; |
1262 | 1259 | ||
1263 | /* Set the Panel Power On/Off timings if uninitialized. */ |
1260 | /* Set the Panel Power On/Off timings if uninitialized. */ |
1264 | if (!HAS_PCH_SPLIT(dev) && |
1261 | if (!HAS_PCH_SPLIT(dev) && |
1265 | I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) { |
1262 | I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) { |
1266 | /* Set T2 to 40ms and T5 to 200ms */ |
1263 | /* Set T2 to 40ms and T5 to 200ms */ |
1267 | I915_WRITE(PP_ON_DELAYS, 0x019007d0); |
1264 | I915_WRITE(PP_ON_DELAYS, 0x019007d0); |
1268 | 1265 | ||
1269 | /* Set T3 to 35ms and Tx to 200ms */ |
1266 | /* Set T3 to 35ms and Tx to 200ms */ |
1270 | I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); |
1267 | I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); |
1271 | } |
1268 | } |
1272 | }>>=>>>>>>>>>>>>>>>>>>>>><>><>><>><>><>> |
1269 | }>>=>>>>>>>>>>>>>>>>>>>><>><>><>><>><>> |