aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv04_tv.c
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-07-19 09:55:08 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-07-25 21:42:30 -0400
commit6d416d80f720f71e2dfe903d672bcca071822538 (patch)
tree9b5739051504e8b1674d797c045daffcfc3b6b2a /drivers/gpu/drm/nouveau/nv04_tv.c
parent6d6a413aa23c8bc7a5787596e06f3d6d8d4f11c7 (diff)
drm/nouveau: Add some generic I2C gadget detection code.
Clean up and move the external TV encoder detection code to nouveau_i2c.c, it's also going to be useful for external TMDS and DDC detection. Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c115
1 files changed, 35 insertions, 80 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 84b5954a8efb..8de1eef3594a 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -34,69 +34,26 @@
34 34
35#include "i2c/ch7006.h" 35#include "i2c/ch7006.h"
36 36
37static struct { 37static struct i2c_board_info nv04_tv_encoder_info[] = {
38 struct i2c_board_info board_info;
39 struct drm_encoder_funcs funcs;
40 struct drm_encoder_helper_funcs hfuncs;
41 void *params;
42
43} nv04_tv_encoder_info[] = {
44 { 38 {
45 .board_info = { I2C_BOARD_INFO("ch7006", 0x75) }, 39 I2C_BOARD_INFO("ch7006", 0x75),
46 .params = &(struct ch7006_encoder_params) { 40 .platform_data = &(struct ch7006_encoder_params) {
47 CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, 41 CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
48 0, 0, 0, 42 0, 0, 0,
49 CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, 43 CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
50 CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC 44 CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
51 }, 45 }
52 }, 46 },
47 { }
53}; 48};
54 49
55static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr)
56{
57 struct i2c_msg msg = {
58 .addr = addr,
59 .len = 0,
60 };
61
62 return i2c_transfer(adapter, &msg, 1) == 1;
63}
64
65int nv04_tv_identify(struct drm_device *dev, int i2c_index) 50int nv04_tv_identify(struct drm_device *dev, int i2c_index)
66{ 51{
67 struct nouveau_i2c_chan *i2c; 52 return nouveau_i2c_identify(dev, "TV encoder",
68 bool was_locked; 53 nv04_tv_encoder_info, i2c_index);
69 int i, ret;
70
71 NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index);
72
73 i2c = nouveau_i2c_find(dev, i2c_index);
74 if (!i2c)
75 return -ENODEV;
76
77 was_locked = NVLockVgaCrtcs(dev, false);
78
79 for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) {
80 if (probe_i2c_addr(&i2c->adapter,
81 nv04_tv_encoder_info[i].board_info.addr)) {
82 ret = i;
83 break;
84 }
85 }
86
87 if (i < ARRAY_SIZE(nv04_tv_encoder_info)) {
88 NV_TRACE(dev, "Detected TV encoder: %s\n",
89 nv04_tv_encoder_info[i].board_info.type);
90
91 } else {
92 NV_TRACE(dev, "No TV encoders found.\n");
93 i = -ENODEV;
94 }
95
96 NVLockVgaCrtcs(dev, was_locked);
97 return i;
98} 54}
99 55
56
100#define PLLSEL_TV_CRTC1_MASK \ 57#define PLLSEL_TV_CRTC1_MASK \
101 (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ 58 (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \
102 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1) 59 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
@@ -214,32 +171,33 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
214 171
215static void nv04_tv_destroy(struct drm_encoder *encoder) 172static void nv04_tv_destroy(struct drm_encoder *encoder)
216{ 173{
217 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
218
219 to_encoder_slave(encoder)->slave_funcs->destroy(encoder); 174 to_encoder_slave(encoder)->slave_funcs->destroy(encoder);
220 175
221 drm_encoder_cleanup(encoder); 176 drm_encoder_cleanup(encoder);
222 177
223 kfree(nv_encoder); 178 kfree(encoder->helper_private);
179 kfree(nouveau_encoder(encoder));
224} 180}
225 181
182static const struct drm_encoder_funcs nv04_tv_funcs = {
183 .destroy = nv04_tv_destroy,
184};
185
226int 186int
227nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) 187nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
228{ 188{
229 struct nouveau_encoder *nv_encoder; 189 struct nouveau_encoder *nv_encoder;
230 struct drm_encoder *encoder; 190 struct drm_encoder *encoder;
231 struct drm_device *dev = connector->dev; 191 struct drm_device *dev = connector->dev;
232 struct drm_nouveau_private *dev_priv = dev->dev_private; 192 struct drm_encoder_helper_funcs *hfuncs;
233 struct i2c_adapter *adap; 193 struct drm_encoder_slave_funcs *sfuncs;
234 struct drm_encoder_funcs *funcs = NULL; 194 struct nouveau_i2c_chan *i2c =
235 struct drm_encoder_helper_funcs *hfuncs = NULL; 195 nouveau_i2c_find(dev, entry->i2c_index);
236 struct drm_encoder_slave_funcs *sfuncs = NULL;
237 int i2c_index = entry->i2c_index;
238 int type, ret; 196 int type, ret;
239 bool was_locked; 197 bool was_locked;
240 198
241 /* Ensure that we can talk to this encoder */ 199 /* Ensure that we can talk to this encoder */
242 type = nv04_tv_identify(dev, i2c_index); 200 type = nv04_tv_identify(dev, entry->i2c_index);
243 if (type < 0) 201 if (type < 0)
244 return type; 202 return type;
245 203
@@ -248,41 +206,37 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
248 if (!nv_encoder) 206 if (!nv_encoder)
249 return -ENOMEM; 207 return -ENOMEM;
250 208
209 hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL);
210 if (!hfuncs) {
211 ret = -ENOMEM;
212 goto fail_free;
213 }
214
251 /* Initialize the common members */ 215 /* Initialize the common members */
252 encoder = to_drm_encoder(nv_encoder); 216 encoder = to_drm_encoder(nv_encoder);
253 217
254 funcs = &nv04_tv_encoder_info[type].funcs; 218 drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC);
255 hfuncs = &nv04_tv_encoder_info[type].hfuncs;
256
257 drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC);
258 drm_encoder_helper_add(encoder, hfuncs); 219 drm_encoder_helper_add(encoder, hfuncs);
259 220
260 encoder->possible_crtcs = entry->heads; 221 encoder->possible_crtcs = entry->heads;
261 encoder->possible_clones = 0; 222 encoder->possible_clones = 0;
262
263 nv_encoder->dcb = entry; 223 nv_encoder->dcb = entry;
264 nv_encoder->or = ffs(entry->or) - 1; 224 nv_encoder->or = ffs(entry->or) - 1;
265 225
266 /* Run the slave-specific initialization */ 226 /* Run the slave-specific initialization */
267 adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter;
268
269 was_locked = NVLockVgaCrtcs(dev, false); 227 was_locked = NVLockVgaCrtcs(dev, false);
270 228
271 ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), adap, 229 ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
272 &nv04_tv_encoder_info[type].board_info); 230 &i2c->adapter, &nv04_tv_encoder_info[type]);
273 231
274 NVLockVgaCrtcs(dev, was_locked); 232 NVLockVgaCrtcs(dev, was_locked);
275 233
276 if (ret < 0) 234 if (ret < 0)
277 goto fail; 235 goto fail_cleanup;
278 236
279 /* Fill the function pointers */ 237 /* Fill the function pointers */
280 sfuncs = to_encoder_slave(encoder)->slave_funcs; 238 sfuncs = to_encoder_slave(encoder)->slave_funcs;
281 239
282 *funcs = (struct drm_encoder_funcs) {
283 .destroy = nv04_tv_destroy,
284 };
285
286 *hfuncs = (struct drm_encoder_helper_funcs) { 240 *hfuncs = (struct drm_encoder_helper_funcs) {
287 .dpms = nv04_tv_dpms, 241 .dpms = nv04_tv_dpms,
288 .save = sfuncs->save, 242 .save = sfuncs->save,
@@ -294,16 +248,17 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
294 .detect = sfuncs->detect, 248 .detect = sfuncs->detect,
295 }; 249 };
296 250
297 /* Set the slave encoder configuration */ 251 /* Attach it to the specified connector. */
298 sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); 252 sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
299 sfuncs->create_resources(encoder, connector); 253 sfuncs->create_resources(encoder, connector);
300
301 drm_mode_connector_attach_encoder(connector, encoder); 254 drm_mode_connector_attach_encoder(connector, encoder);
255
302 return 0; 256 return 0;
303 257
304fail: 258fail_cleanup:
305 drm_encoder_cleanup(encoder); 259 drm_encoder_cleanup(encoder);
306 260 kfree(hfuncs);
261fail_free:
307 kfree(nv_encoder); 262 kfree(nv_encoder);
308 return ret; 263 return ret;
309} 264}