Line data Source code
1 : /*
2 : * Copyright © 2006 Intel Corporation
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the "Software"),
6 : * to deal in the Software without restriction, including without limitation
7 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : * and/or sell copies of the Software, and to permit persons to whom the
9 : * Software is furnished to do so, subject to the following conditions:
10 : *
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
13 : * Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 : * DEALINGS IN THE SOFTWARE.
22 : *
23 : * Authors:
24 : * Eric Anholt <eric@anholt.net>
25 : * Thomas Richter <thor@math.tu-berlin.de>
26 : *
27 : * Minor modifications (Dithering enable):
28 : * Thomas Richter <thor@math.tu-berlin.de>
29 : *
30 : */
31 :
32 : #include "dvo.h"
33 :
34 : /*
35 : * register definitions for the i82807aa.
36 : *
37 : * Documentation on this chipset can be found in datasheet #29069001 at
38 : * intel.com.
39 : */
40 :
41 : /*
42 : * VCH Revision & GMBus Base Addr
43 : */
44 : #define VR00 0x00
45 : # define VR00_BASE_ADDRESS_MASK 0x007f
46 :
47 : /*
48 : * Functionality Enable
49 : */
50 : #define VR01 0x01
51 :
52 : /*
53 : * Enable the panel fitter
54 : */
55 : # define VR01_PANEL_FIT_ENABLE (1 << 3)
56 : /*
57 : * Enables the LCD display.
58 : *
59 : * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
60 : */
61 : # define VR01_LCD_ENABLE (1 << 2)
62 : /** Enables the DVO repeater. */
63 : # define VR01_DVO_BYPASS_ENABLE (1 << 1)
64 : /** Enables the DVO clock */
65 : # define VR01_DVO_ENABLE (1 << 0)
66 : /** Enable dithering for 18bpp panels. Not documented. */
67 : # define VR01_DITHER_ENABLE (1 << 4)
68 :
69 : /*
70 : * LCD Interface Format
71 : */
72 : #define VR10 0x10
73 : /** Enables LVDS output instead of CMOS */
74 : # define VR10_LVDS_ENABLE (1 << 4)
75 : /** Enables 18-bit LVDS output. */
76 : # define VR10_INTERFACE_1X18 (0 << 2)
77 : /** Enables 24-bit LVDS or CMOS output */
78 : # define VR10_INTERFACE_1X24 (1 << 2)
79 : /** Enables 2x18-bit LVDS or CMOS output. */
80 : # define VR10_INTERFACE_2X18 (2 << 2)
81 : /** Enables 2x24-bit LVDS output */
82 : # define VR10_INTERFACE_2X24 (3 << 2)
83 : /** Mask that defines the depth of the pipeline */
84 : # define VR10_INTERFACE_DEPTH_MASK (3 << 2)
85 :
86 : /*
87 : * VR20 LCD Horizontal Display Size
88 : */
89 : #define VR20 0x20
90 :
91 : /*
92 : * LCD Vertical Display Size
93 : */
94 : #define VR21 0x21
95 :
96 : /*
97 : * Panel power down status
98 : */
99 : #define VR30 0x30
100 : /** Read only bit indicating that the panel is not in a safe poweroff state. */
101 : # define VR30_PANEL_ON (1 << 15)
102 :
103 : #define VR40 0x40
104 : # define VR40_STALL_ENABLE (1 << 13)
105 : # define VR40_VERTICAL_INTERP_ENABLE (1 << 12)
106 : # define VR40_ENHANCED_PANEL_FITTING (1 << 11)
107 : # define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
108 : # define VR40_AUTO_RATIO_ENABLE (1 << 9)
109 : # define VR40_CLOCK_GATING_ENABLE (1 << 8)
110 :
111 : /*
112 : * Panel Fitting Vertical Ratio
113 : * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
114 : */
115 : #define VR41 0x41
116 :
117 : /*
118 : * Panel Fitting Horizontal Ratio
119 : * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
120 : */
121 : #define VR42 0x42
122 :
123 : /*
124 : * Horizontal Image Size
125 : */
126 : #define VR43 0x43
127 :
128 : /* VR80 GPIO 0
129 : */
130 : #define VR80 0x80
131 : #define VR81 0x81
132 : #define VR82 0x82
133 : #define VR83 0x83
134 : #define VR84 0x84
135 : #define VR85 0x85
136 : #define VR86 0x86
137 : #define VR87 0x87
138 :
139 : /* VR88 GPIO 8
140 : */
141 : #define VR88 0x88
142 :
143 : /* Graphics BIOS scratch 0
144 : */
145 : #define VR8E 0x8E
146 : # define VR8E_PANEL_TYPE_MASK (0xf << 0)
147 : # define VR8E_PANEL_INTERFACE_CMOS (0 << 4)
148 : # define VR8E_PANEL_INTERFACE_LVDS (1 << 4)
149 : # define VR8E_FORCE_DEFAULT_PANEL (1 << 5)
150 :
151 : /* Graphics BIOS scratch 1
152 : */
153 : #define VR8F 0x8F
154 : # define VR8F_VCH_PRESENT (1 << 0)
155 : # define VR8F_DISPLAY_CONN (1 << 1)
156 : # define VR8F_POWER_MASK (0x3c)
157 : # define VR8F_POWER_POS (2)
158 :
159 : /* Some Bios implementations do not restore the DVO state upon
160 : * resume from standby. Thus, this driver has to handle it
161 : * instead. The following list contains all registers that
162 : * require saving.
163 : */
164 : static const uint16_t backup_addresses[] = {
165 : 0x11, 0x12,
166 : 0x18, 0x19, 0x1a, 0x1f,
167 : 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
168 : 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
169 : 0x8e, 0x8f,
170 : 0x10 /* this must come last */
171 : };
172 :
173 :
174 : struct ivch_priv {
175 : bool quiet;
176 :
177 : uint16_t width, height;
178 :
179 : /* Register backup */
180 :
181 : uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
182 : };
183 :
184 :
185 : static void ivch_dump_regs(struct intel_dvo_device *dvo);
186 : /**
187 : * Reads a register on the ivch.
188 : *
189 : * Each of the 256 registers are 16 bits long.
190 : */
191 0 : static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
192 : {
193 0 : struct ivch_priv *priv = dvo->dev_priv;
194 0 : struct i2c_adapter *adapter = dvo->i2c_bus;
195 0 : u8 out_buf[1];
196 0 : u8 in_buf[2];
197 :
198 0 : struct i2c_msg msgs[] = {
199 0 : {
200 0 : .addr = dvo->slave_addr,
201 : .flags = I2C_M_RD,
202 : .len = 0,
203 : },
204 0 : {
205 : .addr = 0,
206 : .flags = I2C_M_NOSTART,
207 : .len = 1,
208 0 : .buf = out_buf,
209 : },
210 0 : {
211 0 : .addr = dvo->slave_addr,
212 : .flags = I2C_M_RD | I2C_M_NOSTART,
213 : .len = 2,
214 0 : .buf = in_buf,
215 : }
216 : };
217 :
218 0 : out_buf[0] = addr;
219 :
220 0 : if (i2c_transfer(adapter, msgs, 3) == 3) {
221 0 : *data = (in_buf[1] << 8) | in_buf[0];
222 0 : return true;
223 : }
224 :
225 0 : if (!priv->quiet) {
226 : DRM_DEBUG_KMS("Unable to read register 0x%02x from "
227 : "%s:%02x.\n",
228 : addr, adapter->name, dvo->slave_addr);
229 : }
230 0 : return false;
231 0 : }
232 :
233 : /** Writes a 16-bit register on the ivch */
234 0 : static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
235 : {
236 0 : struct ivch_priv *priv = dvo->dev_priv;
237 0 : struct i2c_adapter *adapter = dvo->i2c_bus;
238 0 : u8 out_buf[3];
239 0 : struct i2c_msg msg = {
240 0 : .addr = dvo->slave_addr,
241 : .flags = 0,
242 : .len = 3,
243 0 : .buf = out_buf,
244 : };
245 :
246 0 : out_buf[0] = addr;
247 0 : out_buf[1] = data & 0xff;
248 0 : out_buf[2] = data >> 8;
249 :
250 0 : if (i2c_transfer(adapter, &msg, 1) == 1)
251 0 : return true;
252 :
253 0 : if (!priv->quiet) {
254 : DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
255 : addr, adapter->name, dvo->slave_addr);
256 : }
257 :
258 0 : return false;
259 0 : }
260 :
261 : /** Probes the given bus and slave address for an ivch */
262 0 : static bool ivch_init(struct intel_dvo_device *dvo,
263 : struct i2c_adapter *adapter)
264 : {
265 : struct ivch_priv *priv;
266 0 : uint16_t temp;
267 : int i;
268 :
269 0 : priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
270 0 : if (priv == NULL)
271 0 : return false;
272 :
273 0 : dvo->i2c_bus = adapter;
274 0 : dvo->dev_priv = priv;
275 0 : priv->quiet = true;
276 :
277 0 : if (!ivch_read(dvo, VR00, &temp))
278 : goto out;
279 0 : priv->quiet = false;
280 :
281 : /* Since the identification bits are probably zeroes, which doesn't seem
282 : * very unique, check that the value in the base address field matches
283 : * the address it's responding on.
284 : */
285 0 : if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
286 : DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
287 : "(%d vs %d)\n",
288 : (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
289 : goto out;
290 : }
291 :
292 0 : ivch_read(dvo, VR20, &priv->width);
293 0 : ivch_read(dvo, VR21, &priv->height);
294 :
295 : /* Make a backup of the registers to be able to restore them
296 : * upon suspend.
297 : */
298 0 : for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
299 0 : ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
300 :
301 0 : ivch_dump_regs(dvo);
302 :
303 0 : return true;
304 :
305 : out:
306 0 : kfree(priv);
307 0 : return false;
308 0 : }
309 :
310 0 : static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
311 : {
312 0 : return connector_status_connected;
313 : }
314 :
315 0 : static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
316 : struct drm_display_mode *mode)
317 : {
318 0 : if (mode->clock > 112000)
319 0 : return MODE_CLOCK_HIGH;
320 :
321 0 : return MODE_OK;
322 0 : }
323 :
324 : /* Restore the DVO registers after a resume
325 : * from RAM. Registers have been saved during
326 : * the initialization.
327 : */
328 0 : static void ivch_reset(struct intel_dvo_device *dvo)
329 : {
330 0 : struct ivch_priv *priv = dvo->dev_priv;
331 : int i;
332 :
333 : DRM_DEBUG_KMS("Resetting the IVCH registers\n");
334 :
335 0 : ivch_write(dvo, VR10, 0x0000);
336 :
337 0 : for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
338 0 : ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
339 0 : }
340 :
341 : /** Sets the power state of the panel connected to the ivch */
342 0 : static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
343 : {
344 : int i;
345 0 : uint16_t vr01, vr30, backlight;
346 :
347 0 : ivch_reset(dvo);
348 :
349 : /* Set the new power state of the panel. */
350 0 : if (!ivch_read(dvo, VR01, &vr01))
351 0 : return;
352 :
353 0 : if (enable)
354 0 : backlight = 1;
355 : else
356 : backlight = 0;
357 :
358 0 : ivch_write(dvo, VR80, backlight);
359 :
360 0 : if (enable)
361 0 : vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
362 : else
363 0 : vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
364 :
365 0 : ivch_write(dvo, VR01, vr01);
366 :
367 : /* Wait for the panel to make its state transition */
368 0 : for (i = 0; i < 100; i++) {
369 0 : if (!ivch_read(dvo, VR30, &vr30))
370 : break;
371 :
372 0 : if (((vr30 & VR30_PANEL_ON) != 0) == enable)
373 : break;
374 0 : udelay(1000);
375 : }
376 : /* wait some more; vch may fail to resync sometimes without this */
377 0 : udelay(16 * 1000);
378 0 : }
379 :
380 0 : static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
381 : {
382 0 : uint16_t vr01;
383 :
384 0 : ivch_reset(dvo);
385 :
386 : /* Set the new power state of the panel. */
387 0 : if (!ivch_read(dvo, VR01, &vr01))
388 0 : return false;
389 :
390 0 : if (vr01 & VR01_LCD_ENABLE)
391 0 : return true;
392 : else
393 0 : return false;
394 0 : }
395 :
396 0 : static void ivch_mode_set(struct intel_dvo_device *dvo,
397 : const struct drm_display_mode *mode,
398 : const struct drm_display_mode *adjusted_mode)
399 : {
400 0 : struct ivch_priv *priv = dvo->dev_priv;
401 : uint16_t vr40 = 0;
402 : uint16_t vr01 = 0;
403 : uint16_t vr10;
404 :
405 0 : ivch_reset(dvo);
406 :
407 0 : vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
408 :
409 : /* Enable dithering for 18 bpp pipelines */
410 0 : vr10 &= VR10_INTERFACE_DEPTH_MASK;
411 0 : if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
412 0 : vr01 = VR01_DITHER_ENABLE;
413 :
414 : vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
415 : VR40_HORIZONTAL_INTERP_ENABLE);
416 :
417 0 : if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
418 0 : mode->vdisplay != adjusted_mode->crtc_vdisplay) {
419 : uint16_t x_ratio, y_ratio;
420 :
421 0 : vr01 |= VR01_PANEL_FIT_ENABLE;
422 : vr40 |= VR40_CLOCK_GATING_ENABLE;
423 0 : x_ratio = (((mode->hdisplay - 1) << 16) /
424 0 : (adjusted_mode->crtc_hdisplay - 1)) >> 2;
425 0 : y_ratio = (((mode->vdisplay - 1) << 16) /
426 0 : (adjusted_mode->crtc_vdisplay - 1)) >> 2;
427 0 : ivch_write(dvo, VR42, x_ratio);
428 0 : ivch_write(dvo, VR41, y_ratio);
429 0 : } else {
430 0 : vr01 &= ~VR01_PANEL_FIT_ENABLE;
431 : vr40 &= ~VR40_CLOCK_GATING_ENABLE;
432 : }
433 0 : vr40 &= ~VR40_AUTO_RATIO_ENABLE;
434 :
435 0 : ivch_write(dvo, VR01, vr01);
436 0 : ivch_write(dvo, VR40, vr40);
437 0 : }
438 :
439 0 : static void ivch_dump_regs(struct intel_dvo_device *dvo)
440 : {
441 0 : uint16_t val;
442 :
443 0 : ivch_read(dvo, VR00, &val);
444 : DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
445 0 : ivch_read(dvo, VR01, &val);
446 : DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
447 0 : ivch_read(dvo, VR10, &val);
448 : DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
449 0 : ivch_read(dvo, VR30, &val);
450 : DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
451 0 : ivch_read(dvo, VR40, &val);
452 : DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
453 :
454 : /* GPIO registers */
455 0 : ivch_read(dvo, VR80, &val);
456 : DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
457 0 : ivch_read(dvo, VR81, &val);
458 : DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
459 0 : ivch_read(dvo, VR82, &val);
460 : DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
461 0 : ivch_read(dvo, VR83, &val);
462 : DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
463 0 : ivch_read(dvo, VR84, &val);
464 : DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
465 0 : ivch_read(dvo, VR85, &val);
466 : DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
467 0 : ivch_read(dvo, VR86, &val);
468 : DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
469 0 : ivch_read(dvo, VR87, &val);
470 : DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
471 0 : ivch_read(dvo, VR88, &val);
472 : DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
473 :
474 : /* Scratch register 0 - AIM Panel type */
475 0 : ivch_read(dvo, VR8E, &val);
476 : DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
477 :
478 : /* Scratch register 1 - Status register */
479 0 : ivch_read(dvo, VR8F, &val);
480 : DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
481 0 : }
482 :
483 0 : static void ivch_destroy(struct intel_dvo_device *dvo)
484 : {
485 0 : struct ivch_priv *priv = dvo->dev_priv;
486 :
487 0 : if (priv) {
488 0 : kfree(priv);
489 0 : dvo->dev_priv = NULL;
490 0 : }
491 0 : }
492 :
493 : struct intel_dvo_dev_ops ivch_ops = {
494 : .init = ivch_init,
495 : .dpms = ivch_dpms,
496 : .get_hw_state = ivch_get_hw_state,
497 : .mode_valid = ivch_mode_valid,
498 : .mode_set = ivch_mode_set,
499 : .detect = ivch_detect,
500 : .dump_regs = ivch_dump_regs,
501 : .destroy = ivch_destroy,
502 : };
|