0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <subdev/bios.h>
0025 #include <subdev/bios/dcb.h>
0026
0027 u16
0028 dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0029 {
0030 struct nvkm_subdev *subdev = &bios->subdev;
0031 struct nvkm_device *device = subdev->device;
0032 u16 dcb = 0x0000;
0033
0034 if (device->card_type > NV_04)
0035 dcb = nvbios_rd16(bios, 0x36);
0036 if (!dcb) {
0037 nvkm_warn(subdev, "DCB table not found\n");
0038 return dcb;
0039 }
0040
0041 *ver = nvbios_rd08(bios, dcb);
0042
0043 if (*ver >= 0x42) {
0044 nvkm_warn(subdev, "DCB version 0x%02x unknown\n", *ver);
0045 return 0x0000;
0046 } else
0047 if (*ver >= 0x30) {
0048 if (nvbios_rd32(bios, dcb + 6) == 0x4edcbdcb) {
0049 *hdr = nvbios_rd08(bios, dcb + 1);
0050 *cnt = nvbios_rd08(bios, dcb + 2);
0051 *len = nvbios_rd08(bios, dcb + 3);
0052 return dcb;
0053 }
0054 } else
0055 if (*ver >= 0x20) {
0056 if (nvbios_rd32(bios, dcb + 4) == 0x4edcbdcb) {
0057 u16 i2c = nvbios_rd16(bios, dcb + 2);
0058 *hdr = 8;
0059 *cnt = (i2c - dcb) / 8;
0060 *len = 8;
0061 return dcb;
0062 }
0063 } else
0064 if (*ver >= 0x15) {
0065 if (!nvbios_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
0066 u16 i2c = nvbios_rd16(bios, dcb + 2);
0067 *hdr = 4;
0068 *cnt = (i2c - dcb) / 10;
0069 *len = 10;
0070 return dcb;
0071 }
0072 } else {
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 nvkm_debug(subdev, "DCB contains no useful data\n");
0091 return 0x0000;
0092 }
0093
0094 nvkm_warn(subdev, "DCB header validation failed\n");
0095 return 0x0000;
0096 }
0097
0098 u16
0099 dcb_outp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
0100 {
0101 u8 hdr, cnt;
0102 u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
0103 if (dcb && idx < cnt)
0104 return dcb + hdr + (idx * *len);
0105 return 0x0000;
0106 }
0107
0108 static inline u16
0109 dcb_outp_hasht(struct dcb_output *outp)
0110 {
0111 return (outp->extdev << 8) | (outp->location << 4) | outp->type;
0112 }
0113
0114 static inline u16
0115 dcb_outp_hashm(struct dcb_output *outp)
0116 {
0117 return (outp->heads << 8) | (outp->link << 6) | outp->or;
0118 }
0119
0120 u16
0121 dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
0122 struct dcb_output *outp)
0123 {
0124 u16 dcb = dcb_outp(bios, idx, ver, len);
0125 memset(outp, 0x00, sizeof(*outp));
0126 if (dcb) {
0127 if (*ver >= 0x20) {
0128 u32 conn = nvbios_rd32(bios, dcb + 0x00);
0129 outp->or = (conn & 0x0f000000) >> 24;
0130 outp->location = (conn & 0x00300000) >> 20;
0131 outp->bus = (conn & 0x000f0000) >> 16;
0132 outp->connector = (conn & 0x0000f000) >> 12;
0133 outp->heads = (conn & 0x00000f00) >> 8;
0134 outp->i2c_index = (conn & 0x000000f0) >> 4;
0135 outp->type = (conn & 0x0000000f);
0136 outp->link = 0;
0137 } else {
0138 dcb = 0x0000;
0139 }
0140
0141 if (*ver >= 0x40) {
0142 u32 conf = nvbios_rd32(bios, dcb + 0x04);
0143 switch (outp->type) {
0144 case DCB_OUTPUT_DP:
0145 switch (conf & 0x00e00000) {
0146 case 0x00000000:
0147 outp->dpconf.link_bw = 0x06;
0148 break;
0149 case 0x00200000:
0150 outp->dpconf.link_bw = 0x0a;
0151 break;
0152 case 0x00400000:
0153 outp->dpconf.link_bw = 0x14;
0154 break;
0155 case 0x00600000:
0156 default:
0157 outp->dpconf.link_bw = 0x1e;
0158 break;
0159 }
0160
0161 switch ((conf & 0x0f000000) >> 24) {
0162 case 0xf:
0163 case 0x4:
0164 outp->dpconf.link_nr = 4;
0165 break;
0166 case 0x3:
0167 case 0x2:
0168 outp->dpconf.link_nr = 2;
0169 break;
0170 case 0x1:
0171 default:
0172 outp->dpconf.link_nr = 1;
0173 break;
0174 }
0175 fallthrough;
0176
0177 case DCB_OUTPUT_TMDS:
0178 case DCB_OUTPUT_LVDS:
0179 outp->link = (conf & 0x00000030) >> 4;
0180 outp->sorconf.link = outp->link;
0181 outp->extdev = 0x00;
0182 if (outp->location != 0)
0183 outp->extdev = (conf & 0x0000ff00) >> 8;
0184 break;
0185 default:
0186 break;
0187 }
0188 }
0189
0190 outp->hasht = dcb_outp_hasht(outp);
0191 outp->hashm = dcb_outp_hashm(outp);
0192 }
0193 return dcb;
0194 }
0195
0196 u16
0197 dcb_outp_match(struct nvkm_bios *bios, u16 type, u16 mask,
0198 u8 *ver, u8 *len, struct dcb_output *outp)
0199 {
0200 u16 dcb, idx = 0;
0201 while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
0202 if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
0203 if ((dcb_outp_hashm(outp) & mask) == mask)
0204 break;
0205 }
0206 }
0207 return dcb;
0208 }
0209
0210 int
0211 dcb_outp_foreach(struct nvkm_bios *bios, void *data,
0212 int (*exec)(struct nvkm_bios *, void *, int, u16))
0213 {
0214 int ret, idx = -1;
0215 u8 ver, len;
0216 u16 outp;
0217
0218 while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
0219 if (nvbios_rd32(bios, outp) == 0x00000000)
0220 break;
0221 if (nvbios_rd32(bios, outp) == 0xffffffff)
0222 break;
0223
0224 if (nvbios_rd08(bios, outp) == DCB_OUTPUT_UNUSED)
0225 continue;
0226 if (nvbios_rd08(bios, outp) == DCB_OUTPUT_EOL)
0227 break;
0228
0229 ret = exec(bios, data, idx, outp);
0230 if (ret)
0231 return ret;
0232 }
0233
0234 return 0;
0235 }