Subversion Repositories Kolibri OS

Rev

Rev 5060 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2330 Serge 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 
6084 serge 25
 *    Thomas Richter 
2330 Serge 26
 *
6084 serge 27
 * Minor modifications (Dithering enable):
28
 *    Thomas Richter 
29
 *
2330 Serge 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)
6084 serge 66
/** Enable dithering for 18bpp panels. Not documented. */
67
# define VR01_DITHER_ENABLE             (1 << 4)
2330 Serge 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)
6084 serge 83
/** Mask that defines the depth of the pipeline */
84
# define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
2330 Serge 85
 
86
/*
87
 * VR20 LCD Horizontal Display Size
88
 */
89
#define VR20	0x20
90
 
91
/*
92
 * LCD Vertical Display Size
93
 */
6084 serge 94
#define VR21	0x21
2330 Serge 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
 
6084 serge 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
};
2330 Serge 172
 
6084 serge 173
 
2330 Serge 174
struct ivch_priv {
175
	bool quiet;
176
 
177
	uint16_t width, height;
6084 serge 178
 
179
	/* Register backup */
180
 
181
	uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
2330 Serge 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
static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
192
{
193
	struct ivch_priv *priv = dvo->dev_priv;
194
	struct i2c_adapter *adapter = dvo->i2c_bus;
195
	u8 out_buf[1];
196
	u8 in_buf[2];
197
 
198
	struct i2c_msg msgs[] = {
199
		{
200
			.addr = dvo->slave_addr,
201
			.flags = I2C_M_RD,
202
			.len = 0,
203
		},
204
		{
205
			.addr = 0,
206
			.flags = I2C_M_NOSTART,
207
			.len = 1,
208
			.buf = out_buf,
209
		},
210
		{
211
			.addr = dvo->slave_addr,
212
			.flags = I2C_M_RD | I2C_M_NOSTART,
213
			.len = 2,
214
			.buf = in_buf,
215
		}
216
	};
217
 
218
	out_buf[0] = addr;
219
 
220
	if (i2c_transfer(adapter, msgs, 3) == 3) {
221
		*data = (in_buf[1] << 8) | in_buf[0];
222
		return true;
5060 serge 223
	}
2330 Serge 224
 
225
	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
	return false;
231
}
232
 
233
/** Writes a 16-bit register on the ivch */
234
static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
235
{
236
	struct ivch_priv *priv = dvo->dev_priv;
237
	struct i2c_adapter *adapter = dvo->i2c_bus;
238
	u8 out_buf[3];
239
	struct i2c_msg msg = {
240
		.addr = dvo->slave_addr,
241
		.flags = 0,
242
		.len = 3,
243
		.buf = out_buf,
244
	};
245
 
246
	out_buf[0] = addr;
247
	out_buf[1] = data & 0xff;
248
	out_buf[2] = data >> 8;
249
 
250
	if (i2c_transfer(adapter, &msg, 1) == 1)
251
		return true;
252
 
253
	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
	return false;
259
}
260
 
261
/** Probes the given bus and slave address for an ivch */
262
static bool ivch_init(struct intel_dvo_device *dvo,
263
		      struct i2c_adapter *adapter)
264
{
265
	struct ivch_priv *priv;
266
	uint16_t temp;
6084 serge 267
	int i;
2330 Serge 268
 
269
	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
270
	if (priv == NULL)
271
		return false;
272
 
273
	dvo->i2c_bus = adapter;
274
	dvo->dev_priv = priv;
275
	priv->quiet = true;
276
 
277
	if (!ivch_read(dvo, VR00, &temp))
278
		goto out;
279
	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
	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
	ivch_read(dvo, VR20, &priv->width);
293
	ivch_read(dvo, VR21, &priv->height);
294
 
6084 serge 295
	/* Make a backup of the registers to be able to restore them
296
	 * upon suspend.
297
	 */
298
	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
299
		ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
300
 
301
	ivch_dump_regs(dvo);
302
 
2330 Serge 303
	return true;
304
 
305
out:
306
	kfree(priv);
307
	return false;
308
}
309
 
310
static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
311
{
312
	return connector_status_connected;
313
}
314
 
315
static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
316
					    struct drm_display_mode *mode)
317
{
318
	if (mode->clock > 112000)
319
		return MODE_CLOCK_HIGH;
320
 
321
	return MODE_OK;
322
}
323
 
6084 serge 324
/* Restore the DVO registers after a resume
325
 * from RAM. Registers have been saved during
326
 * the initialization.
327
 */
328
static void ivch_reset(struct intel_dvo_device *dvo)
329
{
330
	struct ivch_priv *priv = dvo->dev_priv;
331
	int i;
332
 
333
	DRM_DEBUG_KMS("Resetting the IVCH registers\n");
334
 
335
	ivch_write(dvo, VR10, 0x0000);
336
 
337
	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
338
		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
339
}
340
 
2330 Serge 341
/** Sets the power state of the panel connected to the ivch */
3031 serge 342
static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
2330 Serge 343
{
344
	int i;
345
	uint16_t vr01, vr30, backlight;
346
 
6084 serge 347
	ivch_reset(dvo);
348
 
2330 Serge 349
	/* Set the new power state of the panel. */
350
	if (!ivch_read(dvo, VR01, &vr01))
351
		return;
352
 
3031 serge 353
	if (enable)
2330 Serge 354
		backlight = 1;
355
	else
356
		backlight = 0;
6084 serge 357
 
2330 Serge 358
	ivch_write(dvo, VR80, backlight);
359
 
3031 serge 360
	if (enable)
2330 Serge 361
		vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
362
	else
363
		vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
364
 
365
	ivch_write(dvo, VR01, vr01);
366
 
367
	/* Wait for the panel to make its state transition */
368
	for (i = 0; i < 100; i++) {
369
		if (!ivch_read(dvo, VR30, &vr30))
370
			break;
371
 
3031 serge 372
		if (((vr30 & VR30_PANEL_ON) != 0) == enable)
2330 Serge 373
			break;
374
		udelay(1000);
375
	}
376
	/* wait some more; vch may fail to resync sometimes without this */
377
	udelay(16 * 1000);
378
}
379
 
3031 serge 380
static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
381
{
382
	uint16_t vr01;
383
 
6084 serge 384
	ivch_reset(dvo);
385
 
3031 serge 386
	/* Set the new power state of the panel. */
387
	if (!ivch_read(dvo, VR01, &vr01))
388
		return false;
389
 
390
	if (vr01 & VR01_LCD_ENABLE)
391
		return true;
392
	else
393
		return false;
394
}
395
 
2330 Serge 396
static void ivch_mode_set(struct intel_dvo_device *dvo,
6084 serge 397
			  const struct drm_display_mode *mode,
398
			  const struct drm_display_mode *adjusted_mode)
2330 Serge 399
{
6084 serge 400
	struct ivch_priv *priv = dvo->dev_priv;
2330 Serge 401
	uint16_t vr40 = 0;
6084 serge 402
	uint16_t vr01 = 0;
403
	uint16_t vr10;
2330 Serge 404
 
6084 serge 405
	ivch_reset(dvo);
406
 
407
	vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
408
 
409
	/* Enable dithering for 18 bpp pipelines */
410
	vr10 &= VR10_INTERFACE_DEPTH_MASK;
411
	if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
412
		vr01 = VR01_DITHER_ENABLE;
413
 
2330 Serge 414
	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
415
		VR40_HORIZONTAL_INTERP_ENABLE);
416
 
6084 serge 417
	if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
418
	    mode->vdisplay != adjusted_mode->crtc_vdisplay) {
2330 Serge 419
		uint16_t x_ratio, y_ratio;
420
 
421
		vr01 |= VR01_PANEL_FIT_ENABLE;
422
		vr40 |= VR40_CLOCK_GATING_ENABLE;
423
		x_ratio = (((mode->hdisplay - 1) << 16) /
6084 serge 424
			   (adjusted_mode->crtc_hdisplay - 1)) >> 2;
2330 Serge 425
		y_ratio = (((mode->vdisplay - 1) << 16) /
6084 serge 426
			   (adjusted_mode->crtc_vdisplay - 1)) >> 2;
2342 Serge 427
		ivch_write(dvo, VR42, x_ratio);
428
		ivch_write(dvo, VR41, y_ratio);
2330 Serge 429
	} else {
430
		vr01 &= ~VR01_PANEL_FIT_ENABLE;
431
		vr40 &= ~VR40_CLOCK_GATING_ENABLE;
432
	}
433
	vr40 &= ~VR40_AUTO_RATIO_ENABLE;
434
 
435
	ivch_write(dvo, VR01, vr01);
436
	ivch_write(dvo, VR40, vr40);
437
}
438
 
439
static void ivch_dump_regs(struct intel_dvo_device *dvo)
440
{
441
	uint16_t val;
442
 
443
	ivch_read(dvo, VR00, &val);
5060 serge 444
	DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
2330 Serge 445
	ivch_read(dvo, VR01, &val);
5060 serge 446
	DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
6084 serge 447
	ivch_read(dvo, VR10, &val);
448
	DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
2330 Serge 449
	ivch_read(dvo, VR30, &val);
5060 serge 450
	DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
2330 Serge 451
	ivch_read(dvo, VR40, &val);
5060 serge 452
	DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
2330 Serge 453
 
454
	/* GPIO registers */
455
	ivch_read(dvo, VR80, &val);
5060 serge 456
	DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
2330 Serge 457
	ivch_read(dvo, VR81, &val);
5060 serge 458
	DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
2330 Serge 459
	ivch_read(dvo, VR82, &val);
5060 serge 460
	DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
2330 Serge 461
	ivch_read(dvo, VR83, &val);
5060 serge 462
	DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
2330 Serge 463
	ivch_read(dvo, VR84, &val);
5060 serge 464
	DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
2330 Serge 465
	ivch_read(dvo, VR85, &val);
5060 serge 466
	DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
2330 Serge 467
	ivch_read(dvo, VR86, &val);
5060 serge 468
	DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
2330 Serge 469
	ivch_read(dvo, VR87, &val);
5060 serge 470
	DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
2330 Serge 471
	ivch_read(dvo, VR88, &val);
5060 serge 472
	DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
2330 Serge 473
 
474
	/* Scratch register 0 - AIM Panel type */
475
	ivch_read(dvo, VR8E, &val);
5060 serge 476
	DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
2330 Serge 477
 
478
	/* Scratch register 1 - Status register */
479
	ivch_read(dvo, VR8F, &val);
5060 serge 480
	DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
2330 Serge 481
}
482
 
483
static void ivch_destroy(struct intel_dvo_device *dvo)
484
{
485
	struct ivch_priv *priv = dvo->dev_priv;
486
 
487
	if (priv) {
488
		kfree(priv);
489
		dvo->dev_priv = NULL;
490
	}
491
}
492
 
2342 Serge 493
struct intel_dvo_dev_ops ivch_ops = {
2330 Serge 494
	.init = ivch_init,
495
	.dpms = ivch_dpms,
3031 serge 496
	.get_hw_state = ivch_get_hw_state,
2330 Serge 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
};