aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
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
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')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c34
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.h3
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c115
4 files changed, 75 insertions, 99 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 7f749d281df9..27df0063131e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -139,26 +139,10 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
139 struct nouveau_encoder **pnv_encoder) 139 struct nouveau_encoder **pnv_encoder)
140{ 140{
141 struct drm_device *dev = connector->dev; 141 struct drm_device *dev = connector->dev;
142 uint8_t out_buf[] = { 0x0, 0x0}, buf[2];
143 int ret, flags, i; 142 int ret, flags, i;
144 143
145 struct i2c_msg msgs[] = {
146 {
147 .addr = 0x50,
148 .flags = 0,
149 .len = 1,
150 .buf = out_buf,
151 },
152 {
153 .addr = 0x50,
154 .flags = I2C_M_RD,
155 .len = 1,
156 .buf = buf,
157 }
158 };
159
160 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 144 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
161 struct nouveau_i2c_chan *i2c = NULL; 145 struct nouveau_i2c_chan *i2c;
162 struct nouveau_encoder *nv_encoder; 146 struct nouveau_encoder *nv_encoder;
163 struct drm_mode_object *obj; 147 struct drm_mode_object *obj;
164 int id; 148 int id;
@@ -178,10 +162,10 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
178 continue; 162 continue;
179 163
180 nouveau_connector_ddc_prepare(connector, &flags); 164 nouveau_connector_ddc_prepare(connector, &flags);
181 ret = i2c_transfer(&i2c->adapter, msgs, 2); 165 ret = nouveau_probe_i2c_addr(i2c, 0x50);
182 nouveau_connector_ddc_finish(connector, flags); 166 nouveau_connector_ddc_finish(connector, flags);
183 167
184 if (ret == 2) { 168 if (ret) {
185 *pnv_encoder = nv_encoder; 169 *pnv_encoder = nv_encoder;
186 return i2c; 170 return i2c;
187 } 171 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 316a3c7e6eb4..97ba89ef42a0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -278,3 +278,37 @@ nouveau_i2c_find(struct drm_device *dev, int index)
278 return i2c->chan; 278 return i2c->chan;
279} 279}
280 280
281bool
282nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
283{
284 struct i2c_msg msg = {
285 .addr = addr,
286 .len = 0,
287 };
288
289 return i2c_transfer(&i2c->adapter, &msg, 1) == 1;
290}
291
292int
293nouveau_i2c_identify(struct drm_device *dev, const char *what,
294 struct i2c_board_info *info, int index)
295{
296 struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
297 int was_locked, i;
298
299 was_locked = NVLockVgaCrtcs(dev, false);
300 NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
301
302 for (i = 0; info[i].addr; i++) {
303 if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
304 NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
305 goto out;
306 }
307 }
308
309 NV_DEBUG(dev, "No devices found.\n");
310out:
311 NVLockVgaCrtcs(dev, was_locked);
312
313 return info[i].addr ? i : -ENODEV;
314}
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index c8eaf7a9fcbb..6dd2f8713cd1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -45,6 +45,9 @@ struct nouveau_i2c_chan {
45int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); 45int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
46void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); 46void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
47struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); 47struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
48bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
49int nouveau_i2c_identify(struct drm_device *dev, const char *what,
50 struct i2c_board_info *info, int index);
48 51
49int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, 52int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte,
50 uint8_t *read_byte); 53 uint8_t *read_byte);
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}