static void nv05_devinit_meminit(struct nvkm_devinit *devinit) { static const u8 default_config_tab[][2] = { { 0x24, 0x00 }, { 0x28, 0x00 }, { 0x24, 0x01 }, { 0x1f, 0x00 }, { 0x0f, 0x00 }, { 0x17, 0x00 }, { 0x06, 0x00 }, { 0x00, 0x00 } }; struct nv04_devinit_priv *priv = (void *)devinit; struct nvkm_bios *bios = nvkm_bios(priv); struct io_mapping *fb; u32 patt = 0xdeadbeef; u16 data; u8 strap, ramcfg[2]; int i, v; /* Map the framebuffer aperture */ fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; } strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2; if ((data = bmp_mem_init_table(bios))) { ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); } else { ramcfg[0] = default_config_tab[strap][0]; ramcfg[1] = default_config_tab[strap][1]; } /* Sequencer off */ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) goto out; nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); /* If present load the hardcoded scrambling table */ if (data) { for (i = 0, data += 0x10; i < 8; i++, data += 4) { u32 scramble = nv_ro32(bios, data); nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble); } } /* Set memory type/width/length defaults depending on the straps */ nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); if (ramcfg[1] & 0x80) nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); nv_mask(priv, NV04_PFB_CFG1, 0, 1); /* Probe memory bus width */ for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if (fbmem_peek(fb, 0xc) != patt) nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); /* Probe memory length */ v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && (!fbmem_readback(fb, 0x1000000, ++patt) || !fbmem_readback(fb, 0, ++patt))) nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && !fbmem_readback(fb, 0x800000, ++patt)) nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); if (!fbmem_readback(fb, 0x400000, ++patt)) nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); out: /* Sequencer on */ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); fbmem_fini(fb); }
void nouveau_irq_uninstall(struct drm_device *dev) { /* Master disable */ nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); }
int nouveau_grctx_prog_load(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; const int chipset = dev_priv->chipset; const struct firmware *fw; const struct nouveau_ctxprog *cp; const struct nouveau_ctxvals *cv; char name[32]; int ret, i; if (pgraph->accel_blocked) return -ENODEV; if (!pgraph->ctxprog) { sprintf(name, "nouveau/nv%02x.ctxprog", chipset); ret = request_firmware(&fw, name, &dev->pdev->dev); if (ret) { NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset); return ret; } pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL); if (!pgraph->ctxprog) { NV_ERROR(dev, "OOM copying ctxprog\n"); release_firmware(fw); return -ENOMEM; } memcpy(pgraph->ctxprog, fw->data, fw->size); cp = pgraph->ctxprog; if (le32_to_cpu(cp->signature) != 0x5043564e || cp->version != 0 || le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) { NV_ERROR(dev, "ctxprog invalid\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -EINVAL; } release_firmware(fw); } if (!pgraph->ctxvals) { sprintf(name, "nouveau/nv%02x.ctxvals", chipset); ret = request_firmware(&fw, name, &dev->pdev->dev); if (ret) { NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset); nouveau_grctx_fini(dev); return ret; } pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL); if (!pgraph->ctxvals) { NV_ERROR(dev, "OOM copying ctxvals\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -ENOMEM; } memcpy(pgraph->ctxvals, fw->data, fw->size); cv = (void *)pgraph->ctxvals; if (le32_to_cpu(cv->signature) != 0x5643564e || cv->version != 0 || le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) { NV_ERROR(dev, "ctxvals invalid\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -EINVAL; } release_firmware(fw); } cp = pgraph->ctxprog; nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); for (i = 0; i < le16_to_cpu(cp->length); i++) nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, le32_to_cpu(cp->data[i])); return 0; }
static int nv50_disp_base_init(struct nouveau_object *object) { struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_base *base = (void *)object; int ret, i; u32 tmp; ret = nouveau_parent_init(&base->base); if (ret) return ret; /* The below segments of code copying values from one register to * another appear to inform EVO of the display capabilities or * something similar. NFI what the 0x614004 caps are for.. */ tmp = nv_rd32(priv, 0x614004); nv_wr32(priv, 0x610184, tmp); /* ... CRTC caps */ for (i = 0; i < priv->head.nr; i++) { tmp = nv_rd32(priv, 0x616100 + (i * 0x800)); nv_wr32(priv, 0x610190 + (i * 0x10), tmp); tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); nv_wr32(priv, 0x610194 + (i * 0x10), tmp); tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); nv_wr32(priv, 0x610198 + (i * 0x10), tmp); tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); nv_wr32(priv, 0x61019c + (i * 0x10), tmp); } /* ... DAC caps */ for (i = 0; i < priv->dac.nr; i++) { tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp); } /* ... SOR caps */ for (i = 0; i < priv->sor.nr; i++) { tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); } /* ... PIOR caps */ for (i = 0; i < priv->pior.nr; i++) { tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); } /* steal display away from vbios, or something like that */ if (nv_rd32(priv, 0x610024) & 0x00000100) { nv_wr32(priv, 0x610024, 0x00000100); nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { nv_error(priv, "timeout acquiring display\n"); return -EBUSY; } } /* point at display engine memory area (hash table, objects) */ nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nv_wr32(priv, 0x61002c, 0x00000370); nv_wr32(priv, 0x610028, 0x00000000); return 0; }
static int nvd0_disp_base_init(struct nouveau_object *object) { struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_base *base = (void *)object; int ret, i; u32 tmp; ret = nouveau_parent_init(&base->base); if (ret) return ret; /* The below segments of code copying values from one register to * another appear to inform EVO of the display capabilities or * something similar. */ /* ... CRTC caps */ for (i = 0; i < priv->head.nr; i++) { tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp); tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp); tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); nv_wr32(priv, 0x6101bc + (i * 0x800), tmp); } /* ... DAC caps */ for (i = 0; i < priv->dac.nr; i++) { tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp); } /* ... SOR caps */ for (i = 0; i < priv->sor.nr; i++) { tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp); } /* steal display away from vbios, or something like that */ if (nv_rd32(priv, 0x6100ac) & 0x00000100) { nv_wr32(priv, 0x6100ac, 0x00000100); nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { nv_error(priv, "timeout acquiring display\n"); return -EBUSY; } } /* point at display engine memory area (hash table, objects) */ nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nv_wr32(priv, 0x610090, 0x00000000); nv_wr32(priv, 0x6100a0, 0x00000000); nv_wr32(priv, 0x6100b0, 0x00000307); /* disable underflow reporting, preventing an intermittent issue * on some nve4 boards where the production vbios left this * setting enabled by default. * * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ for (i = 0; i < priv->head.nr; i++) nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); return 0; }
void setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg, struct nouveau_pll_vals *pv) { /* When setting PLLs, there is a merry game of disabling and enabling * various bits of hardware during the process. This function is a * synthesis of six nv4x traces, nearly each card doing a subtly * different thing. With luck all the necessary bits for each card are * combined herein. Without luck it deviates from each card's formula * so as to not work on any :) */ uint32_t Preg = NMNMreg - 4; bool mpll = Preg == 0x4020; uint32_t oldPval = nv_rd32(devinit, Preg); uint32_t NMNM = pv->NM2 << 16 | pv->NM1; uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | 0xc << 28 | pv->log2P << 16; uint32_t saved4600 = 0; /* some cards have different maskc040s */ uint32_t maskc040 = ~(3 << 14), savedc040; bool single_stage = !pv->NM2 || pv->N2 == pv->M2; if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) return; if (Preg == 0x4000) maskc040 = ~0x333; if (Preg == 0x4058) maskc040 = ~(0xc << 24); if (mpll) { struct nvbios_pll info; uint8_t Pval2; if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info)) return; Pval2 = pv->log2P + info.bias_p; if (Pval2 > info.max_p) Pval2 = info.max_p; Pval |= 1 << 28 | Pval2 << 20; saved4600 = nv_rd32(devinit, 0x4600); nv_wr32(devinit, 0x4600, saved4600 | 8 << 28); } if (single_stage) Pval |= mpll ? 1 << 12 : 1 << 8; nv_wr32(devinit, Preg, oldPval | 1 << 28); nv_wr32(devinit, Preg, Pval & ~(4 << 28)); if (mpll) { Pval |= 8 << 20; nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28)); nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28)); } savedc040 = nv_rd32(devinit, 0xc040); nv_wr32(devinit, 0xc040, savedc040 & maskc040); nv_wr32(devinit, NMNMreg, NMNM); if (NMNMreg == 0x4024) nv_wr32(devinit, 0x403c, NMNM); nv_wr32(devinit, Preg, Pval); if (mpll) { Pval &= ~(8 << 20); nv_wr32(devinit, 0x4020, Pval); nv_wr32(devinit, 0x4038, Pval); nv_wr32(devinit, 0x4600, saved4600); } nv_wr32(devinit, 0xc040, savedc040); if (mpll) { nv_wr32(devinit, 0x4020, Pval & ~(1 << 28)); nv_wr32(devinit, 0x4038, Pval & ~(1 << 28)); } }
void setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1, struct nouveau_pll_vals *pv) { int chip_version = nouveau_bios(devinit)->version.chip; bool nv3035 = chip_version == 0x30 || chip_version == 0x35; uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); uint32_t oldpll1 = nv_rd32(devinit, reg1); uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0; uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; uint32_t oldramdac580 = 0, ramdac580 = 0; bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */ uint32_t saved_powerctrl_1 = 0, savedc040 = 0; int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1); /* model specific additions to generic pll1 and pll2 set up above */ if (nv3035) { pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 | (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4; pll2 = 0; } if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ oldramdac580 = nv_rd32(devinit, 0x680580); ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); if (oldramdac580 != ramdac580) oldpll1 = ~0; /* force mismatch */ if (single_stage) /* magic value used by nvidia in single stage mode */ pll2 |= 0x011f; } if (chip_version > 0x70) /* magic bits set by the blob (but not the bios) on g71-73 */ pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28; if (oldpll1 == pll1 && oldpll2 == pll2) return; /* already set */ if (shift_powerctrl_1 >= 0) { saved_powerctrl_1 = nv_rd32(devinit, 0x001584); nv_wr32(devinit, 0x001584, (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | 1 << shift_powerctrl_1); } if (chip_version >= 0x40) { int shift_c040 = 14; switch (reg1) { case 0x680504: shift_c040 += 2; case 0x680500: shift_c040 += 2; case 0x680520: shift_c040 += 2; case 0x680508: shift_c040 += 2; } savedc040 = nv_rd32(devinit, 0xc040); if (shift_c040 != 14) nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040)); } if (oldramdac580 != ramdac580) nv_wr32(devinit, 0x680580, ramdac580); if (!nv3035) nv_wr32(devinit, reg2, pll2); nv_wr32(devinit, reg1, pll1); if (shift_powerctrl_1 >= 0) nv_wr32(devinit, 0x001584, saved_powerctrl_1); if (chip_version >= 0x40) nv_wr32(devinit, 0xc040, savedc040); }
int gm204_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr_priv *priv = (void *)object; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; int ret, i; u32 tmp; ret = nvkm_gr_init(&priv->base); if (ret) return ret; tmp = nv_rd32(priv, 0x100c80); /*XXX: mask? */ nv_wr32(priv, 0x418880, 0x00001000 | (tmp & 0x00000fff)); nv_wr32(priv, 0x418890, 0x00000000); nv_wr32(priv, 0x418894, 0x00000000); nv_wr32(priv, 0x4188b4, priv->unk4188b4->addr >> 8); nv_wr32(priv, 0x4188b8, priv->unk4188b8->addr >> 8); nv_mask(priv, 0x4188b0, 0x00040000, 0x00040000); /*XXX: belongs in fb */ nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8); nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8); nv_mask(priv, 0x100cc4, 0x00040000, 0x00040000); gf100_gr_mmio(priv, oclass->mmio); gm107_gr_init_bios(priv); nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); for (i = 0, gpc = -1; i < priv->tpc_total; i++) { do { gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } nv_wr32(priv, GPC_BCAST(0x0980), data[0]); nv_wr32(priv, GPC_BCAST(0x0984), data[1]); nv_wr32(priv, GPC_BCAST(0x0988), data[2]); nv_wr32(priv, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); } nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); nv_wr32(priv, GPC_BCAST(0x033c), nv_rd32(priv, 0x100804)); nv_wr32(priv, 0x400500, 0x00010001); nv_wr32(priv, 0x400100, 0xffffffff); nv_wr32(priv, 0x40013c, 0xffffffff); nv_wr32(priv, 0x400124, 0x00000002); nv_wr32(priv, 0x409c24, 0x000e0000); nv_wr32(priv, 0x405848, 0xc0000000); nv_wr32(priv, 0x40584c, 0x00000001); nv_wr32(priv, 0x404000, 0xc0000000); nv_wr32(priv, 0x404600, 0xc0000000); nv_wr32(priv, 0x408030, 0xc0000000); nv_wr32(priv, 0x404490, 0xc0000000); nv_wr32(priv, 0x406018, 0xc0000000); nv_wr32(priv, 0x407020, 0x40000000); nv_wr32(priv, 0x405840, 0xc0000000); nv_wr32(priv, 0x405844, 0x00ffffff); nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } for (rop = 0; rop < priv->rop_nr; rop++) { nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); } nv_wr32(priv, 0x400108, 0xffffffff); nv_wr32(priv, 0x400138, 0xffffffff); nv_wr32(priv, 0x400118, 0xffffffff); nv_wr32(priv, 0x400130, 0xffffffff); nv_wr32(priv, 0x40011c, 0xffffffff); nv_wr32(priv, 0x400134, 0xffffffff); nv_wr32(priv, 0x400054, 0x2c350f63); gf100_gr_zbc_init(priv); return gm204_gr_init_ctxctl(priv); }