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/bit.h>
0026 #include <subdev/bios/dp.h>
0027
0028 u16
0029 nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0030 {
0031 struct bit_entry d;
0032
0033 if (!bit_entry(bios, 'd', &d)) {
0034 if (d.version == 1 && d.length >= 2) {
0035 u16 data = nvbios_rd16(bios, d.offset);
0036 if (data) {
0037 *ver = nvbios_rd08(bios, data + 0x00);
0038 switch (*ver) {
0039 case 0x20:
0040 case 0x21:
0041 case 0x30:
0042 case 0x40:
0043 case 0x41:
0044 case 0x42:
0045 *hdr = nvbios_rd08(bios, data + 0x01);
0046 *len = nvbios_rd08(bios, data + 0x02);
0047 *cnt = nvbios_rd08(bios, data + 0x03);
0048 return data;
0049 default:
0050 break;
0051 }
0052 }
0053 }
0054 }
0055
0056 return 0x0000;
0057 }
0058
0059 static u16
0060 nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,
0061 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0062 {
0063 u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
0064 if (data && idx < *cnt) {
0065 u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len);
0066 switch (*ver * !!outp) {
0067 case 0x20:
0068 case 0x21:
0069 case 0x30:
0070 *hdr = nvbios_rd08(bios, data + 0x04);
0071 *len = nvbios_rd08(bios, data + 0x05);
0072 *cnt = nvbios_rd08(bios, outp + 0x04);
0073 break;
0074 case 0x40:
0075 case 0x41:
0076 case 0x42:
0077 *hdr = nvbios_rd08(bios, data + 0x04);
0078 *cnt = 0;
0079 *len = 0;
0080 break;
0081 default:
0082 break;
0083 }
0084 return outp;
0085 }
0086 *ver = 0x00;
0087 return 0x0000;
0088 }
0089
0090 u16
0091 nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,
0092 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
0093 struct nvbios_dpout *info)
0094 {
0095 u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
0096 memset(info, 0x00, sizeof(*info));
0097 if (data && *ver) {
0098 info->type = nvbios_rd16(bios, data + 0x00);
0099 info->mask = nvbios_rd16(bios, data + 0x02);
0100 switch (*ver) {
0101 case 0x20:
0102 info->mask |= 0x00c0;
0103 fallthrough;
0104 case 0x21:
0105 case 0x30:
0106 info->flags = nvbios_rd08(bios, data + 0x05);
0107 info->script[0] = nvbios_rd16(bios, data + 0x06);
0108 info->script[1] = nvbios_rd16(bios, data + 0x08);
0109 if (*len >= 0x0c)
0110 info->lnkcmp = nvbios_rd16(bios, data + 0x0a);
0111 if (*len >= 0x0f) {
0112 info->script[2] = nvbios_rd16(bios, data + 0x0c);
0113 info->script[3] = nvbios_rd16(bios, data + 0x0e);
0114 }
0115 if (*len >= 0x11)
0116 info->script[4] = nvbios_rd16(bios, data + 0x10);
0117 break;
0118 case 0x40:
0119 case 0x41:
0120 case 0x42:
0121 info->flags = nvbios_rd08(bios, data + 0x04);
0122 info->script[0] = nvbios_rd16(bios, data + 0x05);
0123 info->script[1] = nvbios_rd16(bios, data + 0x07);
0124 info->lnkcmp = nvbios_rd16(bios, data + 0x09);
0125 info->script[2] = nvbios_rd16(bios, data + 0x0b);
0126 info->script[3] = nvbios_rd16(bios, data + 0x0d);
0127 info->script[4] = nvbios_rd16(bios, data + 0x0f);
0128 break;
0129 default:
0130 data = 0x0000;
0131 break;
0132 }
0133 }
0134 return data;
0135 }
0136
0137 u16
0138 nvbios_dpout_match(struct nvkm_bios *bios, u16 type, u16 mask,
0139 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
0140 struct nvbios_dpout *info)
0141 {
0142 u16 data, idx = 0;
0143 while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
0144 if (data && info->type == type) {
0145 if ((info->mask & mask) == mask)
0146 break;
0147 }
0148 }
0149 return data;
0150 }
0151
0152 static u16
0153 nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
0154 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0155 {
0156 if (*ver >= 0x40) {
0157 outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
0158 *hdr = *hdr + (*len * * cnt);
0159 *len = nvbios_rd08(bios, outp + 0x06);
0160 *cnt = nvbios_rd08(bios, outp + 0x07) *
0161 nvbios_rd08(bios, outp + 0x05);
0162 }
0163
0164 if (idx < *cnt)
0165 return outp + *hdr + (idx * *len);
0166
0167 return 0x0000;
0168 }
0169
0170 u16
0171 nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
0172 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
0173 struct nvbios_dpcfg *info)
0174 {
0175 u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
0176 memset(info, 0x00, sizeof(*info));
0177 if (data) {
0178 switch (*ver) {
0179 case 0x20:
0180 case 0x21:
0181 info->dc = nvbios_rd08(bios, data + 0x02);
0182 info->pe = nvbios_rd08(bios, data + 0x03);
0183 info->tx_pu = nvbios_rd08(bios, data + 0x04);
0184 break;
0185 case 0x30:
0186 case 0x40:
0187 case 0x41:
0188 info->pc = nvbios_rd08(bios, data + 0x00);
0189 info->dc = nvbios_rd08(bios, data + 0x01);
0190 info->pe = nvbios_rd08(bios, data + 0x02);
0191 info->tx_pu = nvbios_rd08(bios, data + 0x03);
0192 break;
0193 case 0x42:
0194 info->dc = nvbios_rd08(bios, data + 0x00);
0195 info->pe = nvbios_rd08(bios, data + 0x01);
0196 info->tx_pu = nvbios_rd08(bios, data + 0x02);
0197 break;
0198 default:
0199 data = 0x0000;
0200 break;
0201 }
0202 }
0203 return data;
0204 }
0205
0206 u16
0207 nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
0208 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
0209 struct nvbios_dpcfg *info)
0210 {
0211 u8 idx = 0xff;
0212 u16 data;
0213
0214 if (*ver >= 0x30) {
0215 static const u8 vsoff[] = { 0, 4, 7, 9 };
0216 idx = (pc * 10) + vsoff[vs] + pe;
0217 if (*ver >= 0x40 && *ver <= 0x41 && *hdr >= 0x12)
0218 idx += nvbios_rd08(bios, outp + 0x11) * 40;
0219 else
0220 if (*ver >= 0x42)
0221 idx += nvbios_rd08(bios, outp + 0x11) * 10;
0222 } else {
0223 while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
0224 ver, hdr, cnt, len))) {
0225 if (nvbios_rd08(bios, data + 0x00) == vs &&
0226 nvbios_rd08(bios, data + 0x01) == pe)
0227 break;
0228 }
0229 }
0230
0231 return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
0232 }