diff options
author | Francisco Jerez <currojerez@riseup.net> | 2010-07-19 09:55:08 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-07-25 21:42:30 -0400 |
commit | 6d416d80f720f71e2dfe903d672bcca071822538 (patch) | |
tree | 9b5739051504e8b1674d797c045daffcfc3b6b2a /drivers | |
parent | 6d6a413aa23c8bc7a5787596e06f3d6d8d4f11c7 (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')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_i2c.c | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_i2c.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_tv.c | 115 |
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 | ||
281 | bool | ||
282 | nouveau_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 | |||
292 | int | ||
293 | nouveau_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"); | ||
310 | out: | ||
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 { | |||
45 | int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); | 45 | int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); |
46 | void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); | 46 | void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); |
47 | struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); | 47 | struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); |
48 | bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); | ||
49 | int nouveau_i2c_identify(struct drm_device *dev, const char *what, | ||
50 | struct i2c_board_info *info, int index); | ||
48 | 51 | ||
49 | int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, | 52 | int 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 | ||
37 | static struct { | 37 | static 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 | ||
55 | static 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 | |||
65 | int nv04_tv_identify(struct drm_device *dev, int i2c_index) | 50 | int 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 | ||
215 | static void nv04_tv_destroy(struct drm_encoder *encoder) | 172 | static 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 | ||
182 | static const struct drm_encoder_funcs nv04_tv_funcs = { | ||
183 | .destroy = nv04_tv_destroy, | ||
184 | }; | ||
185 | |||
226 | int | 186 | int |
227 | nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) | 187 | nv04_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 | ||
304 | fail: | 258 | fail_cleanup: |
305 | drm_encoder_cleanup(encoder); | 259 | drm_encoder_cleanup(encoder); |
306 | 260 | kfree(hfuncs); | |
261 | fail_free: | ||
307 | kfree(nv_encoder); | 262 | kfree(nv_encoder); |
308 | return ret; | 263 | return ret; |
309 | } | 264 | } |