Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / 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 "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 {
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 /** 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, bool enable)
293 {
294         if (enable)
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 bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
301 {
302         u8 val;
303
304         ch7xxx_readb(dvo, CH7xxx_PM, &val);
305
306         if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
307                 return true;
308         else
309                 return false;
310 }
311
312 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
313 {
314         int i;
315
316         for (i = 0; i < CH7xxx_NUM_REGS; i++) {
317                 uint8_t val;
318                 if ((i % 8) == 0)
319                         DRM_LOG_KMS("\n %02X: ", i);
320                 ch7xxx_readb(dvo, i, &val);
321                 DRM_LOG_KMS("%02X ", val);
322         }
323 }
324
325 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
326 {
327         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
328
329         if (ch7xxx) {
330                 kfree(ch7xxx);
331                 dvo->dev_priv = NULL;
332         }
333 }
334
335 struct intel_dvo_dev_ops ch7xxx_ops = {
336         .init = ch7xxx_init,
337         .detect = ch7xxx_detect,
338         .mode_valid = ch7xxx_mode_valid,
339         .mode_set = ch7xxx_mode_set,
340         .dpms = ch7xxx_dpms,
341         .get_hw_state = ch7xxx_get_hw_state,
342         .dump_regs = ch7xxx_dump_regs,
343         .destroy = ch7xxx_destroy,
344 };