aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/dvo_tfp410.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2008-11-07 17:24:08 -0500
committerDave Airlie <airlied@linux.ie>2008-12-29 02:47:23 -0500
commit79e539453b34e35f39299a899d263b0a1f1670bd (patch)
tree6d1285f2b78fab399aab75a3557b7d6bc0dbd112 /drivers/gpu/drm/i915/dvo_tfp410.c
parentf453ba0460742ad027ae0c4c7d61e62817b3e7ef (diff)
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs. Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are supported. HDMI, DisplayPort and additional SDVO output support will follow. Support for the mode setting code is controlled by the new 'modeset' module option. A new config option, CONFIG_DRM_I915_KMS controls the default behavior, and whether a PCI ID list is built into the module for use by user level module utilities. Note that if mode setting is enabled, user level drivers that access display registers directly or that don't use the kernel graphics memory manager will likely corrupt kernel graphics memory, disrupt output configuration (possibly leading to hangs and/or blank displays), and prevent panic/oops messages from appearing. So use caution when enabling this code; be sure your user level code supports the new interfaces. A new SysRq key, 'g', provides emergency support for switching back to the kernel's framebuffer console; which is useful for testing. Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i915/dvo_tfp410.c')
-rw-r--r--drivers/gpu/drm/i915/dvo_tfp410.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
new file mode 100644
index 000000000000..207fda806ebf
--- /dev/null
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -0,0 +1,335 @@
1/*
2 * Copyright © 2007 Dave Mueller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Dave Mueller <dave.mueller@gmx.ch>
25 *
26 */
27
28#include "dvo.h"
29
30/* register definitions according to the TFP410 data sheet */
31#define TFP410_VID 0x014C
32#define TFP410_DID 0x0410
33
34#define TFP410_VID_LO 0x00
35#define TFP410_VID_HI 0x01
36#define TFP410_DID_LO 0x02
37#define TFP410_DID_HI 0x03
38#define TFP410_REV 0x04
39
40#define TFP410_CTL_1 0x08
41#define TFP410_CTL_1_TDIS (1<<6)
42#define TFP410_CTL_1_VEN (1<<5)
43#define TFP410_CTL_1_HEN (1<<4)
44#define TFP410_CTL_1_DSEL (1<<3)
45#define TFP410_CTL_1_BSEL (1<<2)
46#define TFP410_CTL_1_EDGE (1<<1)
47#define TFP410_CTL_1_PD (1<<0)
48
49#define TFP410_CTL_2 0x09
50#define TFP410_CTL_2_VLOW (1<<7)
51#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
52#define TFP410_CTL_2_MSEL (1<<4)
53#define TFP410_CTL_2_TSEL (1<<3)
54#define TFP410_CTL_2_RSEN (1<<2)
55#define TFP410_CTL_2_HTPLG (1<<1)
56#define TFP410_CTL_2_MDI (1<<0)
57
58#define TFP410_CTL_3 0x0A
59#define TFP410_CTL_3_DK_MASK (0x7<<5)
60#define TFP410_CTL_3_DK (1<<5)
61#define TFP410_CTL_3_DKEN (1<<4)
62#define TFP410_CTL_3_CTL_MASK (0x7<<1)
63#define TFP410_CTL_3_CTL (1<<1)
64
65#define TFP410_USERCFG 0x0B
66
67#define TFP410_DE_DLY 0x32
68
69#define TFP410_DE_CTL 0x33
70#define TFP410_DE_CTL_DEGEN (1<<6)
71#define TFP410_DE_CTL_VSPOL (1<<5)
72#define TFP410_DE_CTL_HSPOL (1<<4)
73#define TFP410_DE_CTL_DEDLY8 (1<<0)
74
75#define TFP410_DE_TOP 0x34
76
77#define TFP410_DE_CNT_LO 0x36
78#define TFP410_DE_CNT_HI 0x37
79
80#define TFP410_DE_LIN_LO 0x38
81#define TFP410_DE_LIN_HI 0x39
82
83#define TFP410_H_RES_LO 0x3A
84#define TFP410_H_RES_HI 0x3B
85
86#define TFP410_V_RES_LO 0x3C
87#define TFP410_V_RES_HI 0x3D
88
89struct tfp410_save_rec {
90 uint8_t ctl1;
91 uint8_t ctl2;
92};
93
94struct tfp410_priv {
95 bool quiet;
96
97 struct tfp410_save_rec saved_reg;
98 struct tfp410_save_rec mode_reg;
99};
100
101static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
102{
103 struct tfp410_priv *tfp = dvo->dev_priv;
104 struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
105 u8 out_buf[2];
106 u8 in_buf[2];
107
108 struct i2c_msg msgs[] = {
109 {
110 .addr = i2cbus->slave_addr,
111 .flags = 0,
112 .len = 1,
113 .buf = out_buf,
114 },
115 {
116 .addr = i2cbus->slave_addr,
117 .flags = I2C_M_RD,
118 .len = 1,
119 .buf = in_buf,
120 }
121 };
122
123 out_buf[0] = addr;
124 out_buf[1] = 0;
125
126 if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
127 *ch = in_buf[0];
128 return true;
129 };
130
131 if (!tfp->quiet) {
132 DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
133 addr, i2cbus->adapter.name, i2cbus->slave_addr);
134 }
135 return false;
136}
137
138static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
139{
140 struct tfp410_priv *tfp = dvo->dev_priv;
141 struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
142 uint8_t out_buf[2];
143 struct i2c_msg msg = {
144 .addr = i2cbus->slave_addr,
145 .flags = 0,
146 .len = 2,
147 .buf = out_buf,
148 };
149
150 out_buf[0] = addr;
151 out_buf[1] = ch;
152
153 if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
154 return true;
155
156 if (!tfp->quiet) {
157 DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
158 addr, i2cbus->adapter.name, i2cbus->slave_addr);
159 }
160
161 return false;
162}
163
164static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
165{
166 uint8_t ch1, ch2;
167
168 if (tfp410_readb(dvo, addr+0, &ch1) &&
169 tfp410_readb(dvo, addr+1, &ch2))
170 return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
171
172 return -1;
173}
174
175/* Ti TFP410 driver for chip on i2c bus */
176static bool tfp410_init(struct intel_dvo_device *dvo,
177 struct intel_i2c_chan *i2cbus)
178{
179 /* this will detect the tfp410 chip on the specified i2c bus */
180 struct tfp410_priv *tfp;
181 int id;
182
183 tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
184 if (tfp == NULL)
185 return false;
186
187 dvo->i2c_bus = i2cbus;
188 dvo->i2c_bus->slave_addr = dvo->slave_addr;
189 dvo->dev_priv = tfp;
190 tfp->quiet = true;
191
192 if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
193 DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
194 id, i2cbus->adapter.name, i2cbus->slave_addr);
195 goto out;
196 }
197
198 if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
199 DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
200 id, i2cbus->adapter.name, i2cbus->slave_addr);
201 goto out;
202 }
203 tfp->quiet = false;
204 return true;
205out:
206 kfree(tfp);
207 return false;
208}
209
210static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
211{
212 enum drm_connector_status ret = connector_status_disconnected;
213 uint8_t ctl2;
214
215 if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
216 if (ctl2 & TFP410_CTL_2_HTPLG)
217 ret = connector_status_connected;
218 else
219 ret = connector_status_disconnected;
220 }
221
222 return ret;
223}
224
225static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
226 struct drm_display_mode *mode)
227{
228 return MODE_OK;
229}
230
231static void tfp410_mode_set(struct intel_dvo_device *dvo,
232 struct drm_display_mode *mode,
233 struct drm_display_mode *adjusted_mode)
234{
235 /* As long as the basics are set up, since we don't have clock dependencies
236 * in the mode setup, we can just leave the registers alone and everything
237 * will work fine.
238 */
239 /* don't do much */
240 return;
241}
242
243/* set the tfp410 power state */
244static void tfp410_dpms(struct intel_dvo_device *dvo, int mode)
245{
246 uint8_t ctl1;
247
248 if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
249 return;
250
251 if (mode == DRM_MODE_DPMS_ON)
252 ctl1 |= TFP410_CTL_1_PD;
253 else
254 ctl1 &= ~TFP410_CTL_1_PD;
255
256 tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
257}
258
259static void tfp410_dump_regs(struct intel_dvo_device *dvo)
260{
261 uint8_t val, val2;
262
263 tfp410_readb(dvo, TFP410_REV, &val);
264 DRM_DEBUG("TFP410_REV: 0x%02X\n", val);
265 tfp410_readb(dvo, TFP410_CTL_1, &val);
266 DRM_DEBUG("TFP410_CTL1: 0x%02X\n", val);
267 tfp410_readb(dvo, TFP410_CTL_2, &val);
268 DRM_DEBUG("TFP410_CTL2: 0x%02X\n", val);
269 tfp410_readb(dvo, TFP410_CTL_3, &val);
270 DRM_DEBUG("TFP410_CTL3: 0x%02X\n", val);
271 tfp410_readb(dvo, TFP410_USERCFG, &val);
272 DRM_DEBUG("TFP410_USERCFG: 0x%02X\n", val);
273 tfp410_readb(dvo, TFP410_DE_DLY, &val);
274 DRM_DEBUG("TFP410_DE_DLY: 0x%02X\n", val);
275 tfp410_readb(dvo, TFP410_DE_CTL, &val);
276 DRM_DEBUG("TFP410_DE_CTL: 0x%02X\n", val);
277 tfp410_readb(dvo, TFP410_DE_TOP, &val);
278 DRM_DEBUG("TFP410_DE_TOP: 0x%02X\n", val);
279 tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
280 tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
281 DRM_DEBUG("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
282 tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
283 tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
284 DRM_DEBUG("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
285 tfp410_readb(dvo, TFP410_H_RES_LO, &val);
286 tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
287 DRM_DEBUG("TFP410_H_RES: 0x%02X%02X\n", val2, val);
288 tfp410_readb(dvo, TFP410_V_RES_LO, &val);
289 tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
290 DRM_DEBUG("TFP410_V_RES: 0x%02X%02X\n", val2, val);
291}
292
293static void tfp410_save(struct intel_dvo_device *dvo)
294{
295 struct tfp410_priv *tfp = dvo->dev_priv;
296
297 if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1))
298 return;
299
300 if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2))
301 return;
302}
303
304static void tfp410_restore(struct intel_dvo_device *dvo)
305{
306 struct tfp410_priv *tfp = dvo->dev_priv;
307
308 /* Restore it powered down initially */
309 tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1);
310
311 tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2);
312 tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1);
313}
314
315static void tfp410_destroy(struct intel_dvo_device *dvo)
316{
317 struct tfp410_priv *tfp = dvo->dev_priv;
318
319 if (tfp) {
320 kfree(tfp);
321 dvo->dev_priv = NULL;
322 }
323}
324
325struct intel_dvo_dev_ops tfp410_ops = {
326 .init = tfp410_init,
327 .detect = tfp410_detect,
328 .mode_valid = tfp410_mode_valid,
329 .mode_set = tfp410_mode_set,
330 .dpms = tfp410_dpms,
331 .dump_regs = tfp410_dump_regs,
332 .save = tfp410_save,
333 .restore = tfp410_restore,
334 .destroy = tfp410_destroy,
335};