diff options
Diffstat (limited to 'nvkm/engine/disp')
-rw-r--r-- | nvkm/engine/disp/base.c | 77 | ||||
-rw-r--r-- | nvkm/engine/disp/conn.c | 63 | ||||
-rw-r--r-- | nvkm/engine/disp/conn.h | 5 | ||||
-rw-r--r-- | nvkm/engine/disp/dport.c | 4 | ||||
-rw-r--r-- | nvkm/engine/disp/gm107.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nv04.c | 25 | ||||
-rw-r--r-- | nvkm/engine/disp/nv50.c | 45 | ||||
-rw-r--r-- | nvkm/engine/disp/nv50.h | 6 | ||||
-rw-r--r-- | nvkm/engine/disp/nv84.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nv94.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nva0.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nva3.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nvd0.c | 72 | ||||
-rw-r--r-- | nvkm/engine/disp/nve0.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/nvf0.c | 1 | ||||
-rw-r--r-- | nvkm/engine/disp/outpdp.c | 100 | ||||
-rw-r--r-- | nvkm/engine/disp/outpdp.h | 5 | ||||
-rw-r--r-- | nvkm/engine/disp/priv.h | 4 | ||||
-rw-r--r-- | nvkm/engine/disp/sornv50.c | 2 |
19 files changed, 247 insertions, 168 deletions
diff --git a/nvkm/engine/disp/base.c b/nvkm/engine/disp/base.c index 9c38c5e40..d1df0ce99 100644 --- a/nvkm/engine/disp/base.c +++ b/nvkm/engine/disp/base.c @@ -22,25 +22,76 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/unpack.h> +#include <nvif/event.h> + #include "priv.h" #include "outp.h" #include "conn.h" +int +nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *notify) +{ + struct nouveau_disp *disp = + container_of(notify->event, typeof(*disp), vblank); + union { + struct nvif_notify_head_req_v0 v0; + } *req = data; + int ret; + + if (nvif_unpack(req->v0, 0, 0, false)) { + notify->size = sizeof(struct nvif_notify_head_rep_v0); + if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) { + notify->types = 1; + notify->index = req->v0.head; + return 0; + } + } + + return ret; +} + +void +nouveau_disp_vblank(struct nouveau_disp *disp, int head) +{ + struct nvif_notify_head_rep_v0 rep = {}; + nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep)); +} + static int -nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index) +nouveau_disp_hpd_ctor(void *data, u32 size, struct nvkm_notify *notify) { - struct nouveau_disp *disp = event->priv; + struct nouveau_disp *disp = + container_of(notify->event, typeof(*disp), hpd); + union { + struct nvif_notify_conn_req_v0 v0; + } *req = data; struct nvkm_output *outp; - list_for_each_entry(outp, &disp->outp, head) { - if (outp->conn->index == index) { - if (outp->conn->hpd.event) - return 0; - break; + int ret; + + if (nvif_unpack(req->v0, 0, 0, false)) { + notify->size = sizeof(struct nvif_notify_conn_rep_v0); + list_for_each_entry(outp, &disp->outp, head) { + if (ret = -ENXIO, outp->conn->index == req->v0.conn) { + if (ret = -ENODEV, outp->conn->hpd.event) { + notify->types = req->v0.mask; + notify->index = req->v0.conn; + ret = 0; + } + break; + } } } - return -ENOSYS; + + return ret; } +static const struct nvkm_event_func +nouveau_disp_hpd_func = { + .ctor = nouveau_disp_hpd_ctor +}; + int _nouveau_disp_fini(struct nouveau_object *object, bool suspend) { @@ -97,7 +148,8 @@ _nouveau_disp_dtor(struct nouveau_object *object) struct nouveau_disp *disp = (void *)object; struct nvkm_output *outp, *outt; - nouveau_event_destroy(&disp->vblank); + nvkm_event_fini(&disp->vblank); + nvkm_event_fini(&disp->hpd); if (disp->outp.next) { list_for_each_entry_safe(outp, outt, &disp->outp, head) { @@ -157,14 +209,11 @@ nouveau_disp_create_(struct nouveau_object *parent, hpd = max(hpd, (u8)(dcbE.connector + 1)); } - ret = nouveau_event_create(3, hpd, &disp->hpd); + ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; - disp->hpd->priv = disp; - disp->hpd->check = nouveau_disp_hpd_check; - - ret = nouveau_event_create(1, heads, &disp->vblank); + ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank); if (ret) return ret; diff --git a/nvkm/engine/disp/conn.c b/nvkm/engine/disp/conn.c index 4ffbc70ec..3d1070228 100644 --- a/nvkm/engine/disp/conn.c +++ b/nvkm/engine/disp/conn.c @@ -22,39 +22,41 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/event.h> + #include <subdev/gpio.h> #include "conn.h" #include "outp.h" -static void -nvkm_connector_hpd_work(struct work_struct *w) +static int +nvkm_connector_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work); + struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); struct nouveau_disp *disp = nouveau_disp(conn); struct nouveau_gpio *gpio = nouveau_gpio(conn); - u32 send = NVKM_HPD_UNPLUG; - if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index)) - send = NVKM_HPD_PLUG; - nouveau_event_trigger(disp->hpd, send, conn->index); - nouveau_event_get(conn->hpd.event); -} + const struct nvkm_gpio_ntfy_rep *line = notify->data; + struct nvif_notify_conn_rep_v0 rep; + int index = conn->index; -static int -nvkm_connector_hpd(void *data, u32 type, int index) -{ - struct nvkm_connector *conn = data; - DBG("HPD: %d\n", type); - schedule_work(&conn->hpd.work); - return NVKM_EVENT_DROP; + DBG("HPD: %d\n", line->mask); + + if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) + rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; + else + rep.mask = NVIF_NOTIFY_CONN_V0_PLUG; + rep.version = 0; + + nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; } int _nvkm_connector_fini(struct nouveau_object *object, bool suspend) { struct nvkm_connector *conn = (void *)object; - if (conn->hpd.event) - nouveau_event_put(conn->hpd.event); + nvkm_notify_put(&conn->hpd); return nouveau_object_fini(&conn->base, suspend); } @@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object) { struct nvkm_connector *conn = (void *)object; int ret = nouveau_object_init(&conn->base); - if (ret == 0) { - if (conn->hpd.event) - nouveau_event_get(conn->hpd.event); - } + if (ret == 0) + nvkm_notify_get(&conn->hpd); return ret; } @@ -74,7 +74,7 @@ void _nvkm_connector_dtor(struct nouveau_object *object) { struct nvkm_connector *conn = (void *)object; - nouveau_event_ref(NULL, &conn->hpd.event); + nvkm_notify_fini(&conn->hpd); nouveau_object_destroy(&conn->base); } @@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent, if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { ERR("hpd %02x unknown\n", info->hpd); - goto done; + return 0; } 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); - goto done; + return 0; } - ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED, - func.line, nvkm_connector_hpd, - conn, &conn->hpd.event); + ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true, + &(struct nvkm_gpio_ntfy_req) { + .mask = NVKM_GPIO_TOGGLED, + .line = func.line, + }, + sizeof(struct nvkm_gpio_ntfy_req), + sizeof(struct nvkm_gpio_ntfy_rep), + &conn->hpd); if (ret) { ERR("func %02x failed, %d\n", info->hpd, ret); } else { @@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent, } } -done: - INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work); return 0; } diff --git a/nvkm/engine/disp/conn.h b/nvkm/engine/disp/conn.h index 035ebeacb..55e5f5c82 100644 --- a/nvkm/engine/disp/conn.h +++ b/nvkm/engine/disp/conn.h @@ -10,10 +10,7 @@ struct nvkm_connector { struct nvbios_connE info; int index; - struct { - struct nouveau_eventh *event; - struct work_struct work; - } hpd; + struct nvkm_notify hpd; }; #define nvkm_connector_create(p,e,c,b,i,d) \ diff --git a/nvkm/engine/disp/dport.c b/nvkm/engine/disp/dport.c index 5a5b59b21..157bda97f 100644 --- a/nvkm/engine/disp/dport.c +++ b/nvkm/engine/disp/dport.c @@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w) cfg--; /* disable link interrupt handling during link training */ - nouveau_event_put(outp->irq); + nvkm_notify_put(&outp->irq); /* enable down-spreading and execute pre-train script from vbios */ dp_link_train_init(dp, outp->dpcd[3] & 0x01); @@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w) DBG("training complete\n"); atomic_set(&outp->lt.done, 1); wake_up(&outp->lt.wait); - nouveau_event_get(outp->irq); + nvkm_notify_get(&outp->irq); } diff --git a/nvkm/engine/disp/gm107.c b/nvkm/engine/disp/gm107.c index 9fc7447fe..a9681df32 100644 --- a/nvkm/engine/disp/gm107.c +++ b/nvkm/engine/disp/gm107.c @@ -93,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nv04.c b/nvkm/engine/disp/nv04.c index a32666ed0..f1f3bd15a 100644 --- a/nvkm/engine/disp/nv04.c +++ b/nvkm/engine/disp/nv04.c @@ -86,17 +86,26 @@ nv04_disp_sclass[] = { ******************************************************************************/ static void -nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head) +nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) { - nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001); } static void -nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head) +nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head) { - nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000); } +static const struct nvkm_event_func +nv04_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nv04_disp_vblank_init, + .fini = nv04_disp_vblank_fini, +}; + static void nv04_disp_intr(struct nouveau_subdev *subdev) { @@ -106,12 +115,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev) u32 pvideo; if (crtc0 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 1, 0); + nouveau_disp_vblank(&priv->base, 0); nv_wr32(priv, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 1, 1); + nouveau_disp_vblank(&priv->base, 1); nv_wr32(priv, 0x602100, 0x00000001); } @@ -140,9 +149,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_engine(priv)->sclass = nv04_disp_sclass; nv_subdev(priv)->intr = nv04_disp_intr; - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nv04_disp_vblank_enable; - priv->base.vblank->disable = nv04_disp_vblank_disable; return 0; } @@ -155,4 +161,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .vblank = &nv04_disp_vblank_func, }.base; diff --git a/nvkm/engine/disp/nv50.c b/nvkm/engine/disp/nv50.c index 2283c442a..5311f0fcd 100644 --- a/nvkm/engine/disp/nv50.c +++ b/nvkm/engine/disp/nv50.c @@ -828,19 +828,7 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, return 0; } -static void -nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); -} - -static void -nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x61002c, (4 << head), 0); -} - -static int +int nv50_disp_base_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -856,14 +844,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent, if (ret) return ret; - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nv50_disp_base_vblank_enable; - priv->base.vblank->disable = nv50_disp_base_vblank_disable; return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, &base->ramht); } -static void +void nv50_disp_base_dtor(struct nouveau_object *object) { struct nv50_disp_base *base = (void *)object; @@ -1040,6 +1025,27 @@ nv50_disp_cclass = { * Display engine implementation ******************************************************************************/ +static void +nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x61002c, (4 << head), 0); +} + +static void +nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x61002c, (4 << head), (4 << head)); +} + +const struct nvkm_event_func +nv50_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nv50_disp_vblank_init, + .fini = nv50_disp_vblank_fini, +}; + static const struct nouveau_enum nv50_disp_intr_error_type[] = { { 3, "ILLEGAL_MTHD" }, @@ -1654,13 +1660,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev) } if (intr1 & 0x00000004) { - nouveau_event_trigger(priv->base.vblank, 1, 0); + nouveau_disp_vblank(&priv->base, 0); nv_wr32(priv, 0x610024, 0x00000004); intr1 &= ~0x00000004; } if (intr1 & 0x00000008) { - nouveau_event_trigger(priv->base.vblank, 1, 1); + nouveau_disp_vblank(&priv->base, 1); nv_wr32(priv, 0x610024, 0x00000008); intr1 &= ~0x00000008; } @@ -1718,6 +1724,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv50_disp_mast_mthd_chan, .mthd.base = &nv50_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nv50.h b/nvkm/engine/disp/nv50.h index 1a886472b..c0e8b7924 100644 --- a/nvkm/engine/disp/nv50.h +++ b/nvkm/engine/disp/nv50.h @@ -165,11 +165,16 @@ extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; extern struct nouveau_ofuncs nv50_disp_base_ofuncs; +int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv50_disp_base_dtor(struct nouveau_object *); extern struct nouveau_oclass nv50_disp_cclass; void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, const struct nv50_disp_mthd_chan *); void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nouveau_subdev *); +extern const struct nvkm_event_func nv50_disp_vblank_func; extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; @@ -195,6 +200,7 @@ extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; extern struct nouveau_oclass nvd0_disp_cclass; void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr(struct nouveau_subdev *); +extern const struct nvkm_event_func nvd0_disp_vblank_func; extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; diff --git a/nvkm/engine/disp/nv84.c b/nvkm/engine/disp/nv84.c index 1cc62e434..dd59774ad 100644 --- a/nvkm/engine/disp/nv84.c +++ b/nvkm/engine/disp/nv84.c @@ -276,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv84_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nv94.c b/nvkm/engine/disp/nv94.c index 4f718a9f5..03a6b2572 100644 --- a/nvkm/engine/disp/nv94.c +++ b/nvkm/engine/disp/nv94.c @@ -143,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv94_disp_outp_sclass, .mthd.core = &nv94_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nva0.c b/nvkm/engine/disp/nva0.c index 6237a9a36..ea1b5a7ad 100644 --- a/nvkm/engine/disp/nva0.c +++ b/nvkm/engine/disp/nva0.c @@ -138,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv84_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nva3.c b/nvkm/engine/disp/nva3.c index 019124d47..00f38a39e 100644 --- a/nvkm/engine/disp/nva3.c +++ b/nvkm/engine/disp/nva3.c @@ -110,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv94_disp_outp_sclass, .mthd.core = &nv94_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nvd0.c b/nvkm/engine/disp/nvd0.c index fa30d8196..1ab216914 100644 --- a/nvkm/engine/disp/nvd0.c +++ b/nvkm/engine/disp/nvd0.c @@ -747,50 +747,6 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, return 0; } -static void -nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); -} - -static void -nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); -} - -static int -nvd0_disp_base_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_base *base; - int ret; - - ret = nouveau_parent_create(parent, engine, oclass, 0, - priv->sclass, 0, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nvd0_disp_base_vblank_enable; - priv->base.vblank->disable = nvd0_disp_base_vblank_disable; - - return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, - &base->ramht); -} - -static void -nvd0_disp_base_dtor(struct nouveau_object *object) -{ - struct nv50_disp_base *base = (void *)object; - nouveau_ramht_ref(NULL, &base->ramht); - nouveau_parent_destroy(&base->base); -} - static int nvd0_disp_base_init(struct nouveau_object *object) { @@ -874,8 +830,8 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend) struct nouveau_ofuncs nvd0_disp_base_ofuncs = { - .ctor = nvd0_disp_base_ctor, - .dtor = nvd0_disp_base_dtor, + .ctor = nv50_disp_base_ctor, + .dtor = nv50_disp_base_dtor, .init = nvd0_disp_base_init, .fini = nvd0_disp_base_fini, }; @@ -916,6 +872,27 @@ nvd0_disp_sclass[] = { * Display engine implementation ******************************************************************************/ +static void +nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); +} + +static void +nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); +} + +const struct nvkm_event_func +nvd0_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nvd0_disp_vblank_init, + .fini = nvd0_disp_vblank_fini, +}; + static struct nvkm_output * exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -1343,7 +1320,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) if (mask & intr) { u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); if (stat & 0x00000001) - nouveau_event_trigger(priv->base.vblank, 1, i); + nouveau_disp_vblank(&priv->base, i); nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); nv_rd32(priv, 0x6100c0 + (i * 0x800)); } @@ -1396,6 +1373,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nvd0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nve0.c b/nvkm/engine/disp/nve0.c index 11328e3f5..1e5a79a5c 100644 --- a/nvkm/engine/disp/nve0.c +++ b/nvkm/engine/disp/nve0.c @@ -258,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/nvf0.c b/nvkm/engine/disp/nvf0.c index 104388081..198bc4b0d 100644 --- a/nvkm/engine/disp/nvf0.c +++ b/nvkm/engine/disp/nvf0.c @@ -93,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, diff --git a/nvkm/engine/disp/outpdp.c b/nvkm/engine/disp/outpdp.c index eb2d77895..6f6e2a898 100644 --- a/nvkm/engine/disp/outpdp.c +++ b/nvkm/engine/disp/outpdp.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/event.h> + #include <subdev/i2c.h> #include "outpdp.h" @@ -86,7 +89,7 @@ done: atomic_set(&outp->lt.done, 0); schedule_work(&outp->lt.work); } else { - nouveau_event_get(outp->irq); + nvkm_notify_get(&outp->irq); } if (wait) { @@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp) } } -static void -nvkm_output_dp_service_work(struct work_struct *work) +static int +nvkm_output_dp_hpd(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work); - struct nouveau_disp *disp = nouveau_disp(outp); - int type = atomic_xchg(&outp->pending, 0); - u32 send = 0; - - if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) { - nvkm_output_dp_detect(outp); - if (type & NVKM_I2C_UNPLUG) - send |= NVKM_HPD_UNPLUG; - if (type & NVKM_I2C_PLUG) - send |= NVKM_HPD_PLUG; - nouveau_event_get(outp->base.conn->hpd.event); - } - - if (type & NVKM_I2C_IRQ) { - nvkm_output_dp_train(&outp->base, 0, true); - send |= NVKM_HPD_IRQ; + struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); + struct nvkm_output_dp *outp; + struct nouveau_disp *disp = nouveau_disp(conn); + const struct nvkm_i2c_ntfy_rep *line = notify->data; + 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_detect(outp); + + 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; + + nvkm_event_send(&disp->hpd, rep.mask, conn->index, + &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; + } } - nouveau_event_trigger(disp->hpd, send, outp->base.info.connector); + WARN_ON(1); + return NVKM_NOTIFY_DROP; } static int -nvkm_output_dp_service(void *data, u32 type, int index) +nvkm_output_dp_irq(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = data; - DBG("HPD: %d\n", type); - atomic_or(type, &outp->pending); - schedule_work(&outp->work); - return NVKM_EVENT_DROP; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nouveau_disp *disp = nouveau_disp(outp); + const struct nvkm_i2c_ntfy_rep *line = notify->data; + 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); + nvkm_output_dp_train(&outp->base, 0, true); + + nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + return NVKM_NOTIFY_DROP; } int _nvkm_output_dp_fini(struct nouveau_object *object, bool suspend) { struct nvkm_output_dp *outp = (void *)object; - nouveau_event_put(outp->irq); + nvkm_notify_put(&outp->irq); nvkm_output_dp_enable(outp, false); return nvkm_output_fini(&outp->base, suspend); } @@ -189,7 +205,7 @@ void _nvkm_output_dp_dtor(struct nouveau_object *object) { struct nvkm_output_dp *outp = (void *)object; - nouveau_event_ref(NULL, &outp->irq); + nvkm_notify_fini(&outp->irq); nvkm_output_destroy(&outp->base); } @@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent, if (ret) return ret; - nouveau_event_ref(NULL, &outp->base.conn->hpd.event); + nvkm_notify_fini(&outp->base.conn->hpd); /* access to the aux channel is not optional... */ if (!outp->base.edid) { @@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent, atomic_set(&outp->lt.done, 0); /* link maintenance */ - ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index, - nvkm_output_dp_service, outp, &outp->irq); + ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_IRQ, + .port = outp->base.edid->index, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->irq); if (ret) { ERR("error monitoring aux irq event: %d\n", ret); return ret; } - INIT_WORK(&outp->work, nvkm_output_dp_service_work); - /* hotplug detect, replaces gpio-based mechanism with aux events */ - ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - outp->base.edid->index, - nvkm_output_dp_service, outp, - &outp->base.conn->hpd.event); + ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, + .port = outp->base.edid->index, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->base.conn->hpd); if (ret) { ERR("error monitoring aux hpd events: %d\n", ret); return ret; diff --git a/nvkm/engine/disp/outpdp.h b/nvkm/engine/disp/outpdp.h index ff33ba12c..1fac367cc 100644 --- a/nvkm/engine/disp/outpdp.h +++ b/nvkm/engine/disp/outpdp.h @@ -12,10 +12,7 @@ struct nvkm_output_dp { struct nvbios_dpout info; u8 version; - struct nouveau_eventh *irq; - struct nouveau_eventh *hpd; - struct work_struct work; - atomic_t pending; + struct nvkm_notify irq; bool present; u8 dpcd[16]; diff --git a/nvkm/engine/disp/priv.h b/nvkm/engine/disp/priv.h index 26e9a4256..5506d119b 100644 --- a/nvkm/engine/disp/priv.h +++ b/nvkm/engine/disp/priv.h @@ -11,6 +11,7 @@ struct nouveau_disp_impl { struct nouveau_oclass base; struct nouveau_oclass **outp; struct nouveau_oclass **conn; + const struct nvkm_event_func *vblank; }; #define nouveau_disp_create(p,e,c,h,i,x,d) \ @@ -39,4 +40,7 @@ int _nouveau_disp_fini(struct nouveau_object *, bool); extern struct nouveau_oclass *nvkm_output_oclass; extern struct nouveau_oclass *nvkm_connector_oclass; +int nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *); +void nouveau_disp_vblank(struct nouveau_disp *, int head); + #endif diff --git a/nvkm/engine/disp/sornv50.c b/nvkm/engine/disp/sornv50.c index 7a1ebdfa9..3101248ee 100644 --- a/nvkm/engine/disp/sornv50.c +++ b/nvkm/engine/disp/sornv50.c @@ -87,7 +87,7 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) struct nvkm_output_dp *outpdp = (void *)outp; switch (data) { case NV94_DISP_SOR_DP_PWR_STATE_OFF: - nouveau_event_put(outpdp->irq); + nvkm_notify_put(&outpdp->irq); ((struct nvkm_output_dp_impl *)nv_oclass(outp)) ->lnk_pwr(outpdp, 0); atomic_set(&outpdp->lt.done, 0); |