static int nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, struct nouveau_ram_data *data) { struct nouveau_bios *bios = nouveau_bios(pfb); struct nve0_ram *ram = (void *)pfb->ram; u8 strap, cnt, len; /* lookup memory config data relevant to the target frequency */ ram->base.rammap.data = nvbios_rammapEp(bios, freq / 1000, &ram->base.rammap.version, &ram->base.rammap.size, &cnt, &len, &data->bios); if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 || ram->base.rammap.size < 0x09) { nv_error(pfb, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(pfb)); ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data, ram->base.rammap.version, ram->base.rammap.size, cnt, len, strap, &ram->base.ramcfg.version, &ram->base.ramcfg.size, &data->bios); if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 || ram->base.ramcfg.size < 0x08) { nv_error(pfb, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00); if (strap != 0xff) { ram->base.timing.data = nvbios_timingEp(bios, strap, &ram->base.timing.version, &ram->base.timing.size, &cnt, &len, &data->bios); if (!ram->base.timing.data || ram->base.timing.version != 0x20 || ram->base.timing.size < 0x33) { nv_error(pfb, "invalid/missing timing entry\n"); return -EINVAL; } } else { ram->base.timing.data = 0; } data->freq = freq; return 0; }
static int nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) { struct nouveau_bios *bios = nouveau_bios(pfb); struct nva3_ram *ram = (void *)pfb->ram; struct nva3_ramfuc *fuc = &ram->fuc; struct nva3_clock_info mclk; struct nouveau_ram_data *next; u8 ver, hdr, cnt, len, strap; u32 data; u32 r004018, r100760, ctrl; u32 unk714, unk718, unk71c; int ret, i; next = &ram->base.target; next->freq = freq; ram->base.next = next; /* lookup memory config data relevant to the target frequency */ i = 0; while ((data = nvbios_rammapEp(bios, i++, &ver, &hdr, &cnt, &len, &next->bios))) { if (freq / 1000 >= next->bios.rammap_min && freq / 1000 <= next->bios.rammap_max) break; } if (!data || ver != 0x10 || hdr < 0x0e) { nv_error(pfb, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(pfb)); if (strap >= cnt) { nv_error(pfb, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, &ver, &hdr, &next->bios); if (!data || ver != 0x10 || hdr < 0x0e) { nv_error(pfb, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ if (next->bios.ramcfg_timing != 0xff) { data = nvbios_timingEp(bios, next->bios.ramcfg_timing, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x19) { nv_error(pfb, "invalid/missing timing entry\n"); return -EINVAL; } } ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { nv_error(pfb, "failed mclk calculation\n"); return ret; } ret = ram_init(fuc, pfb); if (ret) return ret; /* XXX: where the f**k does 750MHz come from? */ if (freq <= 750000) { r004018 = 0x10000000; r100760 = 0x22222222; } else { r004018 = 0x00000000; r100760 = 0x00000000; } ctrl = ram_rd32(fuc, 0x004000); if (ctrl & 0x00000008) { if (mclk.pll) { ram_mask(fuc, 0x004128, 0x00000101, 0x00000101); ram_wr32(fuc, 0x004004, mclk.pll); ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001)); ram_wr32(fuc, 0x004000, (ctrl &= 0xffffffef)); ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000); ram_wr32(fuc, 0x004000, (ctrl |= 0x00000010)); ram_wr32(fuc, 0x004018, 0x00005000 | r004018); ram_wr32(fuc, 0x004000, (ctrl |= 0x00000004)); } } else { u32 ssel = 0x00000101; if (mclk.clk) ssel |= mclk.clk; else ssel |= 0x00080000; /* 324MHz, shouldn't matter... */ ram_mask(fuc, 0x004168, 0x003f3141, ctrl); } if (next->bios.ramcfg_10_02_10) { ram_mask(fuc, 0x111104, 0x00000600, 0x00000000); } else { ram_mask(fuc, 0x111100, 0x40000000, 0x40000000); ram_mask(fuc, 0x111104, 0x00000180, 0x00000000); } if (!next->bios.rammap_10_04_02) ram_mask(fuc, 0x100200, 0x00000800, 0x00000000); ram_wr32(fuc, 0x611200, 0x00003300); if (!next->bios.ramcfg_10_02_10) ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/ ram_wr32(fuc, 0x1002d4, 0x00000001); ram_wr32(fuc, 0x1002d0, 0x00000001); ram_wr32(fuc, 0x1002d0, 0x00000001); ram_wr32(fuc, 0x100210, 0x00000000); ram_wr32(fuc, 0x1002dc, 0x00000001); ram_nsec(fuc, 2000); ctrl = ram_rd32(fuc, 0x004000); if (!(ctrl & 0x00000008) && mclk.pll) { ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008)); ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); ram_wr32(fuc, 0x004018, 0x00001000); ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000001)); ram_wr32(fuc, 0x004004, mclk.pll); ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001)); udelay(64); ram_wr32(fuc, 0x004018, 0x00005000 | r004018); udelay(20); } else if (!mclk.pll) { ram_mask(fuc, 0x004168, 0x003f3040, mclk.clk); ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008)); ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); ram_wr32(fuc, 0x004018, 0x0000d000 | r004018); } if (next->bios.rammap_10_04_08) { ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 | next->bios.ramcfg_10_05 << 8 | next->bios.ramcfg_10_05); ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 | next->bios.ramcfg_10_07); ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 | next->bios.ramcfg_10_03_0f << 16 | next->bios.ramcfg_10_09_0f | 0x80000000); ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000); } else { ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000); ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000); ram_mask(fuc, 0x100760, 0x22222222, r100760); ram_mask(fuc, 0x1007a0, 0x22222222, r100760); ram_mask(fuc, 0x1007e0, 0x22222222, r100760); } if (mclk.pll) { ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000); ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000008)); } /*XXX: LEAVE */ ram_wr32(fuc, 0x1002dc, 0x00000000); ram_wr32(fuc, 0x1002d4, 0x00000001); ram_wr32(fuc, 0x100210, 0x80000000); ram_nsec(fuc, 1000); ram_nsec(fuc, 1000); ram_mask(fuc, mr[2], 0x00000000, 0x00000000); ram_nsec(fuc, 1000); ram_nuke(fuc, mr[0]); ram_mask(fuc, mr[0], 0x00000000, 0x00000000); ram_nsec(fuc, 1000); ram_mask(fuc, 0x100220[3], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[1], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[6], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[7], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[2], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[4], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[5], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000); ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12); unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010; unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100; unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100; if (next->bios.ramcfg_10_02_20) unk714 |= 0xf0000000; if (!next->bios.ramcfg_10_02_04) unk714 |= 0x00000010; ram_wr32(fuc, 0x100714, unk714); if (next->bios.ramcfg_10_02_01) unk71c |= 0x00000100; ram_wr32(fuc, 0x10071c, unk71c); if (next->bios.ramcfg_10_02_02) unk718 |= 0x00000100; ram_wr32(fuc, 0x100718, unk718); if (next->bios.ramcfg_10_02_10) ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/ ram_mask(fuc, mr[0], 0x100, 0x100); ram_nsec(fuc, 1000); ram_mask(fuc, mr[0], 0x100, 0x000); ram_nsec(fuc, 1000); ram_nsec(fuc, 2000); ram_nsec(fuc, 12000); ram_wr32(fuc, 0x611200, 0x00003330); if (next->bios.rammap_10_04_02) ram_mask(fuc, 0x100200, 0x00000800, 0x00000800); if (next->bios.ramcfg_10_02_10) { ram_mask(fuc, 0x111104, 0x00000180, 0x00000180); ram_mask(fuc, 0x111100, 0x40000000, 0x00000000); } else { ram_mask(fuc, 0x111104, 0x00000600, 0x00000600); } if (mclk.pll) { ram_mask(fuc, 0x004168, 0x00000001, 0x00000000); ram_mask(fuc, 0x004168, 0x00000100, 0x00000000); } else { ram_mask(fuc, 0x004000, 0x00000001, 0x00000000); ram_mask(fuc, 0x004128, 0x00000001, 0x00000000); ram_mask(fuc, 0x004128, 0x00000100, 0x00000000); } return 0; }