Revert "drm/i915: Don't enable pipe/plane/VCO early (wait for DPMS on)."
[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         struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
117         u8 out_buf[2];
118         u8 in_buf[2];
119
120         struct i2c_msg msgs[] = {
121                 {
122                         .addr = dvo->slave_addr,
123                         .flags = 0,
124                         .len = 1,
125                         .buf = out_buf,
126                 },
127                 {
128                         .addr = dvo->slave_addr,
129                         .flags = I2C_M_RD,
130                         .len = 1,
131                         .buf = in_buf,
132                 }
133         };
134
135         out_buf[0] = addr;
136         out_buf[1] = 0;
137
138         if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
139                 *ch = in_buf[0];
140                 return true;
141         };
142
143         if (!ch7xxx->quiet) {
144                 DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
145                           addr, i2cbus->adapter.name, dvo->slave_addr);
146         }
147         return false;
148 }
149
150 /** Writes an 8 bit register */
151 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
152 {
153         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
154         struct i2c_adapter *adapter = dvo->i2c_bus;
155         struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
156         uint8_t out_buf[2];
157         struct i2c_msg msg = {
158                 .addr = dvo->slave_addr,
159                 .flags = 0,
160                 .len = 2,
161                 .buf = out_buf,
162         };
163
164         out_buf[0] = addr;
165         out_buf[1] = ch;
166
167         if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
168                 return true;
169
170         if (!ch7xxx->quiet) {
171                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
172                           addr, i2cbus->adapter.name, dvo->slave_addr);
173         }
174
175         return false;
176 }
177
178 static bool ch7xxx_init(struct intel_dvo_device *dvo,
179                         struct i2c_adapter *adapter)
180 {
181         /* this will detect the CH7xxx chip on the specified i2c bus */
182         struct ch7xxx_priv *ch7xxx;
183         uint8_t vendor, device;
184         char *name;
185
186         ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
187         if (ch7xxx == NULL)
188                 return false;
189
190         dvo->i2c_bus = adapter;
191         dvo->dev_priv = ch7xxx;
192         ch7xxx->quiet = true;
193
194         if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
195                 goto out;
196
197         name = ch7xxx_get_id(vendor);
198         if (!name) {
199                 DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
200                                 "slave %d.\n",
201                           vendor, adapter->name, dvo->slave_addr);
202                 goto out;
203         }
204
205
206         if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
207                 goto out;
208
209         if (device != CH7xxx_DID) {
210                 DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
211                                 "slave %d.\n",
212                           vendor, adapter->name, dvo->slave_addr);
213                 goto out;
214         }
215
216         ch7xxx->quiet = false;
217         DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
218                   name, vendor, device);
219         return true;
220 out:
221         kfree(ch7xxx);
222         return false;
223 }
224
225 static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
226 {
227         uint8_t cdet, orig_pm, pm;
228
229         ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
230
231         pm = orig_pm;
232         pm &= ~CH7xxx_PM_FPD;
233         pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
234
235         ch7xxx_writeb(dvo, CH7xxx_PM, pm);
236
237         ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
238
239         ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
240
241         if (cdet & CH7xxx_CDET_DVI)
242                 return connector_status_connected;
243         return connector_status_disconnected;
244 }
245
246 static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
247                                               struct drm_display_mode *mode)
248 {
249         if (mode->clock > 165000)
250                 return MODE_CLOCK_HIGH;
251
252         return MODE_OK;
253 }
254
255 static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
256                             struct drm_display_mode *mode,
257                             struct drm_display_mode *adjusted_mode)
258 {
259         uint8_t tvco, tpcp, tpd, tlpf, idf;
260
261         if (mode->clock <= 65000) {
262                 tvco = 0x23;
263                 tpcp = 0x08;
264                 tpd = 0x16;
265                 tlpf = 0x60;
266         } else {
267                 tvco = 0x2d;
268                 tpcp = 0x06;
269                 tpd = 0x26;
270                 tlpf = 0xa0;
271         }
272
273         ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
274         ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
275         ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
276         ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
277         ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
278         ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
279         ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
280
281         ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
282
283         idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
284         if (mode->flags & DRM_MODE_FLAG_PHSYNC)
285                 idf |= CH7xxx_IDF_HSP;
286
287         if (mode->flags & DRM_MODE_FLAG_PVSYNC)
288                 idf |= CH7xxx_IDF_HSP;
289
290         ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
291 }
292
293 /* set the CH7xxx power state */
294 static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
295 {
296         if (mode == DRM_MODE_DPMS_ON)
297                 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
298         else
299                 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
300 }
301
302 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
303 {
304         int i;
305
306         for (i = 0; i < CH7xxx_NUM_REGS; i++) {
307                 uint8_t val;
308                 if ((i % 8) == 0 )
309                         DRM_LOG_KMS("\n %02X: ", i);
310                 ch7xxx_readb(dvo, i, &val);
311                 DRM_LOG_KMS("%02X ", val);
312         }
313 }
314
315 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
316 {
317         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
318
319         if (ch7xxx) {
320                 kfree(ch7xxx);
321                 dvo->dev_priv = NULL;
322         }
323 }
324
325 struct intel_dvo_dev_ops ch7xxx_ops = {
326         .init = ch7xxx_init,
327         .detect = ch7xxx_detect,
328         .mode_valid = ch7xxx_mode_valid,
329         .mode_set = ch7xxx_mode_set,
330         .dpms = ch7xxx_dpms,
331         .dump_regs = ch7xxx_dump_regs,
332         .destroy = ch7xxx_destroy,
333 };