aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-13 00:47:36 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 02:09:16 -0400
commit3668a339d6e7d47f777b8ce86bd7ca53451df6bb (patch)
treee5b5f3a569c34511602f1bcf2ae95125e5ec1431
parentc26fe843560fe01b4b652ee21952d33f60f4e699 (diff)
drm/nouveau/i2c: add interfaces to support handling aux channel interrupts
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/i2c.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c65
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h15
4 files changed, 94 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
index 857a11025dac..a4c9c8b5cb70 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
@@ -14,12 +14,24 @@
14#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) 14#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
15#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) 15#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
16 16
17enum nvkm_i2c_event {
18 NVKM_I2C_PLUG = 1,
19 NVKM_I2C_UNPLUG = 2,
20 NVKM_I2C_IRQ = 4,
21 NVKM_I2C_DONE = 8,
22 NVKM_I2C_ANY = (NVKM_I2C_PLUG |
23 NVKM_I2C_UNPLUG |
24 NVKM_I2C_IRQ |
25 NVKM_I2C_DONE),
26};
27
17struct nouveau_i2c_port { 28struct nouveau_i2c_port {
18 struct nouveau_object base; 29 struct nouveau_object base;
19 struct i2c_adapter adapter; 30 struct i2c_adapter adapter;
20 31
21 struct list_head head; 32 struct list_head head;
22 u8 index; 33 u8 index;
34 int aux;
23 35
24 const struct nouveau_i2c_func *func; 36 const struct nouveau_i2c_func *func;
25}; 37};
@@ -46,6 +58,7 @@ struct nouveau_i2c_board_info {
46 58
47struct nouveau_i2c { 59struct nouveau_i2c {
48 struct nouveau_subdev base; 60 struct nouveau_subdev base;
61 struct nouveau_event *ntfy;
49 62
50 struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); 63 struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
51 struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); 64 struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
index 1c6fa86e9425..0e36057609e7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <core/option.h> 25#include <core/option.h>
26#include <core/event.h>
26 27
27#include <subdev/bios.h> 28#include <subdev/bios.h>
28#include <subdev/bios/dcb.h> 29#include <subdev/bios/dcb.h>
@@ -114,6 +115,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
114 port->adapter.owner = THIS_MODULE; 115 port->adapter.owner = THIS_MODULE;
115 port->adapter.dev.parent = nv_device_base(device); 116 port->adapter.dev.parent = nv_device_base(device);
116 port->index = index; 117 port->index = index;
118 port->aux = -1;
117 port->func = func; 119 port->func = func;
118 120
119 if ( algo == &nouveau_i2c_bit_algo && 121 if ( algo == &nouveau_i2c_bit_algo &&
@@ -236,11 +238,59 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
236 return -ENODEV; 238 return -ENODEV;
237} 239}
238 240
241static void
242nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
243{
244 struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
245 struct nouveau_i2c_port *port = i2c->find(i2c, index);
246 const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
247 if (port && port->aux >= 0)
248 impl->aux_mask(i2c, type, 1 << port->aux, 0);
249}
250
251static void
252nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index)
253{
254 struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
255 struct nouveau_i2c_port *port = i2c->find(i2c, index);
256 const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
257 if (port && port->aux >= 0)
258 impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
259}
260
261static void
262nouveau_i2c_intr(struct nouveau_subdev *subdev)
263{
264 struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev);
265 struct nouveau_i2c *i2c = nouveau_i2c(subdev);
266 struct nouveau_i2c_port *port;
267 u32 hi, lo, rq, tx, e;
268
269 if (impl->aux_stat) {
270 impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
271 if (hi || lo || rq || tx) {
272 list_for_each_entry(port, &i2c->ports, head) {
273 if (e = 0, port->aux < 0)
274 continue;
275
276 if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
277 if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
278 if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
279 if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
280
281 nouveau_event_trigger(i2c->ntfy, e, port->index);
282 }
283 }
284 }
285}
286
239int 287int
240_nouveau_i2c_fini(struct nouveau_object *object, bool suspend) 288_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
241{ 289{
290 struct nouveau_i2c_impl *impl = (void *)nv_oclass(object);
242 struct nouveau_i2c *i2c = (void *)object; 291 struct nouveau_i2c *i2c = (void *)object;
243 struct nouveau_i2c_port *port; 292 struct nouveau_i2c_port *port;
293 u32 mask;
244 int ret; 294 int ret;
245 295
246 list_for_each_entry(port, &i2c->ports, head) { 296 list_for_each_entry(port, &i2c->ports, head) {
@@ -249,6 +299,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
249 goto fail; 299 goto fail;
250 } 300 }
251 301
302 if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
303 impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
304 impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
305 }
306
252 return nouveau_subdev_fini(&i2c->base, suspend); 307 return nouveau_subdev_fini(&i2c->base, suspend);
253fail: 308fail:
254 list_for_each_entry_continue_reverse(port, &i2c->ports, head) { 309 list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
@@ -289,6 +344,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object)
289 struct nouveau_i2c *i2c = (void *)object; 344 struct nouveau_i2c *i2c = (void *)object;
290 struct nouveau_i2c_port *port, *temp; 345 struct nouveau_i2c_port *port, *temp;
291 346
347 nouveau_event_destroy(&i2c->ntfy);
348
292 list_for_each_entry_safe(port, temp, &i2c->ports, head) { 349 list_for_each_entry_safe(port, temp, &i2c->ports, head) {
293 nouveau_object_ref(NULL, (struct nouveau_object **)&port); 350 nouveau_object_ref(NULL, (struct nouveau_object **)&port);
294 } 351 }
@@ -323,6 +380,7 @@ nouveau_i2c_create_(struct nouveau_object *parent,
323 if (ret) 380 if (ret)
324 return ret; 381 return ret;
325 382
383 nv_subdev(i2c)->intr = nouveau_i2c_intr;
326 i2c->find = nouveau_i2c_find; 384 i2c->find = nouveau_i2c_find;
327 i2c->find_type = nouveau_i2c_find_type; 385 i2c->find_type = nouveau_i2c_find_type;
328 i2c->identify = nouveau_i2c_identify; 386 i2c->identify = nouveau_i2c_identify;
@@ -379,6 +437,13 @@ nouveau_i2c_create_(struct nouveau_object *parent,
379 } 437 }
380 } 438 }
381 439
440 ret = nouveau_event_create(4, index, &i2c->ntfy);
441 if (ret)
442 return ret;
443
444 i2c->ntfy->priv = i2c;
445 i2c->ntfy->enable = nouveau_i2c_intr_enable;
446 i2c->ntfy->disable = nouveau_i2c_intr_disable;
382 return 0; 447 return 0;
383} 448}
384 449
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
index 768b849a7370..900f464c716c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
@@ -232,6 +232,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
232 if (ret) 232 if (ret)
233 return ret; 233 return ret;
234 234
235 port->base.aux = info->drive;
235 port->addr = info->drive; 236 port->addr = info->drive;
236 if (info->share != DCB_I2C_UNUSED) { 237 if (info->share != DCB_I2C_UNUSED) {
237 port->ctrl = 0x00e500 + (info->drive * 0x50); 238 port->ctrl = 0x00e500 + (info->drive * 0x50);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
index ec1934205cf5..27b9a9717229 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
@@ -55,7 +55,22 @@ extern const struct i2c_algorithm nouveau_i2c_aux_algo;
55 55
56struct nouveau_i2c_impl { 56struct nouveau_i2c_impl {
57 struct nouveau_oclass base; 57 struct nouveau_oclass base;
58
59 /* supported i2c port classes */
58 struct nouveau_oclass *sclass; 60 struct nouveau_oclass *sclass;
61
62 /* number of native dp aux channels present */
63 int aux;
64
65 /* read and ack pending interrupts, returning only data
66 * for ports that have not been masked off, while still
67 * performing the ack for anything that was pending.
68 */
69 void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
70
71 /* mask on/off interrupt types for a given set of auxch
72 */
73 void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32);
59}; 74};
60 75
61#endif 76#endif