summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-11-08 17:41:06 +1000
committerBen Skeggs <bskeggs@redhat.com>2012-11-29 09:57:48 +1000
commit75f8693f30017855c6ab33679ac60e4c339193e4 (patch)
tree6c28f27866e60073670b449e9e333a32fcd19305
parented58aee93c45d5095253d9bc370b418e3d767940 (diff)
downloadop-kernel-dev-75f8693f30017855c6ab33679ac60e4c339193e4.zip
op-kernel-dev-75f8693f30017855c6ab33679ac60e4c339193e4.tar.gz
drm/nouveau/bios: implement some dcb output entry parsing/matching functions
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c30
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c27
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c63
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))
OpenPOWER on IntegriCloud