Loading drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +13 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,24 @@ #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) enum nvkm_i2c_event { NVKM_I2C_PLUG = 1, NVKM_I2C_UNPLUG = 2, NVKM_I2C_IRQ = 4, NVKM_I2C_DONE = 8, NVKM_I2C_ANY = (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | NVKM_I2C_IRQ | NVKM_I2C_DONE), }; struct nouveau_i2c_port { struct nouveau_object base; struct i2c_adapter adapter; struct list_head head; u8 index; int aux; const struct nouveau_i2c_func *func; }; Loading @@ -46,6 +58,7 @@ struct nouveau_i2c_board_info { struct nouveau_i2c { struct nouveau_subdev base; struct nouveau_event *ntfy; struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); Loading drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +65 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ */ #include <core/option.h> #include <core/event.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> Loading Loading @@ -114,6 +115,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, port->adapter.owner = THIS_MODULE; port->adapter.dev.parent = nv_device_base(device); port->index = index; port->aux = -1; port->func = func; if ( algo == &nouveau_i2c_bit_algo && Loading Loading @@ -236,11 +238,59 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, return -ENODEV; } static void nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) { struct nouveau_i2c *i2c = nouveau_i2c(event->priv); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) impl->aux_mask(i2c, type, 1 << port->aux, 0); } static void nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index) { struct nouveau_i2c *i2c = nouveau_i2c(event->priv); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); } static void nouveau_i2c_intr(struct nouveau_subdev *subdev) { struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev); struct nouveau_i2c *i2c = nouveau_i2c(subdev); struct nouveau_i2c_port *port; u32 hi, lo, rq, tx, e; if (impl->aux_stat) { impl->aux_stat(i2c, &hi, &lo, &rq, &tx); if (hi || lo || rq || tx) { list_for_each_entry(port, &i2c->ports, head) { if (e = 0, port->aux < 0) continue; if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; nouveau_event_trigger(i2c->ntfy, e, port->index); } } } } int _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) { struct nouveau_i2c_impl *impl = (void *)nv_oclass(object); struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port; u32 mask; int ret; list_for_each_entry(port, &i2c->ports, head) { Loading @@ -249,6 +299,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) goto fail; } if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); impl->aux_stat(i2c, &mask, &mask, &mask, &mask); } return nouveau_subdev_fini(&i2c->base, suspend); fail: list_for_each_entry_continue_reverse(port, &i2c->ports, head) { Loading Loading @@ -289,6 +344,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object) struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port, *temp; nouveau_event_destroy(&i2c->ntfy); list_for_each_entry_safe(port, temp, &i2c->ports, head) { nouveau_object_ref(NULL, (struct nouveau_object **)&port); } Loading Loading @@ -323,6 +380,7 @@ nouveau_i2c_create_(struct nouveau_object *parent, if (ret) return ret; nv_subdev(i2c)->intr = nouveau_i2c_intr; i2c->find = nouveau_i2c_find; i2c->find_type = nouveau_i2c_find_type; i2c->identify = nouveau_i2c_identify; Loading Loading @@ -379,6 +437,13 @@ nouveau_i2c_create_(struct nouveau_object *parent, } } ret = nouveau_event_create(4, index, &i2c->ntfy); if (ret) return ret; i2c->ntfy->priv = i2c; i2c->ntfy->enable = nouveau_i2c_intr_enable; i2c->ntfy->disable = nouveau_i2c_intr_disable; return 0; } Loading drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c +1 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; port->base.aux = info->drive; port->addr = info->drive; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->drive * 0x50); Loading drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h +15 −0 Original line number Diff line number Diff line Loading @@ -55,7 +55,22 @@ extern const struct i2c_algorithm nouveau_i2c_aux_algo; struct nouveau_i2c_impl { struct nouveau_oclass base; /* supported i2c port classes */ struct nouveau_oclass *sclass; /* number of native dp aux channels present */ int aux; /* read and ack pending interrupts, returning only data * for ports that have not been masked off, while still * performing the ack for anything that was pending. */ void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); /* mask on/off interrupt types for a given set of auxch */ void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32); }; #endif Loading
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +13 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,24 @@ #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) enum nvkm_i2c_event { NVKM_I2C_PLUG = 1, NVKM_I2C_UNPLUG = 2, NVKM_I2C_IRQ = 4, NVKM_I2C_DONE = 8, NVKM_I2C_ANY = (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | NVKM_I2C_IRQ | NVKM_I2C_DONE), }; struct nouveau_i2c_port { struct nouveau_object base; struct i2c_adapter adapter; struct list_head head; u8 index; int aux; const struct nouveau_i2c_func *func; }; Loading @@ -46,6 +58,7 @@ struct nouveau_i2c_board_info { struct nouveau_i2c { struct nouveau_subdev base; struct nouveau_event *ntfy; struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); Loading
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +65 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ */ #include <core/option.h> #include <core/event.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> Loading Loading @@ -114,6 +115,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, port->adapter.owner = THIS_MODULE; port->adapter.dev.parent = nv_device_base(device); port->index = index; port->aux = -1; port->func = func; if ( algo == &nouveau_i2c_bit_algo && Loading Loading @@ -236,11 +238,59 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, return -ENODEV; } static void nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) { struct nouveau_i2c *i2c = nouveau_i2c(event->priv); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) impl->aux_mask(i2c, type, 1 << port->aux, 0); } static void nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index) { struct nouveau_i2c *i2c = nouveau_i2c(event->priv); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); } static void nouveau_i2c_intr(struct nouveau_subdev *subdev) { struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev); struct nouveau_i2c *i2c = nouveau_i2c(subdev); struct nouveau_i2c_port *port; u32 hi, lo, rq, tx, e; if (impl->aux_stat) { impl->aux_stat(i2c, &hi, &lo, &rq, &tx); if (hi || lo || rq || tx) { list_for_each_entry(port, &i2c->ports, head) { if (e = 0, port->aux < 0) continue; if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; nouveau_event_trigger(i2c->ntfy, e, port->index); } } } } int _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) { struct nouveau_i2c_impl *impl = (void *)nv_oclass(object); struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port; u32 mask; int ret; list_for_each_entry(port, &i2c->ports, head) { Loading @@ -249,6 +299,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) goto fail; } if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); impl->aux_stat(i2c, &mask, &mask, &mask, &mask); } return nouveau_subdev_fini(&i2c->base, suspend); fail: list_for_each_entry_continue_reverse(port, &i2c->ports, head) { Loading Loading @@ -289,6 +344,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object) struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port, *temp; nouveau_event_destroy(&i2c->ntfy); list_for_each_entry_safe(port, temp, &i2c->ports, head) { nouveau_object_ref(NULL, (struct nouveau_object **)&port); } Loading Loading @@ -323,6 +380,7 @@ nouveau_i2c_create_(struct nouveau_object *parent, if (ret) return ret; nv_subdev(i2c)->intr = nouveau_i2c_intr; i2c->find = nouveau_i2c_find; i2c->find_type = nouveau_i2c_find_type; i2c->identify = nouveau_i2c_identify; Loading Loading @@ -379,6 +437,13 @@ nouveau_i2c_create_(struct nouveau_object *parent, } } ret = nouveau_event_create(4, index, &i2c->ntfy); if (ret) return ret; i2c->ntfy->priv = i2c; i2c->ntfy->enable = nouveau_i2c_intr_enable; i2c->ntfy->disable = nouveau_i2c_intr_disable; return 0; } Loading
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c +1 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; port->base.aux = info->drive; port->addr = info->drive; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->drive * 0x50); Loading
drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h +15 −0 Original line number Diff line number Diff line Loading @@ -55,7 +55,22 @@ extern const struct i2c_algorithm nouveau_i2c_aux_algo; struct nouveau_i2c_impl { struct nouveau_oclass base; /* supported i2c port classes */ struct nouveau_oclass *sclass; /* number of native dp aux channels present */ int aux; /* read and ack pending interrupts, returning only data * for ports that have not been masked off, while still * performing the ack for anything that was pending. */ void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); /* mask on/off interrupt types for a given set of auxch */ void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32); }; #endif