Loading drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ struct nvkm_disp { struct nvkm_engine engine; struct list_head outp; struct list_head conn; struct nvkm_event hpd; struct nvkm_event vblank; Loading drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +13 −8 Original line number Diff line number Diff line nvkm-y += nvkm/engine/disp/base.o nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/g84.o Loading @@ -13,17 +10,25 @@ nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm204.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o nvkm-y += nvkm/engine/disp/sorg94.o nvkm-y += nvkm/engine/disp/sorgf110.o nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/dport.o nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/hdagt215.o nvkm-y += nvkm/engine/disp/hdagf110.o nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o nvkm-y += nvkm/engine/disp/hdmigf110.o nvkm-y += nvkm/engine/disp/hdmigk104.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o nvkm-y += nvkm/engine/disp/sorg94.o nvkm-y += nvkm/engine/disp/sorgf110.o nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/vga.o drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +130 −36 Original line number Diff line number Diff line Loading @@ -118,29 +118,25 @@ int _nvkm_disp_fini(struct nvkm_object *object, bool suspend) { struct nvkm_disp *disp = (void *)object; struct nvkm_connector *conn; struct nvkm_output *outp; int ret; list_for_each_entry(outp, &disp->outp, head) { ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend); if (ret && suspend) goto fail_outp; nvkm_output_fini(outp); } return nvkm_engine_fini(&disp->engine, suspend); fail_outp: list_for_each_entry_continue_reverse(outp, &disp->outp, head) { nv_ofuncs(outp)->init(nv_object(outp)); list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_fini(conn); } return ret; return nvkm_engine_fini(&disp->engine, suspend); } int _nvkm_disp_init(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; struct nvkm_connector *conn; struct nvkm_output *outp; int ret; Loading @@ -148,17 +144,12 @@ _nvkm_disp_init(struct nvkm_object *object) if (ret) return ret; list_for_each_entry(outp, &disp->outp, head) { ret = nv_ofuncs(outp)->init(nv_object(outp)); if (ret) goto fail_outp; list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_init(conn); } return ret; fail_outp: list_for_each_entry_continue_reverse(outp, &disp->outp, head) { nv_ofuncs(outp)->fini(nv_object(outp), false); list_for_each_entry(outp, &disp->outp, head) { nvkm_output_init(outp); } return ret; Loading @@ -168,15 +159,22 @@ void _nvkm_disp_dtor(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; struct nvkm_output *outp, *outt; struct nvkm_connector *conn; struct nvkm_output *outp; nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->hpd); if (disp->outp.next) { list_for_each_entry_safe(outp, outt, &disp->outp, head) { nvkm_object_ref(NULL, (struct nvkm_object **)&outp); while (!list_empty(&disp->outp)) { outp = list_first_entry(&disp->outp, typeof(*outp), head); list_del(&outp->head); nvkm_output_del(&outp); } while (!list_empty(&disp->conn)) { conn = list_first_entry(&disp->conn, typeof(*conn), head); list_del(&conn->head); nvkm_connector_del(&conn); } nvkm_engine_destroy(&disp->engine); Loading @@ -188,10 +186,12 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, const char *extname, int length, void **pobject) { struct nvkm_disp_impl *impl = (void *)oclass; struct nvkm_bios *bios = nvkm_bios(parent); struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; struct nvkm_disp *disp; struct nvkm_oclass **sclass; struct nvkm_object *object; struct nvkm_connector *conn; struct nvkm_output *outp, *outt, *pair; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; u32 data; Loading @@ -204,30 +204,124 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, return ret; INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); /* create output objects for each display path in the vbios */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { const struct nvkm_disp_func_outp *outps; int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); if (dcbE.type == DCB_OUTPUT_UNUSED) continue; if (dcbE.type == DCB_OUTPUT_EOL) break; data = dcbE.location << 4 | dcbE.type; outp = NULL; oclass = nvkm_output_oclass; sclass = impl->outp; while (sclass && sclass[0]) { if (sclass[0]->handle == data) { oclass = sclass[0]; break; switch (dcbE.location) { case 0: outps = &impl->outp.internal; break; case 1: outps = &impl->outp.external; break; default: nvkm_warn(&disp->engine.subdev, "dcb %d locn %d unknown\n", i, dcbE.location); continue; } sclass++; switch (dcbE.type) { case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; case DCB_OUTPUT_TV : ctor = outps->tv ; break; case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; case DCB_OUTPUT_DP : ctor = outps->dp ; break; default: nvkm_warn(&disp->engine.subdev, "dcb %d type %d unknown\n", i, dcbE.type); continue; } nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object); if (ctor) ret = ctor(disp, i, &dcbE, &outp); else ret = -ENODEV; if (ret) { if (ret == -ENODEV) { nvkm_debug(&disp->engine.subdev, "dcb %d %d/%d not supported\n", i, dcbE.location, dcbE.type); continue; } nvkm_error(&disp->engine.subdev, "failed to create output %d\n", i); nvkm_output_del(&outp); continue; } list_add_tail(&outp->head, &disp->outp); hpd = max(hpd, (u8)(dcbE.connector + 1)); } /* create connector objects based on the outputs we support */ list_for_each_entry_safe(outp, outt, &disp->outp, head) { /* bios data *should* give us the most useful information */ data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); /* no bios connector data... */ if (!data) { /* heuristic: anything with the same ccb index is * considered to be on the same connector, any * output path without an associated ccb entry will * be put on its own connector */ int ccb_index = outp->info.i2c_index; if (ccb_index != 0xf) { list_for_each_entry(pair, &disp->outp, head) { if (pair->info.i2c_index == ccb_index) { outp->conn = pair->conn; break; } } } /* connector shared with another output path */ if (outp->conn) continue; memset(&connE, 0x00, sizeof(connE)); connE.type = DCB_CONNECTOR_NONE; i = -1; } else { i = outp->info.connector; } /* check that we haven't already created this connector */ list_for_each_entry(conn, &disp->conn, head) { if (conn->index == outp->info.connector) { outp->conn = conn; break; } } if (outp->conn) continue; /* apparently we need to create a new one! */ ret = nvkm_connector_new(disp, i, &connE, &outp->conn); if (ret) { nvkm_error(&disp->engine.subdev, "failed to create output %d conn: %d\n", outp->index, ret); nvkm_connector_del(&outp->conn); list_del(&outp->head); nvkm_output_del(&outp); continue; } list_add_tail(&outp->conn->head, &disp->conn); } ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; Loading drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +36 −78 Original line number Diff line number Diff line Loading @@ -33,13 +33,13 @@ static int nvkm_connector_hpd(struct nvkm_notify *notify) { struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); struct nvkm_disp *disp = nvkm_disp(conn); struct nvkm_gpio *gpio = nvkm_gpio(conn); struct nvkm_disp *disp = conn->disp; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; const struct nvkm_gpio_ntfy_rep *line = notify->data; struct nvif_notify_conn_rep_v0 rep; int index = conn->index; DBG("HPD: %d\n", line->mask); CONN_DBG(conn, "HPD: %d", line->mask); if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; Loading @@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify) return NVKM_NOTIFY_KEEP; } int _nvkm_connector_fini(struct nvkm_object *object, bool suspend) void nvkm_connector_fini(struct nvkm_connector *conn) { struct nvkm_connector *conn = (void *)object; nvkm_notify_put(&conn->hpd); return nvkm_object_fini(&conn->base, suspend); } int _nvkm_connector_init(struct nvkm_object *object) void nvkm_connector_init(struct nvkm_connector *conn) { struct nvkm_connector *conn = (void *)object; int ret = nvkm_object_init(&conn->base); if (ret == 0) nvkm_notify_get(&conn->hpd); return ret; } void _nvkm_connector_dtor(struct nvkm_object *object) nvkm_connector_del(struct nvkm_connector **pconn) { struct nvkm_connector *conn = (void *)object; struct nvkm_connector *conn = *pconn; if (conn) { nvkm_notify_fini(&conn->hpd); nvkm_object_destroy(&conn->base); kfree(*pconn); *pconn = NULL; } } int nvkm_connector_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, struct nvbios_connE *info, int index, int length, void **pobject) static void nvkm_connector_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, struct nvkm_connector *conn) { static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; struct nvkm_disp *disp = nvkm_disp(parent); struct nvkm_gpio *gpio = nvkm_gpio(parent); struct nvkm_connector *conn; struct nvkm_output *outp; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; struct dcb_gpio_func func; int ret; list_for_each_entry(outp, &disp->outp, head) { if (outp->conn && outp->conn->index == index) { atomic_inc(&nv_object(outp->conn)->refcount); *pobject = outp->conn; return 1; } } ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); conn = *pobject; if (ret) return ret; conn->info = *info; conn->disp = disp; conn->index = index; conn->info = *info; DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n", CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x", info->type, info->location, info->hpd, info->dp, info->di, info->sr, info->lcdid); if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { ERR("hpd %02x unknown\n", info->hpd); return 0; CONN_ERR(conn, "hpd %02x unknown", info->hpd); return; } info->hpd = hpd[info->hpd]; ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { ERR("func %02x lookup failed, %d\n", info->hpd, ret); return 0; CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret); return; } ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, Loading @@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent, sizeof(struct nvkm_gpio_ntfy_rep), &conn->hpd); if (ret) { ERR("func %02x failed, %d\n", info->hpd, ret); CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret); } else { DBG("func %02x (HPD)\n", info->hpd); CONN_DBG(conn, "func %02x (HPD)", info->hpd); } } return 0; } int _nvkm_connector_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *info, u32 index, struct nvkm_object **pobject) nvkm_connector_new(struct nvkm_disp *disp, int index, struct nvbios_connE *info, struct nvkm_connector **pconn) { struct nvkm_connector *conn; int ret; ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn); *pobject = nv_object(conn); if (ret) return ret; if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) return -ENOMEM; nvkm_connector_ctor(disp, index, info, *pconn); return 0; } struct nvkm_oclass * nvkm_connector_oclass = &(struct nvkm_connector_impl) { .base = { .handle = 0, .ofuncs = &(struct nvkm_ofuncs) { .ctor = _nvkm_connector_ctor, .dtor = _nvkm_connector_dtor, .init = _nvkm_connector_init, .fini = _nvkm_connector_fini, }, }, }.base; drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +18 −43 Original line number Diff line number Diff line #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ #include <core/object.h> #include <core/notify.h> #include <engine/disp.h> #include <core/notify.h> #include <subdev/bios.h> #include <subdev/bios/conn.h> struct nvkm_connector { struct nvkm_object base; struct list_head head; struct nvbios_connE info; struct nvkm_disp *disp; int index; struct nvbios_connE info; struct nvkm_notify hpd; }; #define nvkm_connector_create(p,e,c,b,i,d) \ nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) #define nvkm_connector_destroy(d) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_dtor(nv_object(disp)); \ }) #define nvkm_connector_init(d) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_init(nv_object(disp)); \ }) #define nvkm_connector_fini(d,s) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_fini(nv_object(disp), (s)); \ }) int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, struct nvbios_connE *, int, int, void **); int _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void _nvkm_connector_dtor(struct nvkm_object *); int _nvkm_connector_init(struct nvkm_object *); int _nvkm_connector_fini(struct nvkm_object *, bool); struct nvkm_connector_impl { struct nvkm_oclass base; struct list_head head; }; #ifndef MSG #define MSG(l,f,a...) do { \ struct nvkm_connector *_conn = (void *)conn; \ nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index, \ _conn->info.location, _conn->info.type, ##a); \ int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, struct nvkm_connector **); void nvkm_connector_del(struct nvkm_connector **); void nvkm_connector_init(struct nvkm_connector *); void nvkm_connector_fini(struct nvkm_connector *); #define CONN_MSG(c,l,f,a...) do { \ struct nvkm_connector *_conn = (c); \ nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ _conn->index, _conn->info.location, _conn->info.type, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) #define ERR(f,a...) MSG(error, f, ##a) #endif #define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a) #define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a) #define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a) #endif Loading
drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ struct nvkm_disp { struct nvkm_engine engine; struct list_head outp; struct list_head conn; struct nvkm_event hpd; struct nvkm_event vblank; Loading
drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +13 −8 Original line number Diff line number Diff line nvkm-y += nvkm/engine/disp/base.o nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/g84.o Loading @@ -13,17 +10,25 @@ nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm204.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o nvkm-y += nvkm/engine/disp/sorg94.o nvkm-y += nvkm/engine/disp/sorgf110.o nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/dport.o nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/hdagt215.o nvkm-y += nvkm/engine/disp/hdagf110.o nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o nvkm-y += nvkm/engine/disp/hdmigf110.o nvkm-y += nvkm/engine/disp/hdmigk104.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o nvkm-y += nvkm/engine/disp/sorg94.o nvkm-y += nvkm/engine/disp/sorgf110.o nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/vga.o
drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +130 −36 Original line number Diff line number Diff line Loading @@ -118,29 +118,25 @@ int _nvkm_disp_fini(struct nvkm_object *object, bool suspend) { struct nvkm_disp *disp = (void *)object; struct nvkm_connector *conn; struct nvkm_output *outp; int ret; list_for_each_entry(outp, &disp->outp, head) { ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend); if (ret && suspend) goto fail_outp; nvkm_output_fini(outp); } return nvkm_engine_fini(&disp->engine, suspend); fail_outp: list_for_each_entry_continue_reverse(outp, &disp->outp, head) { nv_ofuncs(outp)->init(nv_object(outp)); list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_fini(conn); } return ret; return nvkm_engine_fini(&disp->engine, suspend); } int _nvkm_disp_init(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; struct nvkm_connector *conn; struct nvkm_output *outp; int ret; Loading @@ -148,17 +144,12 @@ _nvkm_disp_init(struct nvkm_object *object) if (ret) return ret; list_for_each_entry(outp, &disp->outp, head) { ret = nv_ofuncs(outp)->init(nv_object(outp)); if (ret) goto fail_outp; list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_init(conn); } return ret; fail_outp: list_for_each_entry_continue_reverse(outp, &disp->outp, head) { nv_ofuncs(outp)->fini(nv_object(outp), false); list_for_each_entry(outp, &disp->outp, head) { nvkm_output_init(outp); } return ret; Loading @@ -168,15 +159,22 @@ void _nvkm_disp_dtor(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; struct nvkm_output *outp, *outt; struct nvkm_connector *conn; struct nvkm_output *outp; nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->hpd); if (disp->outp.next) { list_for_each_entry_safe(outp, outt, &disp->outp, head) { nvkm_object_ref(NULL, (struct nvkm_object **)&outp); while (!list_empty(&disp->outp)) { outp = list_first_entry(&disp->outp, typeof(*outp), head); list_del(&outp->head); nvkm_output_del(&outp); } while (!list_empty(&disp->conn)) { conn = list_first_entry(&disp->conn, typeof(*conn), head); list_del(&conn->head); nvkm_connector_del(&conn); } nvkm_engine_destroy(&disp->engine); Loading @@ -188,10 +186,12 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, const char *extname, int length, void **pobject) { struct nvkm_disp_impl *impl = (void *)oclass; struct nvkm_bios *bios = nvkm_bios(parent); struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; struct nvkm_disp *disp; struct nvkm_oclass **sclass; struct nvkm_object *object; struct nvkm_connector *conn; struct nvkm_output *outp, *outt, *pair; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; u32 data; Loading @@ -204,30 +204,124 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, return ret; INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); /* create output objects for each display path in the vbios */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { const struct nvkm_disp_func_outp *outps; int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); if (dcbE.type == DCB_OUTPUT_UNUSED) continue; if (dcbE.type == DCB_OUTPUT_EOL) break; data = dcbE.location << 4 | dcbE.type; outp = NULL; oclass = nvkm_output_oclass; sclass = impl->outp; while (sclass && sclass[0]) { if (sclass[0]->handle == data) { oclass = sclass[0]; break; switch (dcbE.location) { case 0: outps = &impl->outp.internal; break; case 1: outps = &impl->outp.external; break; default: nvkm_warn(&disp->engine.subdev, "dcb %d locn %d unknown\n", i, dcbE.location); continue; } sclass++; switch (dcbE.type) { case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; case DCB_OUTPUT_TV : ctor = outps->tv ; break; case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; case DCB_OUTPUT_DP : ctor = outps->dp ; break; default: nvkm_warn(&disp->engine.subdev, "dcb %d type %d unknown\n", i, dcbE.type); continue; } nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object); if (ctor) ret = ctor(disp, i, &dcbE, &outp); else ret = -ENODEV; if (ret) { if (ret == -ENODEV) { nvkm_debug(&disp->engine.subdev, "dcb %d %d/%d not supported\n", i, dcbE.location, dcbE.type); continue; } nvkm_error(&disp->engine.subdev, "failed to create output %d\n", i); nvkm_output_del(&outp); continue; } list_add_tail(&outp->head, &disp->outp); hpd = max(hpd, (u8)(dcbE.connector + 1)); } /* create connector objects based on the outputs we support */ list_for_each_entry_safe(outp, outt, &disp->outp, head) { /* bios data *should* give us the most useful information */ data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); /* no bios connector data... */ if (!data) { /* heuristic: anything with the same ccb index is * considered to be on the same connector, any * output path without an associated ccb entry will * be put on its own connector */ int ccb_index = outp->info.i2c_index; if (ccb_index != 0xf) { list_for_each_entry(pair, &disp->outp, head) { if (pair->info.i2c_index == ccb_index) { outp->conn = pair->conn; break; } } } /* connector shared with another output path */ if (outp->conn) continue; memset(&connE, 0x00, sizeof(connE)); connE.type = DCB_CONNECTOR_NONE; i = -1; } else { i = outp->info.connector; } /* check that we haven't already created this connector */ list_for_each_entry(conn, &disp->conn, head) { if (conn->index == outp->info.connector) { outp->conn = conn; break; } } if (outp->conn) continue; /* apparently we need to create a new one! */ ret = nvkm_connector_new(disp, i, &connE, &outp->conn); if (ret) { nvkm_error(&disp->engine.subdev, "failed to create output %d conn: %d\n", outp->index, ret); nvkm_connector_del(&outp->conn); list_del(&outp->head); nvkm_output_del(&outp); continue; } list_add_tail(&outp->conn->head, &disp->conn); } ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; Loading
drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +36 −78 Original line number Diff line number Diff line Loading @@ -33,13 +33,13 @@ static int nvkm_connector_hpd(struct nvkm_notify *notify) { struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); struct nvkm_disp *disp = nvkm_disp(conn); struct nvkm_gpio *gpio = nvkm_gpio(conn); struct nvkm_disp *disp = conn->disp; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; const struct nvkm_gpio_ntfy_rep *line = notify->data; struct nvif_notify_conn_rep_v0 rep; int index = conn->index; DBG("HPD: %d\n", line->mask); CONN_DBG(conn, "HPD: %d", line->mask); if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; Loading @@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify) return NVKM_NOTIFY_KEEP; } int _nvkm_connector_fini(struct nvkm_object *object, bool suspend) void nvkm_connector_fini(struct nvkm_connector *conn) { struct nvkm_connector *conn = (void *)object; nvkm_notify_put(&conn->hpd); return nvkm_object_fini(&conn->base, suspend); } int _nvkm_connector_init(struct nvkm_object *object) void nvkm_connector_init(struct nvkm_connector *conn) { struct nvkm_connector *conn = (void *)object; int ret = nvkm_object_init(&conn->base); if (ret == 0) nvkm_notify_get(&conn->hpd); return ret; } void _nvkm_connector_dtor(struct nvkm_object *object) nvkm_connector_del(struct nvkm_connector **pconn) { struct nvkm_connector *conn = (void *)object; struct nvkm_connector *conn = *pconn; if (conn) { nvkm_notify_fini(&conn->hpd); nvkm_object_destroy(&conn->base); kfree(*pconn); *pconn = NULL; } } int nvkm_connector_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, struct nvbios_connE *info, int index, int length, void **pobject) static void nvkm_connector_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, struct nvkm_connector *conn) { static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; struct nvkm_disp *disp = nvkm_disp(parent); struct nvkm_gpio *gpio = nvkm_gpio(parent); struct nvkm_connector *conn; struct nvkm_output *outp; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; struct dcb_gpio_func func; int ret; list_for_each_entry(outp, &disp->outp, head) { if (outp->conn && outp->conn->index == index) { atomic_inc(&nv_object(outp->conn)->refcount); *pobject = outp->conn; return 1; } } ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); conn = *pobject; if (ret) return ret; conn->info = *info; conn->disp = disp; conn->index = index; conn->info = *info; DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n", CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x", info->type, info->location, info->hpd, info->dp, info->di, info->sr, info->lcdid); if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { ERR("hpd %02x unknown\n", info->hpd); return 0; CONN_ERR(conn, "hpd %02x unknown", info->hpd); return; } info->hpd = hpd[info->hpd]; ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { ERR("func %02x lookup failed, %d\n", info->hpd, ret); return 0; CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret); return; } ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, Loading @@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent, sizeof(struct nvkm_gpio_ntfy_rep), &conn->hpd); if (ret) { ERR("func %02x failed, %d\n", info->hpd, ret); CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret); } else { DBG("func %02x (HPD)\n", info->hpd); CONN_DBG(conn, "func %02x (HPD)", info->hpd); } } return 0; } int _nvkm_connector_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *info, u32 index, struct nvkm_object **pobject) nvkm_connector_new(struct nvkm_disp *disp, int index, struct nvbios_connE *info, struct nvkm_connector **pconn) { struct nvkm_connector *conn; int ret; ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn); *pobject = nv_object(conn); if (ret) return ret; if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) return -ENOMEM; nvkm_connector_ctor(disp, index, info, *pconn); return 0; } struct nvkm_oclass * nvkm_connector_oclass = &(struct nvkm_connector_impl) { .base = { .handle = 0, .ofuncs = &(struct nvkm_ofuncs) { .ctor = _nvkm_connector_ctor, .dtor = _nvkm_connector_dtor, .init = _nvkm_connector_init, .fini = _nvkm_connector_fini, }, }, }.base;
drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +18 −43 Original line number Diff line number Diff line #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ #include <core/object.h> #include <core/notify.h> #include <engine/disp.h> #include <core/notify.h> #include <subdev/bios.h> #include <subdev/bios/conn.h> struct nvkm_connector { struct nvkm_object base; struct list_head head; struct nvbios_connE info; struct nvkm_disp *disp; int index; struct nvbios_connE info; struct nvkm_notify hpd; }; #define nvkm_connector_create(p,e,c,b,i,d) \ nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) #define nvkm_connector_destroy(d) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_dtor(nv_object(disp)); \ }) #define nvkm_connector_init(d) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_init(nv_object(disp)); \ }) #define nvkm_connector_fini(d,s) ({ \ struct nvkm_connector *disp = (d); \ _nvkm_connector_fini(nv_object(disp), (s)); \ }) int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, struct nvbios_connE *, int, int, void **); int _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void _nvkm_connector_dtor(struct nvkm_object *); int _nvkm_connector_init(struct nvkm_object *); int _nvkm_connector_fini(struct nvkm_object *, bool); struct nvkm_connector_impl { struct nvkm_oclass base; struct list_head head; }; #ifndef MSG #define MSG(l,f,a...) do { \ struct nvkm_connector *_conn = (void *)conn; \ nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index, \ _conn->info.location, _conn->info.type, ##a); \ int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, struct nvkm_connector **); void nvkm_connector_del(struct nvkm_connector **); void nvkm_connector_init(struct nvkm_connector *); void nvkm_connector_fini(struct nvkm_connector *); #define CONN_MSG(c,l,f,a...) do { \ struct nvkm_connector *_conn = (c); \ nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ _conn->index, _conn->info.location, _conn->info.type, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) #define ERR(f,a...) MSG(error, f, ##a) #endif #define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a) #define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a) #define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a) #endif