u32 nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, struct nvbios_connE *info) { u32 data = nvbios_connEe(bios, idx, ver, len); memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x30: case 0x40: info->type = nvbios_rd08(bios, data + 0x00); info->location = nvbios_rd08(bios, data + 0x01) & 0x0f; info->hpd = (nvbios_rd08(bios, data + 0x01) & 0x30) >> 4; info->dp = (nvbios_rd08(bios, data + 0x01) & 0xc0) >> 6; if (*len < 4) return data; info->hpd |= (nvbios_rd08(bios, data + 0x02) & 0x03) << 2; info->dp |= nvbios_rd08(bios, data + 0x02) & 0x0c; info->di = (nvbios_rd08(bios, data + 0x02) & 0xf0) >> 4; info->hpd |= (nvbios_rd08(bios, data + 0x03) & 0x07) << 4; info->sr = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; info->lcdid = (nvbios_rd08(bios, data + 0x03) & 0x70) >> 4; return data; default: break; } return 0x00000000; }
static u16 nvbios_iccsense_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_P; u16 iccsense; if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 || bit_P.length < 0x2c) return 0; iccsense = nvbios_rd16(bios, bit_P.offset + 0x28); if (!iccsense) return 0; *ver = nvbios_rd08(bios, iccsense + 0); switch (*ver) { case 0x10: case 0x20: *hdr = nvbios_rd08(bios, iccsense + 1); *len = nvbios_rd08(bios, iccsense + 2); *cnt = nvbios_rd08(bios, iccsense + 3); return iccsense; default: break; } return 0; }
u8 mxm_ddc_map(struct nvkm_bios *bios, u8 port) { struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 8) { u16 map = nvbios_rd16(bios, mxm + 6); if (map) { ver = nvbios_rd08(bios, map); if (ver == 0x10) { if (port < nvbios_rd08(bios, map + 3)) { map += nvbios_rd08(bios, map + 1); map += port; return nvbios_rd08(bios, map); } return 0x00; } nvkm_warn(subdev, "unknown ddc map v%02x\n", ver); } } /* v2.x: directly write port as dcb i2cidx */ return (port << 4) | port; }
u32 nvbios_P0260Te(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz) { struct bit_entry bit_P; u32 data = 0x00000000; if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2 && bit_P.length > 0x63) data = nvbios_rd32(bios, bit_P.offset + 0x60); if (data) { *ver = nvbios_rd08(bios, data + 0); switch (*ver) { case 0x10: *hdr = nvbios_rd08(bios, data + 1); *cnt = nvbios_rd08(bios, data + 2); *len = 4; *xnr = nvbios_rd08(bios, data + 3); *xsz = 4; return data; default: break; } } } return 0x00000000; }
u32 nvbios_vmap_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_P; u32 vmap = 0; if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) { vmap = nvbios_rd32(bios, bit_P.offset + 0x20); if (vmap) { *ver = nvbios_rd08(bios, vmap + 0); switch (*ver) { case 0x10: case 0x20: *hdr = nvbios_rd08(bios, vmap + 1); *cnt = nvbios_rd08(bios, vmap + 3); *len = nvbios_rd08(bios, vmap + 2); return vmap; default: break; } } } } return 0; }
static u32 pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_C; u32 data = 0x0000; if (!bit_entry(bios, 'C', &bit_C)) { if (bit_C.version == 1 && bit_C.length >= 10) data = nvbios_rd16(bios, bit_C.offset + 8); if (bit_C.version == 2 && bit_C.length >= 4) data = nvbios_rd32(bios, bit_C.offset + 0); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = nvbios_rd08(bios, data + 1); *len = nvbios_rd08(bios, data + 2); *cnt = nvbios_rd08(bios, data + 3); return data; } } if (bmp_version(bios) >= 0x0524) { data = nvbios_rd16(bios, bios->bmp_offset + 142); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = 1; *cnt = 1; *len = 0x18; return data; } } *ver = 0x00; return data; }
static u16 nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len); switch (*ver * !!outp) { case 0x20: case 0x21: case 0x30: *hdr = nvbios_rd08(bios, data + 0x04); *len = nvbios_rd08(bios, data + 0x05); *cnt = nvbios_rd08(bios, outp + 0x04); break; case 0x40: case 0x41: case 0x42: *hdr = nvbios_rd08(bios, data + 0x04); *cnt = 0; *len = 0; break; default: break; } return outp; } *ver = 0x00; return 0x0000; }
u32 nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, struct nvbios_vmap_entry *info) { u32 vmap = nvbios_vmap_entry(bios, idx, ver, len); memset(info, 0x00, sizeof(*info)); switch (!!vmap * *ver) { case 0x10: info->link = 0xff; info->min = nvbios_rd32(bios, vmap + 0x00); info->max = nvbios_rd32(bios, vmap + 0x04); info->arg[0] = nvbios_rd32(bios, vmap + 0x08); info->arg[1] = nvbios_rd32(bios, vmap + 0x0c); info->arg[2] = nvbios_rd32(bios, vmap + 0x10); break; case 0x20: info->mode = nvbios_rd08(bios, vmap + 0x00); info->link = nvbios_rd08(bios, vmap + 0x01); info->min = nvbios_rd32(bios, vmap + 0x02); info->max = nvbios_rd32(bios, vmap + 0x06); info->arg[0] = nvbios_rd32(bios, vmap + 0x0a); info->arg[1] = nvbios_rd32(bios, vmap + 0x0e); info->arg[2] = nvbios_rd32(bios, vmap + 0x12); info->arg[3] = nvbios_rd32(bios, vmap + 0x16); info->arg[4] = nvbios_rd32(bios, vmap + 0x1a); info->arg[5] = nvbios_rd32(bios, vmap + 0x1e); break; } return vmap; }
u16 nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry d; if (!bit_entry(bios, 'd', &d)) { if (d.version == 1 && d.length >= 2) { u16 data = nvbios_rd16(bios, d.offset); if (data) { *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x20: case 0x21: case 0x30: case 0x40: case 0x41: case 0x42: *hdr = nvbios_rd08(bios, data + 0x01); *len = nvbios_rd08(bios, data + 0x02); *cnt = nvbios_rd08(bios, data + 0x03); return data; default: break; } } } } return 0x0000; }
u16 nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u8 idx = 0xff; u16 data; if (*ver >= 0x30) { const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (pc * 10) + vsoff[vs] + pe; if (*ver >= 0x40 && *ver <= 0x41 && *hdr >= 0x12) idx += nvbios_rd08(bios, outp + 0x11) * 40; else if (*ver >= 0x42) idx += nvbios_rd08(bios, outp + 0x11) * 10; } else { while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { if (nvbios_rd08(bios, data + 0x00) == vs && nvbios_rd08(bios, data + 0x01) == pe) break; } } return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info); }
u16 nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data) { switch (*ver) { case 0x20: case 0x21: info->dc = nvbios_rd08(bios, data + 0x02); info->pe = nvbios_rd08(bios, data + 0x03); info->tx_pu = nvbios_rd08(bios, data + 0x04); break; case 0x30: case 0x40: case 0x41: info->pc = nvbios_rd08(bios, data + 0x00); info->dc = nvbios_rd08(bios, data + 0x01); info->pe = nvbios_rd08(bios, data + 0x02); info->tx_pu = nvbios_rd08(bios, data + 0x03); break; case 0x42: info->dc = nvbios_rd08(bios, data + 0x00); info->pe = nvbios_rd08(bios, data + 0x01); info->tx_pu = nvbios_rd08(bios, data + 0x02); break; default: data = 0x0000; break; } } return data; }
/* Pretend a performance mode is also a rammap entry, helps coalesce entries * later on */ u32 nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, struct nvbios_ramcfg *p) { memset(p, 0x00, sizeof(*p)); p->rammap_00_16_20 = (nvbios_rd08(bios, data + 0x16) & 0x20) >> 5; p->rammap_00_16_40 = (nvbios_rd08(bios, data + 0x16) & 0x40) >> 6; p->rammap_00_17_02 = (nvbios_rd08(bios, data + 0x17) & 0x02) >> 1; return data; }
u32 nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u32 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb && *ver >= 0x30 && *hdr >= 0x16) { u32 data = nvbios_rd16(bios, dcb + 0x14); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = nvbios_rd08(bios, data + 1); *cnt = nvbios_rd08(bios, data + 2); *len = nvbios_rd08(bios, data + 3); return data; } } return 0x00000000; }
u16 nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_volt *info) { u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); switch (!!volt * *ver) { case 0x12: info->type = NVBIOS_VOLT_GPIO; info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x20: info->type = NVBIOS_VOLT_GPIO; info->vidmask = nvbios_rd08(bios, volt + 0x05); break; case 0x30: info->type = NVBIOS_VOLT_GPIO; info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x40: info->type = NVBIOS_VOLT_GPIO; info->base = nvbios_rd32(bios, volt + 0x04); info->step = nvbios_rd16(bios, volt + 0x08); info->vidmask = nvbios_rd08(bios, volt + 0x0b); /*XXX*/ info->min = 0; info->max = info->base; break; case 0x50: info->min = nvbios_rd32(bios, volt + 0x0a); info->max = nvbios_rd32(bios, volt + 0x0e); info->base = nvbios_rd32(bios, volt + 0x12) & 0x00ffffff; /* offset 4 seems to be a flag byte */ if (nvbios_rd32(bios, volt + 0x4) & 1) { info->type = NVBIOS_VOLT_PWM; info->pwm_freq = nvbios_rd32(bios, volt + 0x5) / 1000; info->pwm_range = nvbios_rd32(bios, volt + 0x16); } else { info->type = NVBIOS_VOLT_GPIO; info->vidmask = nvbios_rd08(bios, volt + 0x06); info->step = nvbios_rd16(bios, volt + 0x16); } break; } return volt; }
u16 nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *info) { u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data && *ver) { info->type = nvbios_rd16(bios, data + 0x00); info->mask = nvbios_rd16(bios, data + 0x02); switch (*ver) { case 0x20: info->mask |= 0x00c0; /* match any link */ /* fall-through */ case 0x21: case 0x30: info->flags = nvbios_rd08(bios, data + 0x05); info->script[0] = nvbios_rd16(bios, data + 0x06); info->script[1] = nvbios_rd16(bios, data + 0x08); if (*len >= 0x0c) info->lnkcmp = nvbios_rd16(bios, data + 0x0a); if (*len >= 0x0f) { info->script[2] = nvbios_rd16(bios, data + 0x0c); info->script[3] = nvbios_rd16(bios, data + 0x0e); } if (*len >= 0x11) info->script[4] = nvbios_rd16(bios, data + 0x10); break; case 0x40: case 0x41: case 0x42: info->flags = nvbios_rd08(bios, data + 0x04); info->script[0] = nvbios_rd16(bios, data + 0x05); info->script[1] = nvbios_rd16(bios, data + 0x07); info->lnkcmp = nvbios_rd16(bios, data + 0x09); info->script[2] = nvbios_rd16(bios, data + 0x0b); info->script[3] = nvbios_rd16(bios, data + 0x0d); info->script[4] = nvbios_rd16(bios, data + 0x0f); break; default: data = 0x0000; break; } } return data; }
static u16 nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { if (*ver >= 0x40) { outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); *len = nvbios_rd08(bios, outp + 0x06); *cnt = nvbios_rd08(bios, outp + 0x07) * nvbios_rd08(bios, outp + 0x05); } if (idx < *cnt) return outp + *hdr + (idx * *len); return 0x0000; }
u32 nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_p; u32 data = 0; if (!bit_entry(bios, 'p', &bit_p)) { if (bit_p.version == 2 && bit_p.length >= 4) data = nvbios_rd32(bios, bit_p.offset + 0x00); if ((data = weirdo_pointer(bios, data))) { *ver = nvbios_rd08(bios, data + 0x00); /* maybe? */ *hdr = nvbios_rd08(bios, data + 0x01); *len = nvbios_rd08(bios, data + 0x02); *cnt = nvbios_rd08(bios, data + 0x03); } } return data; }
u32 nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) { struct bit_entry bit_P; u32 rammap = 0x0000; if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) rammap = nvbios_rd32(bios, bit_P.offset + 4); if (rammap) { *ver = nvbios_rd08(bios, rammap + 0); switch (*ver) { case 0x10: case 0x11: *hdr = nvbios_rd08(bios, rammap + 1); *cnt = nvbios_rd08(bios, rammap + 5); *len = nvbios_rd08(bios, rammap + 2); *snr = nvbios_rd08(bios, rammap + 4); *ssz = nvbios_rd08(bios, rammap + 3); return rammap; default: break; } } } return 0x0000; }
u16 nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, struct nvbios_volt_entry *info) { u16 volt = nvbios_volt_entry(bios, idx, ver, len); memset(info, 0x00, sizeof(*info)); switch (!!volt * *ver) { case 0x12: case 0x20: info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; info->vid = nvbios_rd08(bios, volt + 0x01); break; case 0x30: info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; info->vid = nvbios_rd08(bios, volt + 0x01) >> 2; break; case 0x40: case 0x50: break; } return volt; }
int nvbios_memcmp(struct nvkm_bios *bios, u32 addr, const char *str, u32 len) { unsigned char c1, c2; while (len--) { c1 = nvbios_rd08(bios, addr++); c2 = *(str++); if (c1 != c2) return c1 - c2; } return 0; }
u32 nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_vmap *info) { u32 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); switch (!!vmap * *ver) { case 0x10: info->max0 = 0xff; info->max1 = 0xff; info->max2 = 0xff; break; case 0x20: info->max0 = nvbios_rd08(bios, vmap + 0x7); info->max1 = nvbios_rd08(bios, vmap + 0x8); if (*len >= 0xc) info->max2 = nvbios_rd08(bios, vmap + 0xc); else info->max2 = 0xff; break; } return vmap; }
u32 nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, struct nvbios_pmuE *info) { u32 data = nvbios_pmuEe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { default: info->type = nvbios_rd08(bios, data + 0x00); info->data = nvbios_rd32(bios, data + 0x02); break; } return data; }
u32 nvbios_rammapEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p) { u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp; memset(p, 0x00, sizeof(*p)); p->rammap_ver = *ver; p->rammap_hdr = *hdr; switch (!!data * *ver) { case 0x10: p->rammap_min = nvbios_rd16(bios, data + 0x00); p->rammap_max = nvbios_rd16(bios, data + 0x02); p->rammap_10_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; p->rammap_10_04_08 = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; break; case 0x11: p->rammap_min = nvbios_rd16(bios, data + 0x00); p->rammap_max = nvbios_rd16(bios, data + 0x02); p->rammap_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; p->rammap_11_08_0c = (nvbios_rd08(bios, data + 0x08) & 0x0c) >> 2; p->rammap_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; temp = nvbios_rd32(bios, data + 0x09); p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0; p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9; p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18; p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19; p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20; p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25; p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26; p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27; p->rammap_11_0d = nvbios_rd08(bios, data + 0x0d); p->rammap_11_0e = nvbios_rd08(bios, data + 0x0e); p->rammap_11_0f = nvbios_rd08(bios, data + 0x0f); p->rammap_11_11_0c = (nvbios_rd08(bios, data + 0x11) & 0x0c) >> 2; break; default: data = 0; break; } return data; }
u8 mxm_sor_map(struct nvkm_bios *bios, u8 conn) { struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 6) { u16 map = nvbios_rd16(bios, mxm + 4); if (map) { ver = nvbios_rd08(bios, map); if (ver == 0x10) { if (conn < nvbios_rd08(bios, map + 3)) { map += nvbios_rd08(bios, map + 1); map += conn; return nvbios_rd08(bios, map); } return 0x00; } nvkm_warn(subdev, "unknown sor map v%02x\n", ver); } } if (bios->version.chip == 0x84 || bios->version.chip == 0x86) return g84_sor_map[conn]; if (bios->version.chip == 0x92) return g92_sor_map[conn]; if (bios->version.chip == 0x94 || bios->version.chip == 0x96) return g94_sor_map[conn]; if (bios->version.chip == 0x98) return g98_sor_map[conn]; nvkm_warn(subdev, "missing sor map\n"); return 0x00; }
u16 nvbios_volt_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_P; u16 volt = 0x0000; if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) volt = nvbios_rd16(bios, bit_P.offset + 0x0c); else if (bit_P.version == 1) volt = nvbios_rd16(bios, bit_P.offset + 0x10); if (volt) { *ver = nvbios_rd08(bios, volt + 0); switch (*ver) { case 0x12: *hdr = 5; *cnt = nvbios_rd08(bios, volt + 2); *len = nvbios_rd08(bios, volt + 1); return volt; case 0x20: *hdr = nvbios_rd08(bios, volt + 1); *cnt = nvbios_rd08(bios, volt + 2); *len = nvbios_rd08(bios, volt + 3); return volt; case 0x30: case 0x40: case 0x50: *hdr = nvbios_rd08(bios, volt + 1); *cnt = nvbios_rd08(bios, volt + 3); *len = nvbios_rd08(bios, volt + 2); return volt; } } } return 0x0000; }
int nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense) { struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr, cnt, len, i; u16 table, entry; table = nvbios_iccsense_table(bios, &ver, &hdr, &cnt, &len); if (!table || !cnt) return -EINVAL; if (ver != 0x10 && ver != 0x20) { nvkm_error(subdev, "ICCSENSE version 0x%02x unknown\n", ver); return -EINVAL; } iccsense->nr_entry = cnt; iccsense->rail = kmalloc(sizeof(struct pwr_rail_t) * cnt, GFP_KERNEL); if (!iccsense->rail) return -ENOMEM; for (i = 0; i < cnt; ++i) { struct pwr_rail_t *rail = &iccsense->rail[i]; entry = table + hdr + i * len; switch(ver) { case 0x10: rail->mode = nvbios_rd08(bios, entry + 0x1); rail->extdev_id = nvbios_rd08(bios, entry + 0x2); rail->resistor_mohm = nvbios_rd08(bios, entry + 0x3); rail->rail = nvbios_rd08(bios, entry + 0x4); break; case 0x20: rail->mode = nvbios_rd08(bios, entry); rail->extdev_id = nvbios_rd08(bios, entry + 0x1); rail->resistor_mohm = nvbios_rd08(bios, entry + 0x5); rail->rail = nvbios_rd08(bios, entry + 0x6); break; }; } return 0; }
static u32 pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) { struct pll_mapping *map; u8 hdr, cnt; u32 data; data = pll_limits_table(bios, ver, &hdr, &cnt, len); if (data && *ver >= 0x30) { data += hdr; while (cnt--) { if (nvbios_rd08(bios, data + 0) == type) { *reg = nvbios_rd32(bios, data + 3); return data; } data += *len; } return 0x0000; } map = pll_map(bios); while (map && map->reg) { if (map->type == type && *ver >= 0x20) { u32 addr = (data += hdr); *reg = map->reg; while (cnt--) { if (nvbios_rd32(bios, data) == map->reg) return data; data += *len; } return addr; } else if (map->type == type) { *reg = map->reg; return data + 1; } map++; } return 0x0000; }
int nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) { struct nvkm_subdev *subdev = &bios->subdev; struct nvkm_device *device = subdev->device; u8 ver, len; u32 reg = type; u32 data; if (type > PLL_MAX) { reg = type; data = pll_map_reg(bios, reg, &type, &ver, &len); } else { data = pll_map_type(bios, type, ®, &ver, &len); } if (ver && !data) return -ENOENT; memset(info, 0, sizeof(*info)); info->type = type; info->reg = reg; switch (ver) { case 0x00: break; case 0x10: case 0x11: info->vco1.min_freq = nvbios_rd32(bios, data + 0); info->vco1.max_freq = nvbios_rd32(bios, data + 4); info->vco2.min_freq = nvbios_rd32(bios, data + 8); info->vco2.max_freq = nvbios_rd32(bios, data + 12); info->vco1.min_inputfreq = nvbios_rd32(bios, data + 16); info->vco2.min_inputfreq = nvbios_rd32(bios, data + 20); info->vco1.max_inputfreq = INT_MAX; info->vco2.max_inputfreq = INT_MAX; info->max_p = 0x7; info->max_p_usable = 0x6; /* these values taken from nv30/31/36 */ switch (bios->version.chip) { case 0x36: info->vco1.min_n = 0x5; break; default: info->vco1.min_n = 0x1; break; } info->vco1.max_n = 0xff; info->vco1.min_m = 0x1; info->vco1.max_m = 0xd; /* * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this * table version (apart from nv35)), N2 is compared to * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and * save a comparison */ info->vco2.min_n = 0x4; switch (bios->version.chip) { case 0x30: case 0x35: info->vco2.max_n = 0x1f; break; default: info->vco2.max_n = 0x28; break; } info->vco2.min_m = 0x1; info->vco2.max_m = 0x4; break; case 0x20: case 0x21: info->vco1.min_freq = nvbios_rd16(bios, data + 4) * 1000; info->vco1.max_freq = nvbios_rd16(bios, data + 6) * 1000; info->vco2.min_freq = nvbios_rd16(bios, data + 8) * 1000; info->vco2.max_freq = nvbios_rd16(bios, data + 10) * 1000; info->vco1.min_inputfreq = nvbios_rd16(bios, data + 12) * 1000; info->vco2.min_inputfreq = nvbios_rd16(bios, data + 14) * 1000; info->vco1.max_inputfreq = nvbios_rd16(bios, data + 16) * 1000; info->vco2.max_inputfreq = nvbios_rd16(bios, data + 18) * 1000; info->vco1.min_n = nvbios_rd08(bios, data + 20); info->vco1.max_n = nvbios_rd08(bios, data + 21); info->vco1.min_m = nvbios_rd08(bios, data + 22); info->vco1.max_m = nvbios_rd08(bios, data + 23); info->vco2.min_n = nvbios_rd08(bios, data + 24); info->vco2.max_n = nvbios_rd08(bios, data + 25); info->vco2.min_m = nvbios_rd08(bios, data + 26); info->vco2.max_m = nvbios_rd08(bios, data + 27); info->max_p = nvbios_rd08(bios, data + 29); info->max_p_usable = info->max_p; if (bios->version.chip < 0x60) info->max_p_usable = 0x6; info->bias_p = nvbios_rd08(bios, data + 30); if (len > 0x22) info->refclk = nvbios_rd32(bios, data + 31); break; case 0x30: data = nvbios_rd16(bios, data + 1); info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; info->vco2.min_freq = nvbios_rd16(bios, data + 4) * 1000; info->vco2.max_freq = nvbios_rd16(bios, data + 6) * 1000; info->vco1.min_inputfreq = nvbios_rd16(bios, data + 8) * 1000; info->vco2.min_inputfreq = nvbios_rd16(bios, data + 10) * 1000; info->vco1.max_inputfreq = nvbios_rd16(bios, data + 12) * 1000; info->vco2.max_inputfreq = nvbios_rd16(bios, data + 14) * 1000; info->vco1.min_n = nvbios_rd08(bios, data + 16); info->vco1.max_n = nvbios_rd08(bios, data + 17); info->vco1.min_m = nvbios_rd08(bios, data + 18); info->vco1.max_m = nvbios_rd08(bios, data + 19); info->vco2.min_n = nvbios_rd08(bios, data + 20); info->vco2.max_n = nvbios_rd08(bios, data + 21); info->vco2.min_m = nvbios_rd08(bios, data + 22); info->vco2.max_m = nvbios_rd08(bios, data + 23); info->max_p_usable = info->max_p = nvbios_rd08(bios, data + 25); info->bias_p = nvbios_rd08(bios, data + 27); info->refclk = nvbios_rd32(bios, data + 28); break; case 0x40: info->refclk = nvbios_rd16(bios, data + 9) * 1000; data = nvbios_rd16(bios, data + 1); info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; info->vco1.min_inputfreq = nvbios_rd16(bios, data + 4) * 1000; info->vco1.max_inputfreq = nvbios_rd16(bios, data + 6) * 1000; info->vco1.min_m = nvbios_rd08(bios, data + 8); info->vco1.max_m = nvbios_rd08(bios, data + 9); info->vco1.min_n = nvbios_rd08(bios, data + 10); info->vco1.max_n = nvbios_rd08(bios, data + 11); info->min_p = nvbios_rd08(bios, data + 12); info->max_p = nvbios_rd08(bios, data + 13); break; default: nvkm_error(subdev, "unknown pll limits version 0x%02x\n", ver); return -EINVAL; } if (!info->refclk) { info->refclk = device->crystal; if (bios->version.chip == 0x51) { u32 sel_clk = nvkm_rd32(device, 0x680524); if ((info->reg == 0x680508 && sel_clk & 0x20) || (info->reg == 0x680520 && sel_clk & 0x80)) { if (nvkm_rdvgac(device, 0, 0x27) < 0xa3) info->refclk = 200000; else info->refclk = 25000; } } } /* * By now any valid limit table ought to have set a max frequency for * vco1, so if it's zero it's either a pre limit table bios, or one * with an empty limit table (seen on nv18) */ if (!info->vco1.max_freq) { info->vco1.max_freq = nvbios_rd32(bios, bios->bmp_offset + 67); info->vco1.min_freq = nvbios_rd32(bios, bios->bmp_offset + 71); if (bmp_version(bios) < 0x0506) { info->vco1.max_freq = 256000; info->vco1.min_freq = 128000; } info->vco1.min_inputfreq = 0; info->vco1.max_inputfreq = INT_MAX; info->vco1.min_n = 0x1; info->vco1.max_n = 0xff; info->vco1.min_m = 0x1; if (device->crystal == 13500) { /* nv05 does this, nv11 doesn't, nv10 unknown */ if (bios->version.chip < 0x11) info->vco1.min_m = 0x7; info->vco1.max_m = 0xd; } else { if (bios->version.chip < 0x11) info->vco1.min_m = 0x8; info->vco1.max_m = 0xe; } if (bios->version.chip < 0x17 || bios->version.chip == 0x1a || bios->version.chip == 0x20) info->max_p = 4; else info->max_p = 5; info->max_p_usable = info->max_p; } return 0; }
u32 nvbios_rammapSp(struct nvkm_bios *bios, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr, struct nvbios_ramcfg *p) { data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr); p->ramcfg_ver = *ver; p->ramcfg_hdr = *hdr; switch (!!data * *ver) { case 0x10: p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); p->ramcfg_10_02_01 = (nvbios_rd08(bios, data + 0x02) & 0x01) >> 0; p->ramcfg_10_02_02 = (nvbios_rd08(bios, data + 0x02) & 0x02) >> 1; p->ramcfg_10_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; p->ramcfg_10_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; p->ramcfg_10_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; p->ramcfg_10_02_20 = (nvbios_rd08(bios, data + 0x02) & 0x20) >> 5; p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_10_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; p->ramcfg_10_04_01 = (nvbios_rd08(bios, data + 0x04) & 0x01) >> 0; p->ramcfg_FBVDDQ = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; p->ramcfg_10_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; p->ramcfg_10_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; p->ramcfg_10_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; p->ramcfg_10_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; p->ramcfg_10_09_0f = (nvbios_rd08(bios, data + 0x09) & 0x0f) >> 0; p->ramcfg_10_09_f0 = (nvbios_rd08(bios, data + 0x09) & 0xf0) >> 4; break; case 0x11: p->ramcfg_timing = nvbios_rd08(bios, data + 0x00); p->ramcfg_11_01_01 = (nvbios_rd08(bios, data + 0x01) & 0x01) >> 0; p->ramcfg_11_01_02 = (nvbios_rd08(bios, data + 0x01) & 0x02) >> 1; p->ramcfg_11_01_04 = (nvbios_rd08(bios, data + 0x01) & 0x04) >> 2; p->ramcfg_11_01_08 = (nvbios_rd08(bios, data + 0x01) & 0x08) >> 3; p->ramcfg_11_01_10 = (nvbios_rd08(bios, data + 0x01) & 0x10) >> 4; p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x01) & 0x20) >> 5; p->ramcfg_11_01_40 = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6; p->ramcfg_11_01_80 = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7; p->ramcfg_11_02_03 = (nvbios_rd08(bios, data + 0x02) & 0x03) >> 0; p->ramcfg_11_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; p->ramcfg_11_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; p->ramcfg_11_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; p->ramcfg_11_02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_11_02_80 = (nvbios_rd08(bios, data + 0x02) & 0x80) >> 7; p->ramcfg_11_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; p->ramcfg_11_03_30 = (nvbios_rd08(bios, data + 0x03) & 0x30) >> 4; p->ramcfg_11_03_c0 = (nvbios_rd08(bios, data + 0x03) & 0xc0) >> 6; p->ramcfg_11_03_f0 = (nvbios_rd08(bios, data + 0x03) & 0xf0) >> 4; p->ramcfg_11_04 = (nvbios_rd08(bios, data + 0x04) & 0xff) >> 0; p->ramcfg_11_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; p->ramcfg_11_07_02 = (nvbios_rd08(bios, data + 0x07) & 0x02) >> 1; p->ramcfg_11_07_04 = (nvbios_rd08(bios, data + 0x07) & 0x04) >> 2; p->ramcfg_11_07_08 = (nvbios_rd08(bios, data + 0x07) & 0x08) >> 3; p->ramcfg_11_07_10 = (nvbios_rd08(bios, data + 0x07) & 0x10) >> 4; p->ramcfg_11_07_40 = (nvbios_rd08(bios, data + 0x07) & 0x40) >> 6; p->ramcfg_11_07_80 = (nvbios_rd08(bios, data + 0x07) & 0x80) >> 7; p->ramcfg_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; p->ramcfg_11_08_02 = (nvbios_rd08(bios, data + 0x08) & 0x02) >> 1; p->ramcfg_11_08_04 = (nvbios_rd08(bios, data + 0x08) & 0x04) >> 2; p->ramcfg_11_08_08 = (nvbios_rd08(bios, data + 0x08) & 0x08) >> 3; p->ramcfg_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; p->ramcfg_11_08_20 = (nvbios_rd08(bios, data + 0x08) & 0x20) >> 5; p->ramcfg_11_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; break; default: data = 0; break; } return data; }
u32 nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, struct nvbios_ramcfg *p) { data += (idx * size); if (size < 11) return 0x00000000; p->ramcfg_ver = 0; p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); p->ramcfg_00_03_01 = (nvbios_rd08(bios, data + 0x03) & 0x01) >> 0; p->ramcfg_00_03_02 = (nvbios_rd08(bios, data + 0x03) & 0x02) >> 1; p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x03) & 0x04) >> 2; p->ramcfg_00_03_08 = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; p->ramcfg_RON = (nvbios_rd08(bios, data + 0x03) & 0x10) >> 3; p->ramcfg_FBVDDQ = (nvbios_rd08(bios, data + 0x03) & 0x80) >> 7; p->ramcfg_00_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; p->ramcfg_00_04_04 = (nvbios_rd08(bios, data + 0x04) & 0x04) >> 2; p->ramcfg_00_04_20 = (nvbios_rd08(bios, data + 0x04) & 0x20) >> 5; p->ramcfg_00_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; p->ramcfg_00_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; p->ramcfg_00_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; p->ramcfg_00_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; p->ramcfg_00_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; p->ramcfg_00_0a_0f = (nvbios_rd08(bios, data + 0x0a) & 0x0f) >> 0; p->ramcfg_00_0a_f0 = (nvbios_rd08(bios, data + 0x0a) & 0xf0) >> 4; return data; }