Subversion Repositories Kolibri OS

Rev

Rev 3031 | Rev 6084 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3031 Rev 5060
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
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
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
21
 * DEALINGS IN THE SOFTWARE.
22
 *
22
 *
23
 * Authors:
23
 * Authors:
24
 *    Eric Anholt 
24
 *    Eric Anholt 
25
 *
25
 *
26
 */
26
 */
27
 
27
 
28
#include "dvo.h"
28
#include "dvo.h"
29
 
29
 
30
/*
30
/*
31
 * register definitions for the i82807aa.
31
 * register definitions for the i82807aa.
32
 *
32
 *
33
 * Documentation on this chipset can be found in datasheet #29069001 at
33
 * Documentation on this chipset can be found in datasheet #29069001 at
34
 * intel.com.
34
 * intel.com.
35
 */
35
 */
36
 
36
 
37
/*
37
/*
38
 * VCH Revision & GMBus Base Addr
38
 * VCH Revision & GMBus Base Addr
39
 */
39
 */
40
#define VR00		0x00
40
#define VR00		0x00
41
# define VR00_BASE_ADDRESS_MASK		0x007f
41
# define VR00_BASE_ADDRESS_MASK		0x007f
42
 
42
 
43
/*
43
/*
44
 * Functionality Enable
44
 * Functionality Enable
45
 */
45
 */
46
#define VR01		0x01
46
#define VR01		0x01
47
 
47
 
48
/*
48
/*
49
 * Enable the panel fitter
49
 * Enable the panel fitter
50
 */
50
 */
51
# define VR01_PANEL_FIT_ENABLE		(1 << 3)
51
# define VR01_PANEL_FIT_ENABLE		(1 << 3)
52
/*
52
/*
53
 * Enables the LCD display.
53
 * Enables the LCD display.
54
 *
54
 *
55
 * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
55
 * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
56
 */
56
 */
57
# define VR01_LCD_ENABLE		(1 << 2)
57
# define VR01_LCD_ENABLE		(1 << 2)
58
/** Enables the DVO repeater. */
58
/** Enables the DVO repeater. */
59
# define VR01_DVO_BYPASS_ENABLE		(1 << 1)
59
# define VR01_DVO_BYPASS_ENABLE		(1 << 1)
60
/** Enables the DVO clock */
60
/** Enables the DVO clock */
61
# define VR01_DVO_ENABLE		(1 << 0)
61
# define VR01_DVO_ENABLE		(1 << 0)
62
 
62
 
63
/*
63
/*
64
 * LCD Interface Format
64
 * LCD Interface Format
65
 */
65
 */
66
#define VR10		0x10
66
#define VR10		0x10
67
/** Enables LVDS output instead of CMOS */
67
/** Enables LVDS output instead of CMOS */
68
# define VR10_LVDS_ENABLE		(1 << 4)
68
# define VR10_LVDS_ENABLE		(1 << 4)
69
/** Enables 18-bit LVDS output. */
69
/** Enables 18-bit LVDS output. */
70
# define VR10_INTERFACE_1X18		(0 << 2)
70
# define VR10_INTERFACE_1X18		(0 << 2)
71
/** Enables 24-bit LVDS or CMOS output */
71
/** Enables 24-bit LVDS or CMOS output */
72
# define VR10_INTERFACE_1X24		(1 << 2)
72
# define VR10_INTERFACE_1X24		(1 << 2)
73
/** Enables 2x18-bit LVDS or CMOS output. */
73
/** Enables 2x18-bit LVDS or CMOS output. */
74
# define VR10_INTERFACE_2X18		(2 << 2)
74
# define VR10_INTERFACE_2X18		(2 << 2)
75
/** Enables 2x24-bit LVDS output */
75
/** Enables 2x24-bit LVDS output */
76
# define VR10_INTERFACE_2X24		(3 << 2)
76
# define VR10_INTERFACE_2X24		(3 << 2)
77
 
77
 
78
/*
78
/*
79
 * VR20 LCD Horizontal Display Size
79
 * VR20 LCD Horizontal Display Size
80
 */
80
 */
81
#define VR20	0x20
81
#define VR20	0x20
82
 
82
 
83
/*
83
/*
84
 * LCD Vertical Display Size
84
 * LCD Vertical Display Size
85
 */
85
 */
86
#define VR21	0x20
86
#define VR21	0x20
87
 
87
 
88
/*
88
/*
89
 * Panel power down status
89
 * Panel power down status
90
 */
90
 */
91
#define VR30		0x30
91
#define VR30		0x30
92
/** Read only bit indicating that the panel is not in a safe poweroff state. */
92
/** Read only bit indicating that the panel is not in a safe poweroff state. */
93
# define VR30_PANEL_ON			(1 << 15)
93
# define VR30_PANEL_ON			(1 << 15)
94
 
94
 
95
#define VR40		0x40
95
#define VR40		0x40
96
# define VR40_STALL_ENABLE		(1 << 13)
96
# define VR40_STALL_ENABLE		(1 << 13)
97
# define VR40_VERTICAL_INTERP_ENABLE	(1 << 12)
97
# define VR40_VERTICAL_INTERP_ENABLE	(1 << 12)
98
# define VR40_ENHANCED_PANEL_FITTING	(1 << 11)
98
# define VR40_ENHANCED_PANEL_FITTING	(1 << 11)
99
# define VR40_HORIZONTAL_INTERP_ENABLE	(1 << 10)
99
# define VR40_HORIZONTAL_INTERP_ENABLE	(1 << 10)
100
# define VR40_AUTO_RATIO_ENABLE		(1 << 9)
100
# define VR40_AUTO_RATIO_ENABLE		(1 << 9)
101
# define VR40_CLOCK_GATING_ENABLE	(1 << 8)
101
# define VR40_CLOCK_GATING_ENABLE	(1 << 8)
102
 
102
 
103
/*
103
/*
104
 * Panel Fitting Vertical Ratio
104
 * Panel Fitting Vertical Ratio
105
 * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
105
 * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
106
 */
106
 */
107
#define VR41		0x41
107
#define VR41		0x41
108
 
108
 
109
/*
109
/*
110
 * Panel Fitting Horizontal Ratio
110
 * Panel Fitting Horizontal Ratio
111
 * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
111
 * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
112
 */
112
 */
113
#define VR42		0x42
113
#define VR42		0x42
114
 
114
 
115
/*
115
/*
116
 * Horizontal Image Size
116
 * Horizontal Image Size
117
 */
117
 */
118
#define VR43		0x43
118
#define VR43		0x43
119
 
119
 
120
/* VR80 GPIO 0
120
/* VR80 GPIO 0
121
 */
121
 */
122
#define VR80	    0x80
122
#define VR80	    0x80
123
#define VR81	    0x81
123
#define VR81	    0x81
124
#define VR82	    0x82
124
#define VR82	    0x82
125
#define VR83	    0x83
125
#define VR83	    0x83
126
#define VR84	    0x84
126
#define VR84	    0x84
127
#define VR85	    0x85
127
#define VR85	    0x85
128
#define VR86	    0x86
128
#define VR86	    0x86
129
#define VR87	    0x87
129
#define VR87	    0x87
130
 
130
 
131
/* VR88 GPIO 8
131
/* VR88 GPIO 8
132
 */
132
 */
133
#define VR88	    0x88
133
#define VR88	    0x88
134
 
134
 
135
/* Graphics BIOS scratch 0
135
/* Graphics BIOS scratch 0
136
 */
136
 */
137
#define VR8E	    0x8E
137
#define VR8E	    0x8E
138
# define VR8E_PANEL_TYPE_MASK		(0xf << 0)
138
# define VR8E_PANEL_TYPE_MASK		(0xf << 0)
139
# define VR8E_PANEL_INTERFACE_CMOS	(0 << 4)
139
# define VR8E_PANEL_INTERFACE_CMOS	(0 << 4)
140
# define VR8E_PANEL_INTERFACE_LVDS	(1 << 4)
140
# define VR8E_PANEL_INTERFACE_LVDS	(1 << 4)
141
# define VR8E_FORCE_DEFAULT_PANEL	(1 << 5)
141
# define VR8E_FORCE_DEFAULT_PANEL	(1 << 5)
142
 
142
 
143
/* Graphics BIOS scratch 1
143
/* Graphics BIOS scratch 1
144
 */
144
 */
145
#define VR8F	    0x8F
145
#define VR8F	    0x8F
146
# define VR8F_VCH_PRESENT		(1 << 0)
146
# define VR8F_VCH_PRESENT		(1 << 0)
147
# define VR8F_DISPLAY_CONN		(1 << 1)
147
# define VR8F_DISPLAY_CONN		(1 << 1)
148
# define VR8F_POWER_MASK		(0x3c)
148
# define VR8F_POWER_MASK		(0x3c)
149
# define VR8F_POWER_POS			(2)
149
# define VR8F_POWER_POS			(2)
150
 
150
 
151
 
151
 
152
struct ivch_priv {
152
struct ivch_priv {
153
	bool quiet;
153
	bool quiet;
154
 
154
 
155
	uint16_t width, height;
155
	uint16_t width, height;
156
};
156
};
157
 
157
 
158
 
158
 
159
static void ivch_dump_regs(struct intel_dvo_device *dvo);
159
static void ivch_dump_regs(struct intel_dvo_device *dvo);
160
 
160
 
161
/**
161
/**
162
 * Reads a register on the ivch.
162
 * Reads a register on the ivch.
163
 *
163
 *
164
 * Each of the 256 registers are 16 bits long.
164
 * Each of the 256 registers are 16 bits long.
165
 */
165
 */
166
static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
166
static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
167
{
167
{
168
	struct ivch_priv *priv = dvo->dev_priv;
168
	struct ivch_priv *priv = dvo->dev_priv;
169
	struct i2c_adapter *adapter = dvo->i2c_bus;
169
	struct i2c_adapter *adapter = dvo->i2c_bus;
170
	u8 out_buf[1];
170
	u8 out_buf[1];
171
	u8 in_buf[2];
171
	u8 in_buf[2];
172
 
172
 
173
	struct i2c_msg msgs[] = {
173
	struct i2c_msg msgs[] = {
174
		{
174
		{
175
			.addr = dvo->slave_addr,
175
			.addr = dvo->slave_addr,
176
			.flags = I2C_M_RD,
176
			.flags = I2C_M_RD,
177
			.len = 0,
177
			.len = 0,
178
		},
178
		},
179
		{
179
		{
180
			.addr = 0,
180
			.addr = 0,
181
			.flags = I2C_M_NOSTART,
181
			.flags = I2C_M_NOSTART,
182
			.len = 1,
182
			.len = 1,
183
			.buf = out_buf,
183
			.buf = out_buf,
184
		},
184
		},
185
		{
185
		{
186
			.addr = dvo->slave_addr,
186
			.addr = dvo->slave_addr,
187
			.flags = I2C_M_RD | I2C_M_NOSTART,
187
			.flags = I2C_M_RD | I2C_M_NOSTART,
188
			.len = 2,
188
			.len = 2,
189
			.buf = in_buf,
189
			.buf = in_buf,
190
		}
190
		}
191
	};
191
	};
192
 
192
 
193
	out_buf[0] = addr;
193
	out_buf[0] = addr;
194
 
194
 
195
	if (i2c_transfer(adapter, msgs, 3) == 3) {
195
	if (i2c_transfer(adapter, msgs, 3) == 3) {
196
		*data = (in_buf[1] << 8) | in_buf[0];
196
		*data = (in_buf[1] << 8) | in_buf[0];
197
		return true;
197
		return true;
198
	};
198
	}
199
 
199
 
200
	if (!priv->quiet) {
200
	if (!priv->quiet) {
201
		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
201
		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
202
				"%s:%02x.\n",
202
				"%s:%02x.\n",
203
			  addr, adapter->name, dvo->slave_addr);
203
			  addr, adapter->name, dvo->slave_addr);
204
	}
204
	}
205
	return false;
205
	return false;
206
}
206
}
207
 
207
 
208
/** Writes a 16-bit register on the ivch */
208
/** Writes a 16-bit register on the ivch */
209
static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
209
static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
210
{
210
{
211
	struct ivch_priv *priv = dvo->dev_priv;
211
	struct ivch_priv *priv = dvo->dev_priv;
212
	struct i2c_adapter *adapter = dvo->i2c_bus;
212
	struct i2c_adapter *adapter = dvo->i2c_bus;
213
	u8 out_buf[3];
213
	u8 out_buf[3];
214
	struct i2c_msg msg = {
214
	struct i2c_msg msg = {
215
		.addr = dvo->slave_addr,
215
		.addr = dvo->slave_addr,
216
		.flags = 0,
216
		.flags = 0,
217
		.len = 3,
217
		.len = 3,
218
		.buf = out_buf,
218
		.buf = out_buf,
219
	};
219
	};
220
 
220
 
221
	out_buf[0] = addr;
221
	out_buf[0] = addr;
222
	out_buf[1] = data & 0xff;
222
	out_buf[1] = data & 0xff;
223
	out_buf[2] = data >> 8;
223
	out_buf[2] = data >> 8;
224
 
224
 
225
	if (i2c_transfer(adapter, &msg, 1) == 1)
225
	if (i2c_transfer(adapter, &msg, 1) == 1)
226
		return true;
226
		return true;
227
 
227
 
228
	if (!priv->quiet) {
228
	if (!priv->quiet) {
229
		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
229
		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
230
			  addr, adapter->name, dvo->slave_addr);
230
			  addr, adapter->name, dvo->slave_addr);
231
	}
231
	}
232
 
232
 
233
	return false;
233
	return false;
234
}
234
}
235
 
235
 
236
/** Probes the given bus and slave address for an ivch */
236
/** Probes the given bus and slave address for an ivch */
237
static bool ivch_init(struct intel_dvo_device *dvo,
237
static bool ivch_init(struct intel_dvo_device *dvo,
238
		      struct i2c_adapter *adapter)
238
		      struct i2c_adapter *adapter)
239
{
239
{
240
	struct ivch_priv *priv;
240
	struct ivch_priv *priv;
241
	uint16_t temp;
241
	uint16_t temp;
242
 
242
 
243
	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
243
	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
244
	if (priv == NULL)
244
	if (priv == NULL)
245
		return false;
245
		return false;
246
 
246
 
247
	dvo->i2c_bus = adapter;
247
	dvo->i2c_bus = adapter;
248
	dvo->dev_priv = priv;
248
	dvo->dev_priv = priv;
249
	priv->quiet = true;
249
	priv->quiet = true;
250
 
250
 
251
	if (!ivch_read(dvo, VR00, &temp))
251
	if (!ivch_read(dvo, VR00, &temp))
252
		goto out;
252
		goto out;
253
	priv->quiet = false;
253
	priv->quiet = false;
254
 
254
 
255
	/* Since the identification bits are probably zeroes, which doesn't seem
255
	/* Since the identification bits are probably zeroes, which doesn't seem
256
	 * very unique, check that the value in the base address field matches
256
	 * very unique, check that the value in the base address field matches
257
	 * the address it's responding on.
257
	 * the address it's responding on.
258
	 */
258
	 */
259
	if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
259
	if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
260
		DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
260
		DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
261
			  "(%d vs %d)\n",
261
			  "(%d vs %d)\n",
262
			  (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
262
			  (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
263
		goto out;
263
		goto out;
264
	}
264
	}
265
 
265
 
266
	ivch_read(dvo, VR20, &priv->width);
266
	ivch_read(dvo, VR20, &priv->width);
267
	ivch_read(dvo, VR21, &priv->height);
267
	ivch_read(dvo, VR21, &priv->height);
268
 
268
 
269
	return true;
269
	return true;
270
 
270
 
271
out:
271
out:
272
	kfree(priv);
272
	kfree(priv);
273
	return false;
273
	return false;
274
}
274
}
275
 
275
 
276
static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
276
static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
277
{
277
{
278
	return connector_status_connected;
278
	return connector_status_connected;
279
}
279
}
280
 
280
 
281
static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
281
static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
282
					    struct drm_display_mode *mode)
282
					    struct drm_display_mode *mode)
283
{
283
{
284
	if (mode->clock > 112000)
284
	if (mode->clock > 112000)
285
		return MODE_CLOCK_HIGH;
285
		return MODE_CLOCK_HIGH;
286
 
286
 
287
	return MODE_OK;
287
	return MODE_OK;
288
}
288
}
289
 
289
 
290
/** Sets the power state of the panel connected to the ivch */
290
/** Sets the power state of the panel connected to the ivch */
291
static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
291
static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
292
{
292
{
293
	int i;
293
	int i;
294
	uint16_t vr01, vr30, backlight;
294
	uint16_t vr01, vr30, backlight;
295
 
295
 
296
	/* Set the new power state of the panel. */
296
	/* Set the new power state of the panel. */
297
	if (!ivch_read(dvo, VR01, &vr01))
297
	if (!ivch_read(dvo, VR01, &vr01))
298
		return;
298
		return;
299
 
299
 
300
	if (enable)
300
	if (enable)
301
		backlight = 1;
301
		backlight = 1;
302
	else
302
	else
303
		backlight = 0;
303
		backlight = 0;
304
	ivch_write(dvo, VR80, backlight);
304
	ivch_write(dvo, VR80, backlight);
305
 
305
 
306
	if (enable)
306
	if (enable)
307
		vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
307
		vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
308
	else
308
	else
309
		vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
309
		vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
310
 
310
 
311
	ivch_write(dvo, VR01, vr01);
311
	ivch_write(dvo, VR01, vr01);
312
 
312
 
313
	/* Wait for the panel to make its state transition */
313
	/* Wait for the panel to make its state transition */
314
	for (i = 0; i < 100; i++) {
314
	for (i = 0; i < 100; i++) {
315
		if (!ivch_read(dvo, VR30, &vr30))
315
		if (!ivch_read(dvo, VR30, &vr30))
316
			break;
316
			break;
317
 
317
 
318
		if (((vr30 & VR30_PANEL_ON) != 0) == enable)
318
		if (((vr30 & VR30_PANEL_ON) != 0) == enable)
319
			break;
319
			break;
320
		udelay(1000);
320
		udelay(1000);
321
	}
321
	}
322
	/* wait some more; vch may fail to resync sometimes without this */
322
	/* wait some more; vch may fail to resync sometimes without this */
323
	udelay(16 * 1000);
323
	udelay(16 * 1000);
324
}
324
}
325
 
325
 
326
static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
326
static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
327
{
327
{
328
	uint16_t vr01;
328
	uint16_t vr01;
329
 
329
 
330
	/* Set the new power state of the panel. */
330
	/* Set the new power state of the panel. */
331
	if (!ivch_read(dvo, VR01, &vr01))
331
	if (!ivch_read(dvo, VR01, &vr01))
332
		return false;
332
		return false;
333
 
333
 
334
	if (vr01 & VR01_LCD_ENABLE)
334
	if (vr01 & VR01_LCD_ENABLE)
335
		return true;
335
		return true;
336
	else
336
	else
337
		return false;
337
		return false;
338
}
338
}
339
 
339
 
340
static void ivch_mode_set(struct intel_dvo_device *dvo,
340
static void ivch_mode_set(struct intel_dvo_device *dvo,
341
			  struct drm_display_mode *mode,
341
			  struct drm_display_mode *mode,
342
			  struct drm_display_mode *adjusted_mode)
342
			  struct drm_display_mode *adjusted_mode)
343
{
343
{
344
	uint16_t vr40 = 0;
344
	uint16_t vr40 = 0;
345
	uint16_t vr01;
345
	uint16_t vr01;
346
 
346
 
347
	vr01 = 0;
347
	vr01 = 0;
348
	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
348
	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
349
		VR40_HORIZONTAL_INTERP_ENABLE);
349
		VR40_HORIZONTAL_INTERP_ENABLE);
350
 
350
 
351
	if (mode->hdisplay != adjusted_mode->hdisplay ||
351
	if (mode->hdisplay != adjusted_mode->hdisplay ||
352
	    mode->vdisplay != adjusted_mode->vdisplay) {
352
	    mode->vdisplay != adjusted_mode->vdisplay) {
353
		uint16_t x_ratio, y_ratio;
353
		uint16_t x_ratio, y_ratio;
354
 
354
 
355
		vr01 |= VR01_PANEL_FIT_ENABLE;
355
		vr01 |= VR01_PANEL_FIT_ENABLE;
356
		vr40 |= VR40_CLOCK_GATING_ENABLE;
356
		vr40 |= VR40_CLOCK_GATING_ENABLE;
357
		x_ratio = (((mode->hdisplay - 1) << 16) /
357
		x_ratio = (((mode->hdisplay - 1) << 16) /
358
			   (adjusted_mode->hdisplay - 1)) >> 2;
358
			   (adjusted_mode->hdisplay - 1)) >> 2;
359
		y_ratio = (((mode->vdisplay - 1) << 16) /
359
		y_ratio = (((mode->vdisplay - 1) << 16) /
360
			   (adjusted_mode->vdisplay - 1)) >> 2;
360
			   (adjusted_mode->vdisplay - 1)) >> 2;
361
		ivch_write(dvo, VR42, x_ratio);
361
		ivch_write(dvo, VR42, x_ratio);
362
		ivch_write(dvo, VR41, y_ratio);
362
		ivch_write(dvo, VR41, y_ratio);
363
	} else {
363
	} else {
364
		vr01 &= ~VR01_PANEL_FIT_ENABLE;
364
		vr01 &= ~VR01_PANEL_FIT_ENABLE;
365
		vr40 &= ~VR40_CLOCK_GATING_ENABLE;
365
		vr40 &= ~VR40_CLOCK_GATING_ENABLE;
366
	}
366
	}
367
	vr40 &= ~VR40_AUTO_RATIO_ENABLE;
367
	vr40 &= ~VR40_AUTO_RATIO_ENABLE;
368
 
368
 
369
	ivch_write(dvo, VR01, vr01);
369
	ivch_write(dvo, VR01, vr01);
370
	ivch_write(dvo, VR40, vr40);
370
	ivch_write(dvo, VR40, vr40);
371
 
371
 
372
	ivch_dump_regs(dvo);
372
	ivch_dump_regs(dvo);
373
}
373
}
374
 
374
 
375
static void ivch_dump_regs(struct intel_dvo_device *dvo)
375
static void ivch_dump_regs(struct intel_dvo_device *dvo)
376
{
376
{
377
	uint16_t val;
377
	uint16_t val;
378
 
378
 
379
	ivch_read(dvo, VR00, &val);
379
	ivch_read(dvo, VR00, &val);
380
	DRM_LOG_KMS("VR00: 0x%04x\n", val);
380
	DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
381
	ivch_read(dvo, VR01, &val);
381
	ivch_read(dvo, VR01, &val);
382
	DRM_LOG_KMS("VR01: 0x%04x\n", val);
382
	DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
383
	ivch_read(dvo, VR30, &val);
383
	ivch_read(dvo, VR30, &val);
384
	DRM_LOG_KMS("VR30: 0x%04x\n", val);
384
	DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
385
	ivch_read(dvo, VR40, &val);
385
	ivch_read(dvo, VR40, &val);
386
	DRM_LOG_KMS("VR40: 0x%04x\n", val);
386
	DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
387
 
387
 
388
	/* GPIO registers */
388
	/* GPIO registers */
389
	ivch_read(dvo, VR80, &val);
389
	ivch_read(dvo, VR80, &val);
390
	DRM_LOG_KMS("VR80: 0x%04x\n", val);
390
	DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
391
	ivch_read(dvo, VR81, &val);
391
	ivch_read(dvo, VR81, &val);
392
	DRM_LOG_KMS("VR81: 0x%04x\n", val);
392
	DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
393
	ivch_read(dvo, VR82, &val);
393
	ivch_read(dvo, VR82, &val);
394
	DRM_LOG_KMS("VR82: 0x%04x\n", val);
394
	DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
395
	ivch_read(dvo, VR83, &val);
395
	ivch_read(dvo, VR83, &val);
396
	DRM_LOG_KMS("VR83: 0x%04x\n", val);
396
	DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
397
	ivch_read(dvo, VR84, &val);
397
	ivch_read(dvo, VR84, &val);
398
	DRM_LOG_KMS("VR84: 0x%04x\n", val);
398
	DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
399
	ivch_read(dvo, VR85, &val);
399
	ivch_read(dvo, VR85, &val);
400
	DRM_LOG_KMS("VR85: 0x%04x\n", val);
400
	DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
401
	ivch_read(dvo, VR86, &val);
401
	ivch_read(dvo, VR86, &val);
402
	DRM_LOG_KMS("VR86: 0x%04x\n", val);
402
	DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
403
	ivch_read(dvo, VR87, &val);
403
	ivch_read(dvo, VR87, &val);
404
	DRM_LOG_KMS("VR87: 0x%04x\n", val);
404
	DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
405
	ivch_read(dvo, VR88, &val);
405
	ivch_read(dvo, VR88, &val);
406
	DRM_LOG_KMS("VR88: 0x%04x\n", val);
406
	DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
407
 
407
 
408
	/* Scratch register 0 - AIM Panel type */
408
	/* Scratch register 0 - AIM Panel type */
409
	ivch_read(dvo, VR8E, &val);
409
	ivch_read(dvo, VR8E, &val);
410
	DRM_LOG_KMS("VR8E: 0x%04x\n", val);
410
	DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
411
 
411
 
412
	/* Scratch register 1 - Status register */
412
	/* Scratch register 1 - Status register */
413
	ivch_read(dvo, VR8F, &val);
413
	ivch_read(dvo, VR8F, &val);
414
	DRM_LOG_KMS("VR8F: 0x%04x\n", val);
414
	DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
415
}
415
}
416
 
416
 
417
static void ivch_destroy(struct intel_dvo_device *dvo)
417
static void ivch_destroy(struct intel_dvo_device *dvo)
418
{
418
{
419
	struct ivch_priv *priv = dvo->dev_priv;
419
	struct ivch_priv *priv = dvo->dev_priv;
420
 
420
 
421
	if (priv) {
421
	if (priv) {
422
		kfree(priv);
422
		kfree(priv);
423
		dvo->dev_priv = NULL;
423
		dvo->dev_priv = NULL;
424
	}
424
	}
425
}
425
}
426
 
426
 
427
struct intel_dvo_dev_ops ivch_ops = {
427
struct intel_dvo_dev_ops ivch_ops = {
428
	.init = ivch_init,
428
	.init = ivch_init,
429
	.dpms = ivch_dpms,
429
	.dpms = ivch_dpms,
430
	.get_hw_state = ivch_get_hw_state,
430
	.get_hw_state = ivch_get_hw_state,
431
	.mode_valid = ivch_mode_valid,
431
	.mode_valid = ivch_mode_valid,
432
	.mode_set = ivch_mode_set,
432
	.mode_set = ivch_mode_set,
433
	.detect = ivch_detect,
433
	.detect = ivch_detect,
434
	.dump_regs = ivch_dump_regs,
434
	.dump_regs = ivch_dump_regs,
435
	.destroy = ivch_destroy,
435
	.destroy = ivch_destroy,
436
};
436
};