From 75f8693f30017855c6ab33679ac60e4c339193e4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 8 Nov 2012 17:41:06 +1000 Subject: [PATCH] drm/nouveau/bios: implement some dcb output entry parsing/matching functions Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/core/engine/disp/nvd0.c | 30 ++------- .../drm/nouveau/core/engine/disp/sornv50.c | 27 ++------ .../nouveau/core/include/subdev/bios/dcb.h | 5 ++ .../gpu/drm/nouveau/core/subdev/bios/dcb.c | 63 +++++++++++++++++++ 4 files changed, 77 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index bf07248452a6..5ac8c429852d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -576,8 +576,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, struct nvbios_outp *info) { struct nouveau_bios *bios = nouveau_bios(priv); - u16 data, idx = 0; - u16 mask, type; + u16 mask, type, data; if (outp < 4) { type = DCB_OUTPUT_ANALOG; @@ -602,30 +601,11 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, mask |= 0x0001 << outp; mask |= 0x0100 << head; - /* this is a tad special, but for the moment its needed to get - * all the dcb data required by the vbios scripts.. will be cleaned - * up later as more bits are moved to the core.. - */ - while ((data = dcb_outp(bios, idx++, ver, hdr))) { - u32 conn = nv_ro32(bios, data + 0); - u32 conf = nv_ro32(bios, data + 4); - if ((conn & 0x00300000) || - (conn & 0x0000000f) != type || - (conn & 0x0f000000) != (0x01000000 << outp)) - continue; - - if ( (mask & 0x00c0) && (mask & 0x00c0) != - ((mask & 0x00c0) & ((conf & 0x00000030) << 2))) - continue; - - dcb->type = type; - dcb->or = 1 << outp; - dcb->connector = (conn & 0x0000f000) >> 12; - - return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); - } + data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); + if (!data) + return 0x0000; - return 0x0000; + return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); } static bool diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index 4a8117d33f5a..0ca12b9230fd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c @@ -53,37 +53,18 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2; const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or); - struct dcb_output outp = { - .type = type, - .or = (1 << or), - .sorconf.link = (1 << link), - }; - u8 ver, hdr, idx = 0; + struct dcb_output outp; + u8 ver, hdr; u32 data; int ret = -EINVAL; if (size < sizeof(u32)) return -EINVAL; + data = *(u32 *)args; - while (type && (data = dcb_outp(bios, idx++, &ver, &hdr))) { - u32 conn = nv_ro32(bios, data + 0); - u32 conf = nv_ro32(bios, data + 4); - if ((conn & 0x00300000) || - (conn & 0x0000000f) != type || - (conn & 0x0f000000) != (0x01000000 << or)) - continue; - - if ( (mask & 0x00c0) && (mask & 0x00c0) != - ((mask & 0x00c0) & ((conf & 0x00000030) << 2))) - continue; - - outp.connector = (conn & 0x0000f000) >> 12; - } - - if (data == 0x0000) + if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp)) return -ENODEV; - data = *(u32 *)args; switch (mthd & ~0x3f) { case NV50_DISP_SOR_PWR: ret = priv->sor.power(priv, or, data); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h index 0577c67612d4..b79025da581e 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h @@ -23,6 +23,7 @@ struct dcb_output { uint8_t bus; uint8_t location; uint8_t or; + uint8_t link; bool duallink_possible; union { struct sor_conf { @@ -55,6 +56,10 @@ struct dcb_output { u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len); u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); +u16 dcb_outp_parse(struct nouveau_bios *, u8 idx, u8 *, u8 *, + struct dcb_output *); +u16 dcb_outp_match(struct nouveau_bios *, u16 type, u16 mask, u8 *, u8 *, + struct dcb_output *); int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec) (struct nouveau_bios *, void *, int index, u16 entry)); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 7d750382a833..bbd709fba0a9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -107,6 +107,69 @@ dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) return 0x0000; } +u16 +dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, + struct dcb_output *outp) +{ + u16 dcb = dcb_outp(bios, idx, ver, len); + if (dcb) { + if (*ver >= 0x20) { + u32 conn = nv_ro32(bios, dcb + 0x00); + outp->or = (conn & 0x0f000000) >> 24; + outp->location = (conn & 0x00300000) >> 20; + outp->bus = (conn & 0x000f0000) >> 16; + outp->connector = (conn & 0x0000f000) >> 12; + outp->heads = (conn & 0x00000f00) >> 8; + outp->i2c_index = (conn & 0x000000f0) >> 4; + outp->type = (conn & 0x0000000f); + outp->link = 0; + } else { + dcb = 0x0000; + } + + if (*ver >= 0x40) { + u32 conf = nv_ro32(bios, dcb + 0x04); + switch (outp->type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + case DCB_OUTPUT_DP: + outp->link = (conf & 0x00000030) >> 4; + outp->sorconf.link = outp->link; /*XXX*/ + break; + default: + break; + } + } + } + return dcb; +} + +static inline u16 +dcb_outp_hasht(struct dcb_output *outp) +{ + return outp->type; +} + +static inline u16 +dcb_outp_hashm(struct dcb_output *outp) +{ + return (outp->heads << 8) | (outp->link << 6) | outp->or; +} + +u16 +dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask, + u8 *ver, u8 *len, struct dcb_output *outp) +{ + u16 dcb, idx = 0; + while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) { + if (dcb_outp_hasht(outp) == type) { + if ((dcb_outp_hashm(outp) & mask) == mask) + break; + } + } + return dcb; +} + int dcb_outp_foreach(struct nouveau_bios *bios, void *data, int (*exec)(struct nouveau_bios *, void *, int, u16)) -- 2.34.1