diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-11-08 07:41:06 (GMT) |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-11-28 23:57:48 (GMT) |
commit | 75f8693f30017855c6ab33679ac60e4c339193e4 (patch) | |
tree | 6c28f27866e60073670b449e9e333a32fcd19305 /drivers/gpu/drm/nouveau/core | |
parent | ed58aee93c45d5095253d9bc370b418e3d767940 (diff) | |
download | linux-fsl-qoriq-75f8693f30017855c6ab33679ac60e4c339193e4.tar.xz |
drm/nouveau/bios: implement some dcb output entry parsing/matching functions
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h | 5 | ||||
-rw-r--r-- | drivers/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 bf07248..5ac8c42 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 4a8117d..0ca12b9 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 0577c67..b79025d 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 7d75038..bbd709f 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)) |