From 01a976376b6e57838f223dd2d2639597efd92db4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH] drm/nouveau/disp: identity-map display paths to output resources This essentially replicates our current behaviour in a way that's compatible with the new model that's emerging, so that we're able to start porting the hw-specific functions to it. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 10 +++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 74 ++++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 8 +- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index d62e93bb0f70..601fa625e440 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -562,7 +562,10 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, u32 data; int ret; - nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp); + ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp); + if (ret) + return ret; + dp->aux = aux; if (!dp->aux) { OUTP_ERR(&dp->outp, "no aux"); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 2abba07ae632..a8d80eb8d893 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -14,6 +14,16 @@ struct nvkm_ior { char name[8]; struct list_head head; + + struct nvkm_ior_state { + enum nvkm_ior_proto { + CRT, + TMDS, + LVDS, + DP, + UNKNOWN + } proto:3; + } arm, asy; }; struct nvkm_ior_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index f030ff51d076..895a84ca1501 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,11 +22,41 @@ * Authors: Ben Skeggs */ #include "outp.h" +#include "ior.h" #include #include #include +static enum nvkm_ior_proto +nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type) +{ + switch (outp->info.location) { + case 0: + switch (outp->info.type) { + case DCB_OUTPUT_ANALOG: *type = DAC; return CRT; + case DCB_OUTPUT_TMDS : *type = SOR; return TMDS; + case DCB_OUTPUT_LVDS : *type = SOR; return LVDS; + case DCB_OUTPUT_DP : *type = SOR; return DP; + default: + break; + } + break; + case 1: + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: *type = PIOR; return TMDS; + case DCB_OUTPUT_DP : *type = PIOR; return TMDS; /* not a bug */ + default: + break; + } + break; + default: + break; + } + WARN_ON(1); + return UNKNOWN; +} + void nvkm_outp_fini(struct nvkm_outp *outp) { @@ -34,9 +64,38 @@ nvkm_outp_fini(struct nvkm_outp *outp) outp->func->fini(outp); } +static void +nvkm_outp_init_route(struct nvkm_output *outp) +{ + struct nvkm_disp *disp = outp->disp; + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; + struct nvkm_ior *ior; + int id; + + proto = nvkm_outp_xlat(outp, &type); + if (proto == UNKNOWN) + return; + + /* Determine the specific OR, if any, this device is attached to. */ + if (1) { + /* Prior to DCB 4.1, this is hardwired like so. */ + id = ffs(outp->info.or) - 1; + } + + ior = nvkm_ior_find(disp, type, id); + if (!ior) { + WARN_ON(1); + return; + } + + outp->ior = ior; +} + void nvkm_outp_init(struct nvkm_outp *outp) { + nvkm_outp_init_route(outp); if (outp->func->init) outp->func->init(outp); } @@ -53,11 +112,13 @@ nvkm_outp_del(struct nvkm_outp **poutp) } } -void +int nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct nvkm_outp *outp) { struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; outp->func = func; outp->disp = disp; @@ -72,6 +133,13 @@ nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, outp->info.type >= 2 ? outp->info.sorconf.link : 0, outp->info.connector, outp->info.i2c_index, outp->info.bus, outp->info.heads); + + /* Cull output paths we can't map to an output resource. */ + proto = nvkm_outp_xlat(outp, &type); + if (proto == UNKNOWN) + return -ENODEV; + + return 0; } int @@ -81,7 +149,5 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, { if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) return -ENOMEM; - - nvkm_outp_ctor(func, disp, index, dcbE, *poutp); - return 0; + return nvkm_outp_ctor(func, disp, index, dcbE, *poutp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 682fc99c9351..e48251c37822 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -11,16 +11,18 @@ struct nvkm_outp { int index; 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_conn *conn; + + /* Assembly state. */ + struct nvkm_ior *ior; }; -void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_outp *); +int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_outp *); void nvkm_outp_del(struct nvkm_outp **); void nvkm_outp_init(struct nvkm_outp *); void nvkm_outp_fini(struct nvkm_outp *);