Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
2330 Serge 1
/**************************************************************************
2
 
3
Copyright © 2006 Dave Airlie
4
 
5
All Rights Reserved.
6
 
7
Permission is hereby granted, free of charge, to any person obtaining a
8
copy of this software and associated documentation files (the
9
"Software"), to deal in the Software without restriction, including
10
without limitation the rights to use, copy, modify, merge, publish,
11
distribute, sub license, and/or sell copies of the Software, and to
12
permit persons to whom the Software is furnished to do so, subject to
13
the following conditions:
14
 
15
The above copyright notice and this permission notice (including the
16
next paragraph) shall be included in all copies or substantial portions
17
of the Software.
18
 
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
 
27
**************************************************************************/
28
 
29
#include "dvo.h"
30
 
31
#define CH7xxx_REG_VID		0x4a
32
#define CH7xxx_REG_DID		0x4b
33
 
34
#define CH7011_VID		0x83 /* 7010 as well */
35
#define CH7009A_VID		0x84
36
#define CH7009B_VID		0x85
37
#define CH7301_VID		0x95
38
 
39
#define CH7xxx_VID		0x84
40
#define CH7xxx_DID		0x17
41
 
42
#define CH7xxx_NUM_REGS		0x4c
43
 
44
#define CH7xxx_CM		0x1c
45
#define CH7xxx_CM_XCM		(1<<0)
46
#define CH7xxx_CM_MCP		(1<<2)
47
#define CH7xxx_INPUT_CLOCK	0x1d
48
#define CH7xxx_GPIO		0x1e
49
#define CH7xxx_GPIO_HPIR	(1<<3)
50
#define CH7xxx_IDF		0x1f
51
 
52
#define CH7xxx_IDF_HSP		(1<<3)
53
#define CH7xxx_IDF_VSP		(1<<4)
54
 
55
#define CH7xxx_CONNECTION_DETECT 0x20
56
#define CH7xxx_CDET_DVI		(1<<5)
57
 
58
#define CH7301_DAC_CNTL		0x21
59
#define CH7301_HOTPLUG		0x23
60
#define CH7xxx_TCTL		0x31
61
#define CH7xxx_TVCO		0x32
62
#define CH7xxx_TPCP		0x33
63
#define CH7xxx_TPD		0x34
64
#define CH7xxx_TPVT		0x35
65
#define CH7xxx_TLPF		0x36
66
#define CH7xxx_TCT		0x37
67
#define CH7301_TEST_PATTERN	0x48
68
 
69
#define CH7xxx_PM		0x49
70
#define CH7xxx_PM_FPD		(1<<0)
71
#define CH7301_PM_DACPD0	(1<<1)
72
#define CH7301_PM_DACPD1	(1<<2)
73
#define CH7301_PM_DACPD2	(1<<3)
74
#define CH7xxx_PM_DVIL		(1<<6)
75
#define CH7xxx_PM_DVIP		(1<<7)
76
 
77
#define CH7301_SYNC_POLARITY	0x56
78
#define CH7301_SYNC_RGB_YUV	(1<<0)
79
#define CH7301_SYNC_POL_DVI	(1<<5)
80
 
81
/** @file
82
 * driver for the Chrontel 7xxx DVI chip over DVO.
83
 */
84
 
85
static struct ch7xxx_id_struct {
86
	uint8_t vid;
87
	char *name;
88
} ch7xxx_ids[] = {
89
	{ CH7011_VID, "CH7011" },
90
	{ CH7009A_VID, "CH7009A" },
91
	{ CH7009B_VID, "CH7009B" },
92
	{ CH7301_VID, "CH7301" },
93
};
94
 
95
struct ch7xxx_priv {
96
	bool quiet;
97
};
98
 
99
static char *ch7xxx_get_id(uint8_t vid)
100
{
101
	int i;
102
 
103
	for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
104
		if (ch7xxx_ids[i].vid == vid)
105
			return ch7xxx_ids[i].name;
106
	}
107
 
108
	return NULL;
109
}
110
 
111
/** Reads an 8 bit register */
112
static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
113
{
2342 Serge 114
	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
2330 Serge 115
	struct i2c_adapter *adapter = dvo->i2c_bus;
116
	u8 out_buf[2];
117
	u8 in_buf[2];
118
 
119
	struct i2c_msg msgs[] = {
120
		{
121
			.addr = dvo->slave_addr,
122
			.flags = 0,
123
			.len = 1,
124
			.buf = out_buf,
125
		},
126
		{
127
			.addr = dvo->slave_addr,
128
			.flags = I2C_M_RD,
129
			.len = 1,
130
			.buf = in_buf,
131
		}
132
	};
133
 
134
	out_buf[0] = addr;
135
	out_buf[1] = 0;
136
 
137
	if (i2c_transfer(adapter, msgs, 2) == 2) {
138
		*ch = in_buf[0];
139
		return true;
140
	};
141
 
142
	if (!ch7xxx->quiet) {
143
		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
144
			  addr, adapter->name, dvo->slave_addr);
145
	}
146
	return false;
147
}
148
 
149
/** Writes an 8 bit register */
150
static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
151
{
152
	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
153
	struct i2c_adapter *adapter = dvo->i2c_bus;
154
	uint8_t out_buf[2];
155
	struct i2c_msg msg = {
156
		.addr = dvo->slave_addr,
157
		.flags = 0,
158
		.len = 2,
159
		.buf = out_buf,
160
	};
161
 
162
	out_buf[0] = addr;
163
	out_buf[1] = ch;
164
 
165
	if (i2c_transfer(adapter, &msg, 1) == 1)
166
		return true;
167
 
168
	if (!ch7xxx->quiet) {
169
		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
170
			  addr, adapter->name, dvo->slave_addr);
171
	}
172
 
173
	return false;
174
}
175
 
176
static bool ch7xxx_init(struct intel_dvo_device *dvo,
177
			struct i2c_adapter *adapter)
178
{
179
	/* this will detect the CH7xxx chip on the specified i2c bus */
180
	struct ch7xxx_priv *ch7xxx;
181
	uint8_t vendor, device;
182
	char *name;
183
 
184
	ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
185
	if (ch7xxx == NULL)
186
		return false;
187
 
188
	dvo->i2c_bus = adapter;
189
	dvo->dev_priv = ch7xxx;
190
	ch7xxx->quiet = true;
191
 
192
	if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
193
		goto out;
194
 
195
	name = ch7xxx_get_id(vendor);
196
	if (!name) {
197
		DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
198
				"slave %d.\n",
199
			  vendor, adapter->name, dvo->slave_addr);
200
		goto out;
201
	}
202
 
203
 
204
	if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
205
		goto out;
206
 
207
	if (device != CH7xxx_DID) {
208
		DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
209
				"slave %d.\n",
210
			  vendor, adapter->name, dvo->slave_addr);
211
		goto out;
212
	}
213
 
214
	ch7xxx->quiet = false;
215
	DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
216
		  name, vendor, device);
217
	return true;
218
out:
219
	kfree(ch7xxx);
220
	return false;
221
}
222
 
223
static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
224
{
225
	uint8_t cdet, orig_pm, pm;
226
 
227
	ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
228
 
229
	pm = orig_pm;
230
	pm &= ~CH7xxx_PM_FPD;
231
	pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
232
 
233
	ch7xxx_writeb(dvo, CH7xxx_PM, pm);
234
 
235
	ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
236
 
237
	ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
238
 
239
	if (cdet & CH7xxx_CDET_DVI)
240
		return connector_status_connected;
241
	return connector_status_disconnected;
242
}
243
 
244
static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
245
					      struct drm_display_mode *mode)
246
{
247
	if (mode->clock > 165000)
248
		return MODE_CLOCK_HIGH;
249
 
250
	return MODE_OK;
251
}
252
 
253
static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
254
			    struct drm_display_mode *mode,
255
			    struct drm_display_mode *adjusted_mode)
256
{
257
	uint8_t tvco, tpcp, tpd, tlpf, idf;
258
 
259
	if (mode->clock <= 65000) {
260
		tvco = 0x23;
261
		tpcp = 0x08;
262
		tpd = 0x16;
263
		tlpf = 0x60;
264
	} else {
265
		tvco = 0x2d;
266
		tpcp = 0x06;
267
		tpd = 0x26;
268
		tlpf = 0xa0;
269
	}
270
 
271
	ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
272
	ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
273
	ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
274
	ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
275
	ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
276
	ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
277
	ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
278
 
279
	ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
280
 
281
	idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
282
	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
283
		idf |= CH7xxx_IDF_HSP;
284
 
285
	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
286
		idf |= CH7xxx_IDF_HSP;
287
 
288
	ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
289
}
290
 
291
/* set the CH7xxx power state */
292
static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
293
{
294
	if (mode == DRM_MODE_DPMS_ON)
295
		ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
296
	else
297
		ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
298
}
299
 
300
static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
301
{
302
	int i;
303
 
304
	for (i = 0; i < CH7xxx_NUM_REGS; i++) {
305
		uint8_t val;
2342 Serge 306
		if ((i % 8) == 0)
2330 Serge 307
			DRM_LOG_KMS("\n %02X: ", i);
308
		ch7xxx_readb(dvo, i, &val);
309
		DRM_LOG_KMS("%02X ", val);
310
	}
311
}
312
 
313
static void ch7xxx_destroy(struct intel_dvo_device *dvo)
314
{
315
	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
316
 
317
	if (ch7xxx) {
318
		kfree(ch7xxx);
319
		dvo->dev_priv = NULL;
320
	}
321
}
322
 
323
struct intel_dvo_dev_ops ch7xxx_ops = {
324
	.init = ch7xxx_init,
325
	.detect = ch7xxx_detect,
326
	.mode_valid = ch7xxx_mode_valid,
327
	.mode_set = ch7xxx_mode_set,
328
	.dpms = ch7xxx_dpms,
329
	.dump_regs = ch7xxx_dump_regs,
330
	.destroy = ch7xxx_destroy,
331
};