Merge tag 'mips_5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / display / dvo_ch7xxx.c
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 "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 /* 7010 as well */
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 /** @file
85  * driver for the Chrontel 7xxx DVI chip over DVO.
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 /** Reads an 8 bit register */
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 /** Writes an 8 bit register */
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         /* this will detect the CH7xxx chip on the specified i2c bus */
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 /* set the CH7xxx power state */
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 };