drm/nouveau/bios: implement some dcb output entry parsing/matching functions
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Родитель
ed58aee93c
Коммит
75f8693f30
|
@ -576,8 +576,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
|
||||||
struct nvbios_outp *info)
|
struct nvbios_outp *info)
|
||||||
{
|
{
|
||||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||||
u16 data, idx = 0;
|
u16 mask, type, data;
|
||||||
u16 mask, type;
|
|
||||||
|
|
||||||
if (outp < 4) {
|
if (outp < 4) {
|
||||||
type = DCB_OUTPUT_ANALOG;
|
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 |= 0x0001 << outp;
|
||||||
mask |= 0x0100 << head;
|
mask |= 0x0100 << head;
|
||||||
|
|
||||||
/* this is a tad special, but for the moment its needed to get
|
data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
|
||||||
* all the dcb data required by the vbios scripts.. will be cleaned
|
if (!data)
|
||||||
* up later as more bits are moved to the core..
|
return 0x0000;
|
||||||
*/
|
|
||||||
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) !=
|
return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
|
||||||
((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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x0000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
|
@ -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 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
|
||||||
const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
|
const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
|
||||||
const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
|
const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
|
||||||
struct dcb_output outp = {
|
struct dcb_output outp;
|
||||||
.type = type,
|
u8 ver, hdr;
|
||||||
.or = (1 << or),
|
|
||||||
.sorconf.link = (1 << link),
|
|
||||||
};
|
|
||||||
u8 ver, hdr, idx = 0;
|
|
||||||
u32 data;
|
u32 data;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (size < sizeof(u32))
|
if (size < sizeof(u32))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
data = *(u32 *)args;
|
||||||
|
|
||||||
while (type && (data = dcb_outp(bios, idx++, &ver, &hdr))) {
|
if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
|
||||||
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)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
data = *(u32 *)args;
|
|
||||||
switch (mthd & ~0x3f) {
|
switch (mthd & ~0x3f) {
|
||||||
case NV50_DISP_SOR_PWR:
|
case NV50_DISP_SOR_PWR:
|
||||||
ret = priv->sor.power(priv, or, data);
|
ret = priv->sor.power(priv, or, data);
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct dcb_output {
|
||||||
uint8_t bus;
|
uint8_t bus;
|
||||||
uint8_t location;
|
uint8_t location;
|
||||||
uint8_t or;
|
uint8_t or;
|
||||||
|
uint8_t link;
|
||||||
bool duallink_possible;
|
bool duallink_possible;
|
||||||
union {
|
union {
|
||||||
struct sor_conf {
|
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_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(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)
|
int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
|
||||||
(struct nouveau_bios *, void *, int index, u16 entry));
|
(struct nouveau_bios *, void *, int index, u16 entry));
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,69 @@ dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
|
||||||
return 0x0000;
|
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
|
int
|
||||||
dcb_outp_foreach(struct nouveau_bios *bios, void *data,
|
dcb_outp_foreach(struct nouveau_bios *bios, void *data,
|
||||||
int (*exec)(struct nouveau_bios *, void *, int, u16))
|
int (*exec)(struct nouveau_bios *, void *, int, u16))
|
||||||
|
|
Загрузка…
Ссылка в новой задаче