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 "dvo.h"
30
31#define CH7xxx_REG_VID 0x4a
32#define CH7xxx_REG_DID 0x4b
33
34#define CH7011_VID 0x83
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
82
83
84
85static 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
95struct ch7xxx_priv {
96 bool quiet;
97};
98
99static 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
112static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
113{
114 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
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
150static 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
176static bool ch7xxx_init(struct intel_dvo_device *dvo,
177 struct i2c_adapter *adapter)
178{
179
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;
218out:
219 kfree(ch7xxx);
220 return false;
221}
222
223static 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
244static 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
253static 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
292static 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
300static 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;
306 if ((i % 8) == 0)
307 DRM_LOG_KMS("\n %02X: ", i);
308 ch7xxx_readb(dvo, i, &val);
309 DRM_LOG_KMS("%02X ", val);
310 }
311}
312
313static 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
323struct 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};
332