From f2c906fc0cf1657e4164e09ae6061534eebd5430 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: drm/nouveau/disp: transition outp/conn away from being based on nvkm_object Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 24bce1a..cc2ea61 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 16a4e2a..38a8724 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -1,7 +1,4 @@ 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 @@ -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 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 2090e90..7e67445 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -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; @@ -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; @@ -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); @@ -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; @@ -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; + + 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; + } - oclass = nvkm_output_oclass; - sclass = impl->outp; - while (sclass && sclass[0]) { - if (sclass[0]->handle == data) { - oclass = sclass[0]; - break; + 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; + } + + 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; } - sclass++; + nvkm_error(&disp->engine.subdev, + "failed to create output %d\n", i); + nvkm_output_del(&outp); + continue; } - nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object); + 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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index cf03e02..2eb55be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -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; @@ -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; + nvkm_notify_get(&conn->hpd); } void -_nvkm_connector_dtor(struct nvkm_object *object) +nvkm_connector_del(struct nvkm_connector **pconn) { - struct nvkm_connector *conn = (void *)object; - nvkm_notify_fini(&conn->hpd); - nvkm_object_destroy(&conn->base); + struct nvkm_connector *conn = *pconn; + if (conn) { + nvkm_notify_fini(&conn->hpd); + 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", - info->type, info->location, info->hpd, info->dp, - info->di, info->sr, info->lcdid); + 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, @@ -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; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index 7789f70..ed32fe7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -1,58 +1,33 @@ #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ -#include -#include +#include +#include #include #include 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 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index ddd4144..9bfa9e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -112,3 +112,15 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) args->v0.load = (loadval & 0x38000000) >> 27; return 0; } + +static const struct nvkm_output_func +nv50_dac_output_func = { +}; + +int +nv50_dac_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_dac_output_func, disp, + index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index d671da6..cf1ec5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -48,12 +48,12 @@ struct dp_state { static int dp_set_link_config(struct dp_state *dp) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = 0x0000, .outp = &outp->base.info, @@ -64,7 +64,7 @@ dp_set_link_config(struct dp_state *dp) u8 sink[2]; int ret; - DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); + OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw); /* set desired link configuration on the source */ if ((lnkcmp = dp->outp->info.lnkcmp)) { @@ -81,16 +81,16 @@ dp_set_link_config(struct dp_state *dp) nvbios_exec(&init); } - ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, - outp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) - ERR("lnk_ctl failed with %d\n", ret); + OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); return ret; } - impl->lnk_pwr(outp, dp->link_nr); + outp->func->lnk_pwr(outp, dp->link_nr); /* set desired link configuration on the sink */ sink[0] = dp->link_bw / 27000; @@ -104,12 +104,11 @@ dp_set_link_config(struct dp_state *dp) static void dp_set_training_pattern(struct dp_state *dp, u8 pattern) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; u8 sink_tp; - DBG("training pattern %d\n", pattern); - impl->pattern(outp, pattern); + OUTP_DBG(&outp->base, "training pattern %d", pattern); + outp->func->pattern(outp, pattern); nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; @@ -120,7 +119,6 @@ dp_set_training_pattern(struct dp_state *dp, u8 pattern) static int dp_link_train_commit(struct dp_state *dp, bool pc) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; int ret, i; @@ -146,8 +144,9 @@ dp_link_train_commit(struct dp_state *dp, bool pc) dp->conf[i] = (lpre << 3) | lvsw; dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); - DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2); - impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + OUTP_DBG(&outp->base, "config lane %d %02x %02x", + i, dp->conf[i], lpc2); + outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); } ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4); @@ -182,9 +181,10 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1); if (ret) dp->pc2stat = 0x00; - DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); + OUTP_DBG(&outp->base, "status %6ph pc2 %02x", + dp->stat, dp->pc2stat); } else { - DBG("status %6ph\n", dp->stat); + OUTP_DBG(&outp->base, "status %6ph", dp->stat); } return 0; @@ -260,11 +260,11 @@ static void dp_link_train_init(struct dp_state *dp, bool spread) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -286,11 +286,11 @@ static void dp_link_train_fini(struct dp_state *dp) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -322,7 +322,7 @@ void nvkm_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)outp->base.disp; const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { .outp = outp, @@ -334,7 +334,7 @@ nvkm_dp_train(struct work_struct *w) disp->sor.magic(&outp->base); /* bring capabilities within encoder limits */ - if (nv_mclass(disp) < GF110_DISP) + if (disp->base.engine.subdev.device->chipset < 0xd0) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; @@ -386,12 +386,12 @@ nvkm_dp_train(struct work_struct *w) /* finish link training and execute post-train script from vbios */ dp_set_training_pattern(dp, 0); if (ret < 0) - ERR("link training failed\n"); + OUTP_ERR(&outp->base, "link training failed"); dp_link_train_fini(dp); /* signal completion and enable link interrupt handling */ - DBG("training complete\n"); + OUTP_DBG(&outp->base, "training complete"); atomic_set(&outp->lt.done, 1); wake_up(&outp->lt.wait); nvkm_notify_get(&outp->irq); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index a080184..c8d3093 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -262,8 +262,12 @@ g84_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &g84_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 9082fb7..b190a07 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -114,13 +114,6 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } struct nvkm_oclass * -g94_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - &g94_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * g94_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x88), .base.base.ofuncs = &(struct nvkm_ofuncs) { @@ -129,8 +122,13 @@ g94_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = g94_sor_dp_new, + .base.outp.external.lvds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, .mthd.core = &g94_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index bf72996..4161326 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -988,7 +988,7 @@ gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head) /* see note in nv50_disp_intr_unk20_0() */ if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { .subdev = nv_subdev(disp), .bios = nvkm_bios(disp), @@ -1101,7 +1101,7 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) } if (nvkm_output_dp_train(outp, pclk, true)) - ERR("link not trained before attach\n"); + OUTP_ERR(outp, "link not trained before attach"); } else { if (disp->sor.magic) disp->sor.magic(outp); @@ -1340,12 +1340,6 @@ gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } struct nvkm_oclass * -gf110_disp_outp_sclass[] = { - &gf110_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * gf110_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x90), .base.base.ofuncs = &(struct nvkm_ofuncs) { @@ -1354,8 +1348,11 @@ gf110_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gf110_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gf110_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index baf2c28..ffd8e77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -259,8 +259,11 @@ gk104_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index ee51b4f..ca2d6f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -94,8 +94,11 @@ gk110_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 13a02ac..f841d82 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -94,8 +94,11 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 89d9839..8da3174 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -88,12 +88,6 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } struct nvkm_oclass * -gm204_disp_outp_sclass[] = { - &gm204_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * gm204_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x07), .base.base.ofuncs = &(struct nvkm_ofuncs) { @@ -102,8 +96,11 @@ gm204_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gm204_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gm204_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 65cf51f..7f9f3a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -138,8 +138,12 @@ gt200_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &g84_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = >200_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 0a2b794..ef6c713 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -94,8 +94,13 @@ gt215_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = g94_sor_dp_new, + .base.outp.external.lvds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, .mthd.core = &g94_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index b07cb06..5079ea3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1109,7 +1109,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_SOR_DP_PWR: { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); union { struct nv50_disp_sor_dp_pwr_v0 v0; } *args = data; @@ -1119,8 +1119,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) args->v0.version, args->v0.state); if (args->v0.state == 0) { nvkm_notify_put(&outpdp->irq); - ((struct nvkm_output_dp_impl *)nv_oclass(outp)) - ->lnk_pwr(outpdp, 0); + outpdp->func->lnk_pwr(outpdp, 0); atomic_set(&outpdp->lt.done, 0); return 0; } else @@ -1655,7 +1654,7 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) * in a blank screen (SOR_PWR off/on can restore it) */ if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { .subdev = nv_subdev(disp), .bios = nvkm_bios(disp), @@ -1855,7 +1854,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) } if (nvkm_output_dp_train(outp, datarate / soff, true)) - ERR("link not trained before attach\n"); + OUTP_ERR(outp, "link not trained before attach"); } exec_clkcmp(disp, head, 0, pclk, &conf); @@ -2048,12 +2047,6 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } struct nvkm_oclass * -nv50_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * nv50_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x50), .base.base.ofuncs = &(struct nvkm_ofuncs) { @@ -2062,8 +2055,12 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv50_disp_core_mthd_chan, .mthd.base = &nv50_disp_base_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 24d3413..0d495d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -214,7 +214,7 @@ extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_oclass *nv50_disp_outp_sclass[]; extern struct nvkm_output_dp_impl g94_sor_dp_impl; -u32 g94_sor_dp_lane_map(struct nv50_disp *, u8 lane); +u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); extern struct nvkm_oclass *g94_disp_outp_sclass[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 88a990e..bbe5ec0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,117 +22,66 @@ * Authors: Ben Skeggs */ #include "outp.h" -#include "priv.h" #include -#include #include #include -int -_nvkm_output_fini(struct nvkm_object *object, bool suspend) +void +nvkm_output_fini(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend); - return nvkm_object_fini(&outp->base, suspend); + if (outp->func->fini) + outp->func->fini(outp); } -int -_nvkm_output_init(struct nvkm_object *object) +void +nvkm_output_init(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - int ret = nvkm_object_init(&outp->base); - if (ret == 0) - nv_ofuncs(outp->conn)->init(nv_object(outp->conn)); - return 0; + if (outp->func->init) + outp->func->init(outp); } void -_nvkm_output_dtor(struct nvkm_object *object) +nvkm_output_del(struct nvkm_output **poutp) { - struct nvkm_output *outp = (void *)object; - list_del(&outp->head); - nvkm_object_ref(NULL, (void *)&outp->conn); - nvkm_object_destroy(&outp->base); + struct nvkm_output *outp = *poutp; + if (outp && !WARN_ON(!outp->func)) { + if (outp->func->dtor) + *poutp = outp->func->dtor(outp); + kfree(*poutp); + *poutp = NULL; + } } -int -nvkm_output_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *dcbE, int index, - int length, void **pobject) +void +nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, + int index, struct dcb_output *dcbE, struct nvkm_output *outp) { - struct nvkm_disp *disp = nvkm_disp(parent); - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvbios_connE connE; - struct nvkm_output *outp; - u8 ver, hdr; - u32 data; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - outp = *pobject; - if (ret) - return ret; - - outp->info = *dcbE; + outp->func = func; + outp->disp = disp; outp->index = index; + outp->info = *dcbE; + outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index); outp->or = ffs(outp->info.or) - 1; - DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", - dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? - dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, - dcbE->bus, dcbE->heads); - - outp->i2c = nvkm_i2c_bus_find(i2c, outp->info.i2c_index); - - data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); - if (!data) { - DBG("vbios connector data not found\n"); - memset(&connE, 0x00, sizeof(connE)); - connE.type = DCB_CONNECTOR_NONE; - } - - ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass, - &connE, outp->info.connector, - (struct nvkm_object **)&outp->conn); - if (ret < 0) { - ERR("error %d creating connector, disabling\n", ret); - return ret; - } - - list_add_tail(&outp->head, &disp->outp); - return 0; + OUTP_DBG(outp, "type %02x loc %d or %d link %d con %x " + "edid %x bus %d head %x", + outp->info.type, outp->info.location, outp->info.or, + outp->info.type >= 2 ? outp->info.sorconf.link : 0, + outp->info.connector, outp->info.i2c_index, + outp->info.bus, outp->info.heads); } int -_nvkm_output_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *dcbE, u32 index, - struct nvkm_object **pobject) +nvkm_output_new_(const struct nvkm_output_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - struct nvkm_output *outp; - int ret; - - ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) + return -ENOMEM; + nvkm_output_ctor(func, disp, index, dcbE, *poutp); return 0; } - -struct nvkm_oclass * -nvkm_output_oclass = &(struct nvkm_output_impl) { - .base = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index fb2ce7c..83d9d3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -1,61 +1,51 @@ #ifndef __NVKM_DISP_OUTP_H__ #define __NVKM_DISP_OUTP_H__ -#include +#include #include #include struct nvkm_output { - struct nvkm_object base; - struct list_head head; - - struct dcb_output info; + const struct nvkm_output_func *func; + struct nvkm_disp *disp; int index; - int or; + struct dcb_output info; // whatever (if anything) is pointed at by the dcb device entry struct nvkm_i2c_bus *i2c; + int or; + struct list_head head; struct nvkm_connector *conn; }; -#define nvkm_output_create(p,e,c,b,i,d) \ - nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_destroy(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_init(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_init(nv_object(_outp)); \ -}) -#define nvkm_output_fini(d,s) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dtor(struct nvkm_object *); -int _nvkm_output_init(struct nvkm_object *); -int _nvkm_output_fini(struct nvkm_object *, bool); - -struct nvkm_output_impl { - struct nvkm_oclass base; +struct nvkm_output_func { + void *(*dtor)(struct nvkm_output *); + void (*init)(struct nvkm_output *); + void (*fini)(struct nvkm_output *); }; -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_output *_outp = (void *)outp; \ - nvkm_##l(&nvkm_disp(_outp)->engine.subdev, "%02x:%04x:%04x: "f, _outp->index, \ - _outp->info.hasht, _outp->info.hashm, ##a); \ +void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output *); +int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output **); +void nvkm_output_del(struct nvkm_output **); +void nvkm_output_init(struct nvkm_output *); +void nvkm_output_fini(struct nvkm_output *); + +int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +#define OUTP_MSG(o,l,f,a...) do { \ + struct nvkm_output *_outp = (o); \ + nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ + _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define OUTP_ERR(o,f,a...) OUTP_MSG((o), error, f, ##a) +#define OUTP_DBG(o,f,a...) OUTP_MSG((o), debug, f, ##a) +#define OUTP_TRACE(o,f,a...) OUTP_MSG((o), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c index dac6f17..3b7a9e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c @@ -33,7 +33,7 @@ int nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) { - struct nvkm_output_dp *outp = (void *)base; + struct nvkm_output_dp *outp = nvkm_output_dp(base); bool retrain = true; u8 link[2], stat[3]; u32 linkrate; @@ -42,7 +42,8 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) /* check that the link is trained at a high enough rate */ ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { - DBG("failed to read link config, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link config, assuming no sink"); goto done; } @@ -50,14 +51,15 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ datarate = (datarate + 9) / 10; /* -> decakilobits */ if (linkrate < datarate) { - DBG("link not trained at sufficient rate\n"); + OUTP_DBG(&outp->base, "link not trained at sufficient rate"); goto done; } /* check that link is still trained */ ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); if (ret) { - DBG("failed to read link status, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link status, assuming no sink"); goto done; } @@ -67,13 +69,14 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - DBG("lane %d not equalised\n", lane); + OUTP_DBG(&outp->base, + "lane %d not equalised", lane); goto done; } } retrain = false; } else { - DBG("no inter-lane alignment\n"); + OUTP_DBG(&outp->base, "no inter-lane alignment"); } done: @@ -108,7 +111,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) if (enable) { if (!outp->present) { - DBG("aux power -> always\n"); + OUTP_DBG(&outp->base, "aux power -> always"); nvkm_i2c_aux_monitor(aux, true); outp->present = true; } @@ -121,7 +124,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) } if (outp->present) { - DBG("aux power -> demand\n"); + OUTP_DBG(&outp->base, "aux power -> demand"); nvkm_i2c_aux_monitor(aux, false); outp->present = false; } @@ -132,116 +135,108 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) static int nvkm_output_dp_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_output_dp *outp; - struct nvkm_disp *disp = nvkm_disp(conn); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = {}; - list_for_each_entry(outp, &disp->outp, base.head) { - if (outp->base.conn == conn && - outp->info.type == DCB_OUTPUT_DP) { - DBG("HPD: %d\n", line->mask); - nvkm_output_dp_enable(outp, true); - - if (line->mask & NVKM_I2C_UNPLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; - if (line->mask & NVKM_I2C_PLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; + OUTP_DBG(&outp->base, "HPD: %d", line->mask); + nvkm_output_dp_enable(outp, true); - nvkm_event_send(&disp->hpd, rep.mask, conn->index, - &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; - } - } + if (line->mask & NVKM_I2C_UNPLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; + if (line->mask & NVKM_I2C_PLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; - WARN_ON(1); - return NVKM_NOTIFY_DROP; + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; } static int nvkm_output_dp_irq(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); - struct nvkm_disp *disp = nvkm_disp(outp); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = { .mask = NVIF_NOTIFY_CONN_V0_IRQ, }; - int index = outp->base.info.connector; - DBG("IRQ: %d\n", line->mask); + OUTP_DBG(&outp->base, "IRQ: %d", line->mask); nvkm_output_dp_train(&outp->base, 0, true); - nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); return NVKM_NOTIFY_DROP; } -int -_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_output_dp_fini(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->hpd); nvkm_notify_put(&outp->irq); + flush_work(&outp->lt.work); nvkm_output_dp_enable(outp, false); - return nvkm_output_fini(&outp->base, suspend); } -int -_nvkm_output_dp_init(struct nvkm_object *object) +static void +nvkm_output_dp_init(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->base.conn->hpd); nvkm_output_dp_enable(outp, true); - return nvkm_output_init(&outp->base); + nvkm_notify_get(&outp->hpd); } -void -_nvkm_output_dp_dtor(struct nvkm_object *object) +static void * +nvkm_output_dp_dtor(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_fini(&outp->hpd); nvkm_notify_fini(&outp->irq); - nvkm_output_destroy(&outp->base); + return outp; } +static const struct nvkm_output_func +nvkm_output_dp_func = { + .dtor = nvkm_output_dp_dtor, + .init = nvkm_output_dp_init, + .fini = nvkm_output_dp_fini, +}; + int -nvkm_output_dp_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *info, int index, - int length, void **pobject) +nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) { - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; u8 hdr, cnt, len; u32 data; int ret; - ret = nvkm_output_create_(parent, engine, oclass, info, index, - length, pobject); - outp = *pobject; - if (ret) - return ret; - - nvkm_notify_fini(&outp->base.conn->hpd); - - /* access to the aux channel is not optional... */ - //XXX: breaks anx support - outp->aux = nvkm_i2c_aux_find(i2c, outp->base.info.i2c_index); + nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); + outp->func = func; + outp->aux = aux; if (!outp->aux) { - ERR("aux channel not found\n"); + OUTP_ERR(&outp->base, "no aux"); return -ENODEV; } - /* nor is the bios data for this output... */ + /* bios data is not optional */ data = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, &outp->version, &hdr, &cnt, &len, &outp->info); if (!data) { - ERR("no bios dp data\n"); + OUTP_ERR(&outp->base, "no bios dp data"); return -ENODEV; } - DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len); + OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", + outp->version, hdr, cnt, len); /* link training */ INIT_WORK(&outp->lt.work, nvkm_dp_train); @@ -258,7 +253,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent, sizeof(struct nvkm_i2c_ntfy_rep), &outp->irq); if (ret) { - ERR("error monitoring aux irq event: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); return ret; } @@ -270,9 +265,9 @@ nvkm_output_dp_create_(struct nvkm_object *parent, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), - &outp->base.conn->hpd); + &outp->hpd); if (ret) { - ERR("error monitoring aux hpd events: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); return ret; } @@ -280,18 +275,17 @@ nvkm_output_dp_create_(struct nvkm_object *parent, } int -_nvkm_output_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); struct nvkm_output_dp *outp; - int ret; - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - return 0; + return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index f90e84c..1c1bd38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -1,5 +1,14 @@ #ifndef __NVKM_DISP_OUTP_DP_H__ #define __NVKM_DISP_OUTP_DP_H__ +#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) +#ifndef MSG +#define MSG(l,f,a...) \ + nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f, \ + outp->base.index, outp->base.info.hasht, \ + outp->base.info.hashm, ##a) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif #include "outp.h" #include @@ -7,6 +16,7 @@ #include struct nvkm_output_dp { + const struct nvkm_output_dp_func *func; struct nvkm_output base; struct nvbios_dpout info; @@ -15,6 +25,7 @@ struct nvkm_output_dp { struct nvkm_i2c_aux *aux; struct nvkm_notify irq; + struct nvkm_notify hpd; bool present; u8 dpcd[16]; @@ -25,34 +36,7 @@ struct nvkm_output_dp { } lt; }; -#define nvkm_output_dp_create(p,e,c,b,i,d) \ - nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_dp_destroy(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_dp_init(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_init(nv_object(_outp)); \ -}) -#define nvkm_output_dp_fini(d,s) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dp_dtor(struct nvkm_object *); -int _nvkm_output_dp_init(struct nvkm_object *); -int _nvkm_output_dp_fini(struct nvkm_object *, bool); - -struct nvkm_output_dp_impl { - struct nvkm_output_impl base; +struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); int (*lnk_pwr)(struct nvkm_output_dp *, int nr); int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); @@ -60,4 +44,23 @@ struct nvkm_output_dp_impl { }; int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait); + +int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_i2c_aux *, + struct nvkm_output_dp *); +int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, + struct nvkm_output **); + +int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int gf110_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index ac122d7..ab524bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,8 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" #include "outpdp.h" +#include "nv50.h" #include #include @@ -31,135 +31,101 @@ #include #include -/****************************************************************************** - * TMDS - *****************************************************************************/ - -static int -nv50_pior_tmds_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +int +nv50_pior_power(NV50_DISP_MTHD_V1) { - struct nvkm_output *outp; + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_pior_pwr_v0 v0; + } *args = data; + u32 ctrl, type; int ret; - ret = nvkm_output_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) + nvif_ioctl(object, "disp pior pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); + if (args->v0.type > 0x0f) + return -EINVAL; + ctrl = !!args->v0.state; + type = args->v0.type; + } else return ret; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + disp->pior.type[outp->or] = type; return 0; } -struct nvkm_output_impl -nv50_pior_tmds_impl = { - .base.handle = DCB_OUTPUT_TMDS | 0x0100, - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_tmds_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, -}; - /****************************************************************************** - * DisplayPort + * TMDS *****************************************************************************/ +static const struct nvkm_output_func +nv50_pior_output_func = { +}; -static int -nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) +int +nv50_pior_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) { - return -ENODEV; + return nvkm_output_new_(&nv50_pior_output_func, disp, + index, dcbE, poutp); } +/****************************************************************************** + * DisplayPort + *****************************************************************************/ static int -nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) { return 0; } static int -nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) -{ - return nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); -} - -static int -nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) +nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - return -ENODEV; + return 0; } static int -nv50_pior_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, + int nr, int bw, bool ef) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; - int ret; - - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); + int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); if (ret) return ret; - - outp->aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(outp->base.info.extdev)); - return 0; + return 1; } -struct nvkm_output_dp_impl -nv50_pior_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP | 0x0010, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, - .pattern = nv50_pior_dp_pattern, - .lnk_pwr = nv50_pior_dp_lnk_pwr, - .lnk_ctl = nv50_pior_dp_lnk_ctl, - .drv_ctl = nv50_pior_dp_drv_ctl, +static const struct nvkm_output_dp_func +nv50_pior_output_dp_func = { + .pattern = nv50_pior_output_dp_pattern, + .lnk_pwr = nv50_pior_output_dp_lnk_pwr, + .lnk_ctl = nv50_pior_output_dp_lnk_ctl, }; -/****************************************************************************** - * General PIOR handling - *****************************************************************************/ - int -nv50_pior_power(NV50_DISP_MTHD_V1) +nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = + nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); + struct nvkm_output_dp *outp; - nvif_ioctl(object, "disp pior pwr size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - disp->pior.type[outp->or] = type; - return 0; + return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, + index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 961ce8b..f1df297 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -1,11 +1,28 @@ #ifndef __NVKM_DISP_PRIV_H__ #define __NVKM_DISP_PRIV_H__ #include +#include "outp.h" +#include "outpdp.h" + +struct nvkm_disp_func_outp { + int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); +}; struct nvkm_disp_impl { struct nvkm_oclass base; - struct nvkm_oclass **outp; - struct nvkm_oclass **conn; + struct { + const struct nvkm_disp_func_outp internal; + const struct nvkm_disp_func_outp external; + } outp; const struct nvkm_event_func *vblank; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index d921efe..1bb9d66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -38,15 +38,33 @@ g94_sor_loff(struct nvkm_output_dp *outp) return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } +/******************************************************************************* + * TMDS/LVDS + ******************************************************************************/ +static const struct nvkm_output_func +g94_sor_output_func = { +}; + +int +g94_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&g94_sor_output_func, disp, + index, dcbE, poutp); +} + +/******************************************************************************* + * DisplayPort + ******************************************************************************/ u32 -g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) +g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { static const u8 gm100[] = { 0, 8, 16, 24 }; static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ static const u8 g94[] = { 16, 8, 0, 24 }; - if (nv_device(disp)->chipset >= 0x110) + if (device->chipset >= 0x110) return gm100[lane]; - if (nv_device(disp)->chipset == 0xaf) + if (device->chipset == 0xaf) return mcp89[lane]; return g94[lane]; } @@ -54,8 +72,7 @@ g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 loff = g94_sor_loff(outp); nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; @@ -64,14 +81,13 @@ g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (g94_sor_dp_lane_map(disp, i) >> 3); + mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3); nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); @@ -85,8 +101,7 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) static int g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -106,10 +121,9 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) static int g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(disp, ln); + const u32 shift = g94_sor_dp_lane_map(device, ln); const u32 loff = g94_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; @@ -118,12 +132,12 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) addr = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); + &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); + &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; @@ -138,17 +152,17 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) return 0; } -struct nvkm_output_dp_impl -g94_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = g94_sor_dp_lnk_ctl, .drv_ctl = g94_sor_dp_drv_ctl, }; + +int +g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 696bc64..7e5ef50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -39,8 +39,7 @@ gf110_sor_loff(struct nvkm_output_dp *outp) static int gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 loff = gf110_sor_loff(outp); nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; @@ -49,8 +48,7 @@ gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gf110_sor_soff(outp); const u32 loff = gf110_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -70,10 +68,9 @@ static int gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(disp, ln); + const u32 shift = g94_sor_dp_lane_map(device, ln); const u32 loff = gf110_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -104,17 +101,17 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -struct nvkm_output_dp_impl -gf110_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +gf110_sor_dp_func = { .pattern = gf110_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = gf110_sor_dp_lnk_ctl, .drv_ctl = gf110_sor_dp_drv_ctl, }; + +int +gf110_sor_dp_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gf110_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 8792dcf..5a35bf4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -41,8 +41,7 @@ gm204_sor_loff(struct nvkm_output_dp *outp) void gm204_sor_magic(struct nvkm_output *outp) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->disp->engine.subdev.device; const u32 soff = outp->or * 0x100; const u32 data = outp->or + 1; if (outp->info.sorconf.link & 1) @@ -52,7 +51,7 @@ gm204_sor_magic(struct nvkm_output *outp) } static inline u32 -gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) +gm204_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { return lane * 0x08; } @@ -60,8 +59,7 @@ gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) static int gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 data = 0x01010101 * pattern; if (outp->base.info.sorconf.link & 1) @@ -74,14 +72,13 @@ gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) static int gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 loff = gm204_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (gm204_sor_dp_lane_map(disp, i) >> 3); + mask |= 1 << (gm204_sor_dp_lane_map(device, i) >> 3); nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); @@ -96,10 +93,9 @@ static int gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = gm204_sor_dp_lane_map(disp, ln); + const u32 shift = gm204_sor_dp_lane_map(device, ln); const u32 loff = gm204_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -131,17 +127,17 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -struct nvkm_output_dp_impl -gm204_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +gm204_sor_dp_func = { .pattern = gm204_sor_dp_pattern, .lnk_pwr = gm204_sor_dp_lnk_pwr, .lnk_ctl = gf110_sor_dp_lnk_ctl, .drv_ctl = gm204_sor_dp_drv_ctl, }; + +int +gm204_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gm204_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 73ee036..29e0d2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -65,3 +65,15 @@ nv50_sor_power(NV50_DISP_MTHD_V1) ); return 0; } + +static const struct nvkm_output_func +nv50_sor_output_func = { +}; + +int +nv50_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_sor_output_func, disp, + index, dcbE, poutp); +} -- cgit v0.10.2