This source file includes following definitions.
- ch7xxx_get_id
- ch7xxx_get_did
- ch7xxx_readb
- ch7xxx_writeb
- ch7xxx_init
- ch7xxx_detect
- ch7xxx_mode_valid
- ch7xxx_mode_set
- ch7xxx_dpms
- ch7xxx_get_hw_state
- ch7xxx_dump_regs
- ch7xxx_destroy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "intel_display_types.h"
30 #include "intel_dvo_dev.h"
31
32 #define CH7xxx_REG_VID 0x4a
33 #define CH7xxx_REG_DID 0x4b
34
35 #define CH7011_VID 0x83
36 #define CH7010B_VID 0x05
37 #define CH7009A_VID 0x84
38 #define CH7009B_VID 0x85
39 #define CH7301_VID 0x95
40
41 #define CH7xxx_VID 0x84
42 #define CH7xxx_DID 0x17
43 #define CH7010_DID 0x16
44
45 #define CH7xxx_NUM_REGS 0x4c
46
47 #define CH7xxx_CM 0x1c
48 #define CH7xxx_CM_XCM (1<<0)
49 #define CH7xxx_CM_MCP (1<<2)
50 #define CH7xxx_INPUT_CLOCK 0x1d
51 #define CH7xxx_GPIO 0x1e
52 #define CH7xxx_GPIO_HPIR (1<<3)
53 #define CH7xxx_IDF 0x1f
54
55 #define CH7xxx_IDF_HSP (1<<3)
56 #define CH7xxx_IDF_VSP (1<<4)
57
58 #define CH7xxx_CONNECTION_DETECT 0x20
59 #define CH7xxx_CDET_DVI (1<<5)
60
61 #define CH7301_DAC_CNTL 0x21
62 #define CH7301_HOTPLUG 0x23
63 #define CH7xxx_TCTL 0x31
64 #define CH7xxx_TVCO 0x32
65 #define CH7xxx_TPCP 0x33
66 #define CH7xxx_TPD 0x34
67 #define CH7xxx_TPVT 0x35
68 #define CH7xxx_TLPF 0x36
69 #define CH7xxx_TCT 0x37
70 #define CH7301_TEST_PATTERN 0x48
71
72 #define CH7xxx_PM 0x49
73 #define CH7xxx_PM_FPD (1<<0)
74 #define CH7301_PM_DACPD0 (1<<1)
75 #define CH7301_PM_DACPD1 (1<<2)
76 #define CH7301_PM_DACPD2 (1<<3)
77 #define CH7xxx_PM_DVIL (1<<6)
78 #define CH7xxx_PM_DVIP (1<<7)
79
80 #define CH7301_SYNC_POLARITY 0x56
81 #define CH7301_SYNC_RGB_YUV (1<<0)
82 #define CH7301_SYNC_POL_DVI (1<<5)
83
84
85
86
87
88 static struct ch7xxx_id_struct {
89 u8 vid;
90 char *name;
91 } ch7xxx_ids[] = {
92 { CH7011_VID, "CH7011" },
93 { CH7010B_VID, "CH7010B" },
94 { CH7009A_VID, "CH7009A" },
95 { CH7009B_VID, "CH7009B" },
96 { CH7301_VID, "CH7301" },
97 };
98
99 static struct ch7xxx_did_struct {
100 u8 did;
101 char *name;
102 } ch7xxx_dids[] = {
103 { CH7xxx_DID, "CH7XXX" },
104 { CH7010_DID, "CH7010B" },
105 };
106
107 struct ch7xxx_priv {
108 bool quiet;
109 };
110
111 static char *ch7xxx_get_id(u8 vid)
112 {
113 int i;
114
115 for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
116 if (ch7xxx_ids[i].vid == vid)
117 return ch7xxx_ids[i].name;
118 }
119
120 return NULL;
121 }
122
123 static char *ch7xxx_get_did(u8 did)
124 {
125 int i;
126
127 for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
128 if (ch7xxx_dids[i].did == did)
129 return ch7xxx_dids[i].name;
130 }
131
132 return NULL;
133 }
134
135
136 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
137 {
138 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
139 struct i2c_adapter *adapter = dvo->i2c_bus;
140 u8 out_buf[2];
141 u8 in_buf[2];
142
143 struct i2c_msg msgs[] = {
144 {
145 .addr = dvo->slave_addr,
146 .flags = 0,
147 .len = 1,
148 .buf = out_buf,
149 },
150 {
151 .addr = dvo->slave_addr,
152 .flags = I2C_M_RD,
153 .len = 1,
154 .buf = in_buf,
155 }
156 };
157
158 out_buf[0] = addr;
159 out_buf[1] = 0;
160
161 if (i2c_transfer(adapter, msgs, 2) == 2) {
162 *ch = in_buf[0];
163 return true;
164 }
165
166 if (!ch7xxx->quiet) {
167 DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
168 addr, adapter->name, dvo->slave_addr);
169 }
170 return false;
171 }
172
173
174 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
175 {
176 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
177 struct i2c_adapter *adapter = dvo->i2c_bus;
178 u8 out_buf[2];
179 struct i2c_msg msg = {
180 .addr = dvo->slave_addr,
181 .flags = 0,
182 .len = 2,
183 .buf = out_buf,
184 };
185
186 out_buf[0] = addr;
187 out_buf[1] = ch;
188
189 if (i2c_transfer(adapter, &msg, 1) == 1)
190 return true;
191
192 if (!ch7xxx->quiet) {
193 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
194 addr, adapter->name, dvo->slave_addr);
195 }
196
197 return false;
198 }
199
200 static bool ch7xxx_init(struct intel_dvo_device *dvo,
201 struct i2c_adapter *adapter)
202 {
203
204 struct ch7xxx_priv *ch7xxx;
205 u8 vendor, device;
206 char *name, *devid;
207
208 ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
209 if (ch7xxx == NULL)
210 return false;
211
212 dvo->i2c_bus = adapter;
213 dvo->dev_priv = ch7xxx;
214 ch7xxx->quiet = true;
215
216 if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
217 goto out;
218
219 name = ch7xxx_get_id(vendor);
220 if (!name) {
221 DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
222 vendor, adapter->name, dvo->slave_addr);
223 goto out;
224 }
225
226
227 if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
228 goto out;
229
230 devid = ch7xxx_get_did(device);
231 if (!devid) {
232 DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
233 device, adapter->name, dvo->slave_addr);
234 goto out;
235 }
236
237 ch7xxx->quiet = false;
238 DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
239 name, vendor, device);
240 return true;
241 out:
242 kfree(ch7xxx);
243 return false;
244 }
245
246 static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
247 {
248 u8 cdet, orig_pm, pm;
249
250 ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
251
252 pm = orig_pm;
253 pm &= ~CH7xxx_PM_FPD;
254 pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
255
256 ch7xxx_writeb(dvo, CH7xxx_PM, pm);
257
258 ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
259
260 ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
261
262 if (cdet & CH7xxx_CDET_DVI)
263 return connector_status_connected;
264 return connector_status_disconnected;
265 }
266
267 static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
268 struct drm_display_mode *mode)
269 {
270 if (mode->clock > 165000)
271 return MODE_CLOCK_HIGH;
272
273 return MODE_OK;
274 }
275
276 static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
277 const struct drm_display_mode *mode,
278 const struct drm_display_mode *adjusted_mode)
279 {
280 u8 tvco, tpcp, tpd, tlpf, idf;
281
282 if (mode->clock <= 65000) {
283 tvco = 0x23;
284 tpcp = 0x08;
285 tpd = 0x16;
286 tlpf = 0x60;
287 } else {
288 tvco = 0x2d;
289 tpcp = 0x06;
290 tpd = 0x26;
291 tlpf = 0xa0;
292 }
293
294 ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
295 ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
296 ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
297 ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
298 ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
299 ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
300 ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
301
302 ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
303
304 idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
305 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
306 idf |= CH7xxx_IDF_HSP;
307
308 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
309 idf |= CH7xxx_IDF_VSP;
310
311 ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
312 }
313
314
315 static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
316 {
317 if (enable)
318 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
319 else
320 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
321 }
322
323 static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
324 {
325 u8 val;
326
327 ch7xxx_readb(dvo, CH7xxx_PM, &val);
328
329 if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
330 return true;
331 else
332 return false;
333 }
334
335 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
336 {
337 int i;
338
339 for (i = 0; i < CH7xxx_NUM_REGS; i++) {
340 u8 val;
341 if ((i % 8) == 0)
342 DRM_DEBUG_KMS("\n %02X: ", i);
343 ch7xxx_readb(dvo, i, &val);
344 DRM_DEBUG_KMS("%02X ", val);
345 }
346 }
347
348 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
349 {
350 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
351
352 if (ch7xxx) {
353 kfree(ch7xxx);
354 dvo->dev_priv = NULL;
355 }
356 }
357
358 const struct intel_dvo_dev_ops ch7xxx_ops = {
359 .init = ch7xxx_init,
360 .detect = ch7xxx_detect,
361 .mode_valid = ch7xxx_mode_valid,
362 .mode_set = ch7xxx_mode_set,
363 .dpms = ch7xxx_dpms,
364 .get_hw_state = ch7xxx_get_hw_state,
365 .dump_regs = ch7xxx_dump_regs,
366 .destroy = ch7xxx_destroy,
367 };