bool nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info) { struct nvbios_pmuE pmuE; u8 ver, hdr, idx = 0; u32 data; memset(info, 0x00, sizeof(*info)); while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) { if ( pmuE.type == type && (data = weirdo_pointer(bios, pmuE.data))) { info->init_addr_pmu = nvbios_rd32(bios, data + 0x08); info->args_addr_pmu = nvbios_rd32(bios, data + 0x0c); info->boot_addr = data + 0x30; info->boot_addr_pmu = nvbios_rd32(bios, data + 0x10) + nvbios_rd32(bios, data + 0x18); info->boot_size = nvbios_rd32(bios, data + 0x1c) - nvbios_rd32(bios, data + 0x18); info->code_addr = info->boot_addr + info->boot_size; info->code_addr_pmu = info->boot_addr_pmu + info->boot_size; info->code_size = nvbios_rd32(bios, data + 0x20); info->data_addr = data + 0x30 + nvbios_rd32(bios, data + 0x24); info->data_addr_pmu = nvbios_rd32(bios, data + 0x28); info->data_size = nvbios_rd32(bios, data + 0x2c); return true; } } return false; }
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; }
void gf119_gpio_reset(struct nvkm_gpio *gpio, u8 match) { struct nvkm_device *device = gpio->subdev.device; struct nvkm_bios *bios = device->bios; u8 ver, len; u16 entry; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { u32 data = nvbios_rd32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); u8 func = (data & 0x0000ff00) >> 8; u8 unk0 = (data & 0x00ff0000) >> 16; u8 unk1 = (data & 0x1f000000) >> 24; if ( func == DCB_GPIO_UNUSED || (match != DCB_GPIO_UNUSED && match != func)) continue; nvkm_gpio_set(gpio, 0, func, line, defs); nvkm_mask(device, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line); } }
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; }
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; }
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 u32 nvbios_iccsense_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_P; u32 iccsense; if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 || bit_P.length < 0x2c) return 0; iccsense = nvbios_rd32(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; }
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; }
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_P0260Xp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, struct nvbios_P0260X *info) { u32 data = nvbios_P0260Xe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: info->data = nvbios_rd32(bios, data); return data; default: break; } 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; }
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_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; }
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; }
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; }
u16 nvbios_perfEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *info) { u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); info->pstate = nvbios_rd08(bios, perf + 0x00); switch (!!perf * *ver) { case 0x12: case 0x13: case 0x14: info->core = nvbios_rd32(bios, perf + 0x01) * 10; info->memory = nvbios_rd32(bios, perf + 0x05) * 20; info->fanspeed = nvbios_rd08(bios, perf + 0x37); if (*hdr > 0x38) info->voltage = nvbios_rd08(bios, perf + 0x38); break; case 0x21: case 0x23: case 0x24: info->fanspeed = nvbios_rd08(bios, perf + 0x04); info->voltage = nvbios_rd08(bios, perf + 0x05); info->shader = nvbios_rd16(bios, perf + 0x06) * 1000; info->core = info->shader + (signed char) nvbios_rd08(bios, perf + 0x08) * 1000; switch (bios->subdev.device->chipset) { case 0x49: case 0x4b: info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000; break; default: info->memory = nvbios_rd16(bios, perf + 0x0b) * 2000; break; } break; case 0x25: info->fanspeed = nvbios_rd08(bios, perf + 0x04); info->voltage = nvbios_rd08(bios, perf + 0x05); info->core = nvbios_rd16(bios, perf + 0x06) * 1000; info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; break; case 0x30: info->script = nvbios_rd16(bios, perf + 0x02); case 0x35: info->fanspeed = nvbios_rd08(bios, perf + 0x06); info->voltage = nvbios_rd08(bios, perf + 0x07); info->core = nvbios_rd16(bios, perf + 0x08) * 1000; info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; info->vdec = nvbios_rd16(bios, perf + 0x10) * 1000; info->disp = nvbios_rd16(bios, perf + 0x14) * 1000; break; case 0x40: info->voltage = nvbios_rd08(bios, perf + 0x02); break; default: return 0x0000; } return perf; }