xref: /linux/drivers/gpu/drm/i915/display/dvo_ivch.c (revision cd1f0d3d)
1379bc100SJani Nikula /*
2379bc100SJani Nikula  * Copyright © 2006 Intel Corporation
3379bc100SJani Nikula  *
4379bc100SJani Nikula  * Permission is hereby granted, free of charge, to any person obtaining a
5379bc100SJani Nikula  * copy of this software and associated documentation files (the "Software"),
6379bc100SJani Nikula  * to deal in the Software without restriction, including without limitation
7379bc100SJani Nikula  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8379bc100SJani Nikula  * and/or sell copies of the Software, and to permit persons to whom the
9379bc100SJani Nikula  * Software is furnished to do so, subject to the following conditions:
10379bc100SJani Nikula  *
11379bc100SJani Nikula  * The above copyright notice and this permission notice (including the next
12379bc100SJani Nikula  * paragraph) shall be included in all copies or substantial portions of the
13379bc100SJani Nikula  * Software.
14379bc100SJani Nikula  *
15379bc100SJani Nikula  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16379bc100SJani Nikula  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17379bc100SJani Nikula  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18379bc100SJani Nikula  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19379bc100SJani Nikula  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20379bc100SJani Nikula  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21379bc100SJani Nikula  * DEALINGS IN THE SOFTWARE.
22379bc100SJani Nikula  *
23379bc100SJani Nikula  * Authors:
24379bc100SJani Nikula  *    Eric Anholt <eric@anholt.net>
25379bc100SJani Nikula  *    Thomas Richter <thor@math.tu-berlin.de>
26379bc100SJani Nikula  *
27379bc100SJani Nikula  * Minor modifications (Dithering enable):
28379bc100SJani Nikula  *    Thomas Richter <thor@math.tu-berlin.de>
29379bc100SJani Nikula  *
30379bc100SJani Nikula  */
31379bc100SJani Nikula 
321d455f8dSJani Nikula #include "intel_display_types.h"
33379bc100SJani Nikula #include "intel_dvo_dev.h"
34379bc100SJani Nikula 
35379bc100SJani Nikula /*
36379bc100SJani Nikula  * register definitions for the i82807aa.
37379bc100SJani Nikula  *
38379bc100SJani Nikula  * Documentation on this chipset can be found in datasheet #29069001 at
39379bc100SJani Nikula  * intel.com.
40379bc100SJani Nikula  */
41379bc100SJani Nikula 
42379bc100SJani Nikula /*
43379bc100SJani Nikula  * VCH Revision & GMBus Base Addr
44379bc100SJani Nikula  */
45379bc100SJani Nikula #define VR00		0x00
46379bc100SJani Nikula # define VR00_BASE_ADDRESS_MASK		0x007f
47379bc100SJani Nikula 
48379bc100SJani Nikula /*
49379bc100SJani Nikula  * Functionality Enable
50379bc100SJani Nikula  */
51379bc100SJani Nikula #define VR01		0x01
52379bc100SJani Nikula 
53379bc100SJani Nikula /*
54379bc100SJani Nikula  * Enable the panel fitter
55379bc100SJani Nikula  */
56379bc100SJani Nikula # define VR01_PANEL_FIT_ENABLE		(1 << 3)
57379bc100SJani Nikula /*
58379bc100SJani Nikula  * Enables the LCD display.
59379bc100SJani Nikula  *
60379bc100SJani Nikula  * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
61379bc100SJani Nikula  */
62379bc100SJani Nikula # define VR01_LCD_ENABLE		(1 << 2)
63379bc100SJani Nikula /* Enables the DVO repeater. */
64379bc100SJani Nikula # define VR01_DVO_BYPASS_ENABLE		(1 << 1)
65379bc100SJani Nikula /* Enables the DVO clock */
66379bc100SJani Nikula # define VR01_DVO_ENABLE		(1 << 0)
67379bc100SJani Nikula /* Enable dithering for 18bpp panels. Not documented. */
68379bc100SJani Nikula # define VR01_DITHER_ENABLE             (1 << 4)
69379bc100SJani Nikula 
70379bc100SJani Nikula /*
71379bc100SJani Nikula  * LCD Interface Format
72379bc100SJani Nikula  */
73379bc100SJani Nikula #define VR10		0x10
74379bc100SJani Nikula /* Enables LVDS output instead of CMOS */
75379bc100SJani Nikula # define VR10_LVDS_ENABLE		(1 << 4)
76379bc100SJani Nikula /* Enables 18-bit LVDS output. */
77379bc100SJani Nikula # define VR10_INTERFACE_1X18		(0 << 2)
78379bc100SJani Nikula /* Enables 24-bit LVDS or CMOS output */
79379bc100SJani Nikula # define VR10_INTERFACE_1X24		(1 << 2)
80379bc100SJani Nikula /* Enables 2x18-bit LVDS or CMOS output. */
81379bc100SJani Nikula # define VR10_INTERFACE_2X18		(2 << 2)
82379bc100SJani Nikula /* Enables 2x24-bit LVDS output */
83379bc100SJani Nikula # define VR10_INTERFACE_2X24		(3 << 2)
84379bc100SJani Nikula /* Mask that defines the depth of the pipeline */
85379bc100SJani Nikula # define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
86379bc100SJani Nikula 
87379bc100SJani Nikula /*
88379bc100SJani Nikula  * VR20 LCD Horizontal Display Size
89379bc100SJani Nikula  */
90379bc100SJani Nikula #define VR20	0x20
91379bc100SJani Nikula 
92379bc100SJani Nikula /*
93379bc100SJani Nikula  * LCD Vertical Display Size
94379bc100SJani Nikula  */
95379bc100SJani Nikula #define VR21	0x21
96379bc100SJani Nikula 
97379bc100SJani Nikula /*
98379bc100SJani Nikula  * Panel power down status
99379bc100SJani Nikula  */
100379bc100SJani Nikula #define VR30		0x30
101379bc100SJani Nikula /* Read only bit indicating that the panel is not in a safe poweroff state. */
102379bc100SJani Nikula # define VR30_PANEL_ON			(1 << 15)
103379bc100SJani Nikula 
104379bc100SJani Nikula #define VR40		0x40
105379bc100SJani Nikula # define VR40_STALL_ENABLE		(1 << 13)
106379bc100SJani Nikula # define VR40_VERTICAL_INTERP_ENABLE	(1 << 12)
107379bc100SJani Nikula # define VR40_ENHANCED_PANEL_FITTING	(1 << 11)
108379bc100SJani Nikula # define VR40_HORIZONTAL_INTERP_ENABLE	(1 << 10)
109379bc100SJani Nikula # define VR40_AUTO_RATIO_ENABLE		(1 << 9)
110379bc100SJani Nikula # define VR40_CLOCK_GATING_ENABLE	(1 << 8)
111379bc100SJani Nikula 
112379bc100SJani Nikula /*
113379bc100SJani Nikula  * Panel Fitting Vertical Ratio
114379bc100SJani Nikula  * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
115379bc100SJani Nikula  */
116379bc100SJani Nikula #define VR41		0x41
117379bc100SJani Nikula 
118379bc100SJani Nikula /*
119379bc100SJani Nikula  * Panel Fitting Horizontal Ratio
120379bc100SJani Nikula  * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
121379bc100SJani Nikula  */
122379bc100SJani Nikula #define VR42		0x42
123379bc100SJani Nikula 
124379bc100SJani Nikula /*
125379bc100SJani Nikula  * Horizontal Image Size
126379bc100SJani Nikula  */
127379bc100SJani Nikula #define VR43		0x43
128379bc100SJani Nikula 
129379bc100SJani Nikula /* VR80 GPIO 0
130379bc100SJani Nikula  */
131379bc100SJani Nikula #define VR80	    0x80
132379bc100SJani Nikula #define VR81	    0x81
133379bc100SJani Nikula #define VR82	    0x82
134379bc100SJani Nikula #define VR83	    0x83
135379bc100SJani Nikula #define VR84	    0x84
136379bc100SJani Nikula #define VR85	    0x85
137379bc100SJani Nikula #define VR86	    0x86
138379bc100SJani Nikula #define VR87	    0x87
139379bc100SJani Nikula 
140379bc100SJani Nikula /* VR88 GPIO 8
141379bc100SJani Nikula  */
142379bc100SJani Nikula #define VR88	    0x88
143379bc100SJani Nikula 
144379bc100SJani Nikula /* Graphics BIOS scratch 0
145379bc100SJani Nikula  */
146379bc100SJani Nikula #define VR8E	    0x8E
147379bc100SJani Nikula # define VR8E_PANEL_TYPE_MASK		(0xf << 0)
148379bc100SJani Nikula # define VR8E_PANEL_INTERFACE_CMOS	(0 << 4)
149379bc100SJani Nikula # define VR8E_PANEL_INTERFACE_LVDS	(1 << 4)
150379bc100SJani Nikula # define VR8E_FORCE_DEFAULT_PANEL	(1 << 5)
151379bc100SJani Nikula 
152379bc100SJani Nikula /* Graphics BIOS scratch 1
153379bc100SJani Nikula  */
154379bc100SJani Nikula #define VR8F	    0x8F
155379bc100SJani Nikula # define VR8F_VCH_PRESENT		(1 << 0)
156379bc100SJani Nikula # define VR8F_DISPLAY_CONN		(1 << 1)
157379bc100SJani Nikula # define VR8F_POWER_MASK		(0x3c)
158379bc100SJani Nikula # define VR8F_POWER_POS			(2)
159379bc100SJani Nikula 
160379bc100SJani Nikula /* Some Bios implementations do not restore the DVO state upon
161379bc100SJani Nikula  * resume from standby. Thus, this driver has to handle it
162379bc100SJani Nikula  * instead. The following list contains all registers that
163379bc100SJani Nikula  * require saving.
164379bc100SJani Nikula  */
165379bc100SJani Nikula static const u16 backup_addresses[] = {
166379bc100SJani Nikula 	0x11, 0x12,
167379bc100SJani Nikula 	0x18, 0x19, 0x1a, 0x1f,
168379bc100SJani Nikula 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
169379bc100SJani Nikula 	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
170379bc100SJani Nikula 	0x8e, 0x8f,
171379bc100SJani Nikula 	0x10		/* this must come last */
172379bc100SJani Nikula };
173379bc100SJani Nikula 
174379bc100SJani Nikula 
175379bc100SJani Nikula struct ivch_priv {
176379bc100SJani Nikula 	bool quiet;
177379bc100SJani Nikula 
178379bc100SJani Nikula 	u16 width, height;
179379bc100SJani Nikula 
180379bc100SJani Nikula 	/* Register backup */
181379bc100SJani Nikula 
182379bc100SJani Nikula 	u16 reg_backup[ARRAY_SIZE(backup_addresses)];
183379bc100SJani Nikula };
184379bc100SJani Nikula 
185379bc100SJani Nikula 
186379bc100SJani Nikula static void ivch_dump_regs(struct intel_dvo_device *dvo);
187379bc100SJani Nikula /*
188379bc100SJani Nikula  * Reads a register on the ivch.
189379bc100SJani Nikula  *
190379bc100SJani Nikula  * Each of the 256 registers are 16 bits long.
191379bc100SJani Nikula  */
ivch_read(struct intel_dvo_device * dvo,int addr,u16 * data)192379bc100SJani Nikula static bool ivch_read(struct intel_dvo_device *dvo, int addr, u16 *data)
193379bc100SJani Nikula {
194379bc100SJani Nikula 	struct ivch_priv *priv = dvo->dev_priv;
195379bc100SJani Nikula 	struct i2c_adapter *adapter = dvo->i2c_bus;
196379bc100SJani Nikula 	u8 out_buf[1];
197379bc100SJani Nikula 	u8 in_buf[2];
198379bc100SJani Nikula 
199379bc100SJani Nikula 	struct i2c_msg msgs[] = {
200379bc100SJani Nikula 		{
201379bc100SJani Nikula 			.addr = dvo->slave_addr,
202379bc100SJani Nikula 			.flags = I2C_M_RD,
203379bc100SJani Nikula 			.len = 0,
204379bc100SJani Nikula 		},
205379bc100SJani Nikula 		{
206379bc100SJani Nikula 			.addr = 0,
207379bc100SJani Nikula 			.flags = I2C_M_NOSTART,
208379bc100SJani Nikula 			.len = 1,
209379bc100SJani Nikula 			.buf = out_buf,
210379bc100SJani Nikula 		},
211379bc100SJani Nikula 		{
212379bc100SJani Nikula 			.addr = dvo->slave_addr,
213379bc100SJani Nikula 			.flags = I2C_M_RD | I2C_M_NOSTART,
214379bc100SJani Nikula 			.len = 2,
215379bc100SJani Nikula 			.buf = in_buf,
216379bc100SJani Nikula 		}
217379bc100SJani Nikula 	};
218379bc100SJani Nikula 
219379bc100SJani Nikula 	out_buf[0] = addr;
220379bc100SJani Nikula 
221379bc100SJani Nikula 	if (i2c_transfer(adapter, msgs, 3) == 3) {
222379bc100SJani Nikula 		*data = (in_buf[1] << 8) | in_buf[0];
223379bc100SJani Nikula 		return true;
224379bc100SJani Nikula 	}
225379bc100SJani Nikula 
226379bc100SJani Nikula 	if (!priv->quiet) {
227379bc100SJani Nikula 		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
228379bc100SJani Nikula 				"%s:%02x.\n",
229379bc100SJani Nikula 			  addr, adapter->name, dvo->slave_addr);
230379bc100SJani Nikula 	}
231379bc100SJani Nikula 	return false;
232379bc100SJani Nikula }
233379bc100SJani Nikula 
234379bc100SJani Nikula /* Writes a 16-bit register on the ivch */
ivch_write(struct intel_dvo_device * dvo,int addr,u16 data)235379bc100SJani Nikula static bool ivch_write(struct intel_dvo_device *dvo, int addr, u16 data)
236379bc100SJani Nikula {
237379bc100SJani Nikula 	struct ivch_priv *priv = dvo->dev_priv;
238379bc100SJani Nikula 	struct i2c_adapter *adapter = dvo->i2c_bus;
239379bc100SJani Nikula 	u8 out_buf[3];
240379bc100SJani Nikula 	struct i2c_msg msg = {
241379bc100SJani Nikula 		.addr = dvo->slave_addr,
242379bc100SJani Nikula 		.flags = 0,
243379bc100SJani Nikula 		.len = 3,
244379bc100SJani Nikula 		.buf = out_buf,
245379bc100SJani Nikula 	};
246379bc100SJani Nikula 
247379bc100SJani Nikula 	out_buf[0] = addr;
248379bc100SJani Nikula 	out_buf[1] = data & 0xff;
249379bc100SJani Nikula 	out_buf[2] = data >> 8;
250379bc100SJani Nikula 
251379bc100SJani Nikula 	if (i2c_transfer(adapter, &msg, 1) == 1)
252379bc100SJani Nikula 		return true;
253379bc100SJani Nikula 
254379bc100SJani Nikula 	if (!priv->quiet) {
255379bc100SJani Nikula 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
256379bc100SJani Nikula 			  addr, adapter->name, dvo->slave_addr);
257379bc100SJani Nikula 	}
258379bc100SJani Nikula 
259379bc100SJani Nikula 	return false;
260379bc100SJani Nikula }
261379bc100SJani Nikula 
262379bc100SJani Nikula /* Probes the given bus and slave address for an ivch */
ivch_init(struct intel_dvo_device * dvo,struct i2c_adapter * adapter)263379bc100SJani Nikula static bool ivch_init(struct intel_dvo_device *dvo,
264379bc100SJani Nikula 		      struct i2c_adapter *adapter)
265379bc100SJani Nikula {
266379bc100SJani Nikula 	struct ivch_priv *priv;
267379bc100SJani Nikula 	u16 temp;
268379bc100SJani Nikula 	int i;
269379bc100SJani Nikula 
270*cd1f0d3dSVille Syrjälä 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
271379bc100SJani Nikula 	if (priv == NULL)
272379bc100SJani Nikula 		return false;
273379bc100SJani Nikula 
274379bc100SJani Nikula 	dvo->i2c_bus = adapter;
275379bc100SJani Nikula 	dvo->dev_priv = priv;
276379bc100SJani Nikula 	priv->quiet = true;
277379bc100SJani Nikula 
278379bc100SJani Nikula 	if (!ivch_read(dvo, VR00, &temp))
279379bc100SJani Nikula 		goto out;
280379bc100SJani Nikula 	priv->quiet = false;
281379bc100SJani Nikula 
282379bc100SJani Nikula 	/* Since the identification bits are probably zeroes, which doesn't seem
283379bc100SJani Nikula 	 * very unique, check that the value in the base address field matches
284379bc100SJani Nikula 	 * the address it's responding on.
285379bc100SJani Nikula 	 */
286379bc100SJani Nikula 	if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
287379bc100SJani Nikula 		DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
288379bc100SJani Nikula 			  "(%d vs %d)\n",
289379bc100SJani Nikula 			  (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
290379bc100SJani Nikula 		goto out;
291379bc100SJani Nikula 	}
292379bc100SJani Nikula 
293379bc100SJani Nikula 	ivch_read(dvo, VR20, &priv->width);
294379bc100SJani Nikula 	ivch_read(dvo, VR21, &priv->height);
295379bc100SJani Nikula 
296379bc100SJani Nikula 	/* Make a backup of the registers to be able to restore them
297379bc100SJani Nikula 	 * upon suspend.
298379bc100SJani Nikula 	 */
299379bc100SJani Nikula 	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
300379bc100SJani Nikula 		ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
301379bc100SJani Nikula 
302379bc100SJani Nikula 	ivch_dump_regs(dvo);
303379bc100SJani Nikula 
304379bc100SJani Nikula 	return true;
305379bc100SJani Nikula 
306379bc100SJani Nikula out:
307379bc100SJani Nikula 	kfree(priv);
308379bc100SJani Nikula 	return false;
309379bc100SJani Nikula }
310379bc100SJani Nikula 
ivch_detect(struct intel_dvo_device * dvo)311379bc100SJani Nikula static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
312379bc100SJani Nikula {
313379bc100SJani Nikula 	return connector_status_connected;
314379bc100SJani Nikula }
315379bc100SJani Nikula 
ivch_mode_valid(struct intel_dvo_device * dvo,struct drm_display_mode * mode)316379bc100SJani Nikula static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
317379bc100SJani Nikula 					    struct drm_display_mode *mode)
318379bc100SJani Nikula {
319379bc100SJani Nikula 	if (mode->clock > 112000)
320379bc100SJani Nikula 		return MODE_CLOCK_HIGH;
321379bc100SJani Nikula 
322379bc100SJani Nikula 	return MODE_OK;
323379bc100SJani Nikula }
324379bc100SJani Nikula 
325379bc100SJani Nikula /* Restore the DVO registers after a resume
326379bc100SJani Nikula  * from RAM. Registers have been saved during
327379bc100SJani Nikula  * the initialization.
328379bc100SJani Nikula  */
ivch_reset(struct intel_dvo_device * dvo)329379bc100SJani Nikula static void ivch_reset(struct intel_dvo_device *dvo)
330379bc100SJani Nikula {
331379bc100SJani Nikula 	struct ivch_priv *priv = dvo->dev_priv;
332379bc100SJani Nikula 	int i;
333379bc100SJani Nikula 
334379bc100SJani Nikula 	DRM_DEBUG_KMS("Resetting the IVCH registers\n");
335379bc100SJani Nikula 
336379bc100SJani Nikula 	ivch_write(dvo, VR10, 0x0000);
337379bc100SJani Nikula 
338379bc100SJani Nikula 	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
339379bc100SJani Nikula 		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
340379bc100SJani Nikula }
341379bc100SJani Nikula 
342379bc100SJani Nikula /* Sets the power state of the panel connected to the ivch */
ivch_dpms(struct intel_dvo_device * dvo,bool enable)343379bc100SJani Nikula static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
344379bc100SJani Nikula {
345379bc100SJani Nikula 	int i;
346379bc100SJani Nikula 	u16 vr01, vr30, backlight;
347379bc100SJani Nikula 
348379bc100SJani Nikula 	ivch_reset(dvo);
349379bc100SJani Nikula 
350379bc100SJani Nikula 	/* Set the new power state of the panel. */
351379bc100SJani Nikula 	if (!ivch_read(dvo, VR01, &vr01))
352379bc100SJani Nikula 		return;
353379bc100SJani Nikula 
354379bc100SJani Nikula 	if (enable)
355379bc100SJani Nikula 		backlight = 1;
356379bc100SJani Nikula 	else
357379bc100SJani Nikula 		backlight = 0;
358379bc100SJani Nikula 
359379bc100SJani Nikula 	ivch_write(dvo, VR80, backlight);
360379bc100SJani Nikula 
361379bc100SJani Nikula 	if (enable)
362379bc100SJani Nikula 		vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
363379bc100SJani Nikula 	else
364379bc100SJani Nikula 		vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
365379bc100SJani Nikula 
366379bc100SJani Nikula 	ivch_write(dvo, VR01, vr01);
367379bc100SJani Nikula 
368379bc100SJani Nikula 	/* Wait for the panel to make its state transition */
369379bc100SJani Nikula 	for (i = 0; i < 100; i++) {
370379bc100SJani Nikula 		if (!ivch_read(dvo, VR30, &vr30))
371379bc100SJani Nikula 			break;
372379bc100SJani Nikula 
373379bc100SJani Nikula 		if (((vr30 & VR30_PANEL_ON) != 0) == enable)
374379bc100SJani Nikula 			break;
375379bc100SJani Nikula 		udelay(1000);
376379bc100SJani Nikula 	}
377379bc100SJani Nikula 	/* wait some more; vch may fail to resync sometimes without this */
378379bc100SJani Nikula 	udelay(16 * 1000);
379379bc100SJani Nikula }
380379bc100SJani Nikula 
ivch_get_hw_state(struct intel_dvo_device * dvo)381379bc100SJani Nikula static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
382379bc100SJani Nikula {
383379bc100SJani Nikula 	u16 vr01;
384379bc100SJani Nikula 
385379bc100SJani Nikula 	ivch_reset(dvo);
386379bc100SJani Nikula 
387379bc100SJani Nikula 	/* Set the new power state of the panel. */
388379bc100SJani Nikula 	if (!ivch_read(dvo, VR01, &vr01))
389379bc100SJani Nikula 		return false;
390379bc100SJani Nikula 
391379bc100SJani Nikula 	if (vr01 & VR01_LCD_ENABLE)
392379bc100SJani Nikula 		return true;
393379bc100SJani Nikula 	else
394379bc100SJani Nikula 		return false;
395379bc100SJani Nikula }
396379bc100SJani Nikula 
ivch_mode_set(struct intel_dvo_device * dvo,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)397379bc100SJani Nikula static void ivch_mode_set(struct intel_dvo_device *dvo,
398379bc100SJani Nikula 			  const struct drm_display_mode *mode,
399379bc100SJani Nikula 			  const struct drm_display_mode *adjusted_mode)
400379bc100SJani Nikula {
401379bc100SJani Nikula 	struct ivch_priv *priv = dvo->dev_priv;
402379bc100SJani Nikula 	u16 vr40 = 0;
403379bc100SJani Nikula 	u16 vr01 = 0;
404379bc100SJani Nikula 	u16 vr10;
405379bc100SJani Nikula 
406379bc100SJani Nikula 	ivch_reset(dvo);
407379bc100SJani Nikula 
408379bc100SJani Nikula 	vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
409379bc100SJani Nikula 
410379bc100SJani Nikula 	/* Enable dithering for 18 bpp pipelines */
411379bc100SJani Nikula 	vr10 &= VR10_INTERFACE_DEPTH_MASK;
412379bc100SJani Nikula 	if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
413379bc100SJani Nikula 		vr01 = VR01_DITHER_ENABLE;
414379bc100SJani Nikula 
415379bc100SJani Nikula 	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
416379bc100SJani Nikula 		VR40_HORIZONTAL_INTERP_ENABLE);
417379bc100SJani Nikula 
418379bc100SJani Nikula 	if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
419379bc100SJani Nikula 	    mode->vdisplay != adjusted_mode->crtc_vdisplay) {
420379bc100SJani Nikula 		u16 x_ratio, y_ratio;
421379bc100SJani Nikula 
422379bc100SJani Nikula 		vr01 |= VR01_PANEL_FIT_ENABLE;
423379bc100SJani Nikula 		vr40 |= VR40_CLOCK_GATING_ENABLE;
424379bc100SJani Nikula 		x_ratio = (((mode->hdisplay - 1) << 16) /
425379bc100SJani Nikula 			   (adjusted_mode->crtc_hdisplay - 1)) >> 2;
426379bc100SJani Nikula 		y_ratio = (((mode->vdisplay - 1) << 16) /
427379bc100SJani Nikula 			   (adjusted_mode->crtc_vdisplay - 1)) >> 2;
428379bc100SJani Nikula 		ivch_write(dvo, VR42, x_ratio);
429379bc100SJani Nikula 		ivch_write(dvo, VR41, y_ratio);
430379bc100SJani Nikula 	} else {
431379bc100SJani Nikula 		vr01 &= ~VR01_PANEL_FIT_ENABLE;
432379bc100SJani Nikula 		vr40 &= ~VR40_CLOCK_GATING_ENABLE;
433379bc100SJani Nikula 	}
434379bc100SJani Nikula 	vr40 &= ~VR40_AUTO_RATIO_ENABLE;
435379bc100SJani Nikula 
436379bc100SJani Nikula 	ivch_write(dvo, VR01, vr01);
437379bc100SJani Nikula 	ivch_write(dvo, VR40, vr40);
438379bc100SJani Nikula }
439379bc100SJani Nikula 
ivch_dump_regs(struct intel_dvo_device * dvo)440379bc100SJani Nikula static void ivch_dump_regs(struct intel_dvo_device *dvo)
441379bc100SJani Nikula {
442379bc100SJani Nikula 	u16 val;
443379bc100SJani Nikula 
444379bc100SJani Nikula 	ivch_read(dvo, VR00, &val);
445379bc100SJani Nikula 	DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
446379bc100SJani Nikula 	ivch_read(dvo, VR01, &val);
447379bc100SJani Nikula 	DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
448379bc100SJani Nikula 	ivch_read(dvo, VR10, &val);
449379bc100SJani Nikula 	DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
450379bc100SJani Nikula 	ivch_read(dvo, VR30, &val);
451379bc100SJani Nikula 	DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
452379bc100SJani Nikula 	ivch_read(dvo, VR40, &val);
453379bc100SJani Nikula 	DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
454379bc100SJani Nikula 
455379bc100SJani Nikula 	/* GPIO registers */
456379bc100SJani Nikula 	ivch_read(dvo, VR80, &val);
457379bc100SJani Nikula 	DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
458379bc100SJani Nikula 	ivch_read(dvo, VR81, &val);
459379bc100SJani Nikula 	DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
460379bc100SJani Nikula 	ivch_read(dvo, VR82, &val);
461379bc100SJani Nikula 	DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
462379bc100SJani Nikula 	ivch_read(dvo, VR83, &val);
463379bc100SJani Nikula 	DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
464379bc100SJani Nikula 	ivch_read(dvo, VR84, &val);
465379bc100SJani Nikula 	DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
466379bc100SJani Nikula 	ivch_read(dvo, VR85, &val);
467379bc100SJani Nikula 	DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
468379bc100SJani Nikula 	ivch_read(dvo, VR86, &val);
469379bc100SJani Nikula 	DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
470379bc100SJani Nikula 	ivch_read(dvo, VR87, &val);
471379bc100SJani Nikula 	DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
472379bc100SJani Nikula 	ivch_read(dvo, VR88, &val);
473379bc100SJani Nikula 	DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
474379bc100SJani Nikula 
475379bc100SJani Nikula 	/* Scratch register 0 - AIM Panel type */
476379bc100SJani Nikula 	ivch_read(dvo, VR8E, &val);
477379bc100SJani Nikula 	DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
478379bc100SJani Nikula 
479379bc100SJani Nikula 	/* Scratch register 1 - Status register */
480379bc100SJani Nikula 	ivch_read(dvo, VR8F, &val);
481379bc100SJani Nikula 	DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
482379bc100SJani Nikula }
483379bc100SJani Nikula 
ivch_destroy(struct intel_dvo_device * dvo)484379bc100SJani Nikula static void ivch_destroy(struct intel_dvo_device *dvo)
485379bc100SJani Nikula {
486379bc100SJani Nikula 	struct ivch_priv *priv = dvo->dev_priv;
487379bc100SJani Nikula 
488379bc100SJani Nikula 	if (priv) {
489379bc100SJani Nikula 		kfree(priv);
490379bc100SJani Nikula 		dvo->dev_priv = NULL;
491379bc100SJani Nikula 	}
492379bc100SJani Nikula }
493379bc100SJani Nikula 
494379bc100SJani Nikula const struct intel_dvo_dev_ops ivch_ops = {
495379bc100SJani Nikula 	.init = ivch_init,
496379bc100SJani Nikula 	.dpms = ivch_dpms,
497379bc100SJani Nikula 	.get_hw_state = ivch_get_hw_state,
498379bc100SJani Nikula 	.mode_valid = ivch_mode_valid,
499379bc100SJani Nikula 	.mode_set = ivch_mode_set,
500379bc100SJani Nikula 	.detect = ivch_detect,
501379bc100SJani Nikula 	.dump_regs = ivch_dump_regs,
502379bc100SJani Nikula 	.destroy = ivch_destroy,
503379bc100SJani Nikula };
504