int nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N, fN, M, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) return ret; ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_wr32(priv, info.reg + 0, 0x50000610); nv_mask(priv, info.reg + 4, 0x003fffff, (P << 16) | (M << 8) | N); nv_wr32(priv, info.reg + 8, fN); break; default: nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } return ret; }
static int nv40_ram_calc(struct nvkm_ram *base, u32 freq) { struct nv40_ram *ram = nv40_ram(base); struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll pll; int N1, M1, N2, M2; int log2P, ret; ret = nvbios_pll_parse(bios, 0x04, &pll); if (ret) { nvkm_error(subdev, "mclk pll data not found\n"); return ret; } ret = nv04_pll_calc(subdev, &pll, freq, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; ram->ctrl = 0x80000000 | (log2P << 16); ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20; if (N2 == M2) { ram->ctrl |= 0x00000100; ram->coef = (N1 << 8) | M1; } else { ram->ctrl |= 0x40000000; ram->coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; } return 0; }
static int nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) { struct nvc0_clock_priv *priv = (void *)clk; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N, fN, M, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) return ret; ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); nv_wr32(priv, info.reg + 0x10, fN << 16); break; default: nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } return ret; }
int nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { struct nvkm_subdev *subdev = &init->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) { nvkm_error(subdev, "failed to retrieve pll data, %d\n", ret); return ret; } ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { nvkm_error(subdev, "failed pll calculation\n"); return ret; } switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nvkm_wr32(device, info.reg + 0, 0x10000611); nvkm_mask(device, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); nvkm_mask(device, info.reg + 8, 0x7fff00ff, (P << 28) | (M2 << 16) | N2); break; case PLL_MEMORY: nvkm_mask(device, info.reg + 0, 0x01ff0000, (P << 22) | (info.bias_p << 19) | (P << 16)); nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; default: nvkm_mask(device, info.reg + 0, 0x00070000, (P << 16)); nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; } return 0; }
static int calc_pll(struct drm_device *dev, u32 id, int khz, struct nv04_pm_clock *clk) { struct nouveau_device *device = nouveau_dev(dev); struct nouveau_bios *bios = nouveau_bios(device); struct nouveau_clock *pclk = nouveau_clock(device); int ret; ret = nvbios_pll_parse(bios, id, &clk->pll); if (ret) return ret; ret = pclk->pll_calc(pclk, &clk->pll, khz, &clk->calc); if (!ret) return -EINVAL; return 0; }
int nv04_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) { struct nv04_clock_priv *priv = (void *)clk; struct nouveau_pll_vals pv; struct nvbios_pll info; int ret; ret = nvbios_pll_parse(nouveau_bios(priv), type > 0x405c ? type : type - 4, &info); if (ret) return ret; ret = clk->pll_calc(clk, &info, freq, &pv); if (!ret) return ret; return clk->pll_prog(clk, type, &pv); }
static int nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) { nv_error(devinit, "failed to retrieve pll data, %d\n", ret); return ret; } ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { nv_error(devinit, "failed pll calculation\n"); return ret; } switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_wr32(priv, info.reg + 0, 0x10000611); nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) | (M2 << 16) | N2); break; case PLL_MEMORY: nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) | (info.bias_p << 19) | (P << 16)); nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); break; default: nv_mask(priv, info.reg + 0, 0x00070000, (P << 16)); nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); break; } return 0; }
int nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nouveau_bios *bios = nouveau_bios(devinit); struct nouveau_pll_vals pv; struct nvbios_pll info; int cv = bios->version.chip; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info); if (ret) return ret; ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) return -EINVAL; pv.refclk = info.refclk; pv.N1 = N1; pv.M1 = M1; pv.N2 = N2; pv.M2 = M2; pv.log2P = P; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { if (type > 0x405c) setPLL_double_highregs(devinit, type, &pv); else setPLL_double_lowregs(devinit, type, &pv); } else setPLL_single(devinit, type, &pv); return 0; }
static void setPLL_double_lowregs(struct nv04_clock_priv *priv, 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(priv, 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(priv, 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(priv), 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(priv, 0x4600); nv_wr32(priv, 0x4600, saved4600 | 8 << 28); } if (single_stage) Pval |= mpll ? 1 << 12 : 1 << 8; nv_wr32(priv, Preg, oldPval | 1 << 28); nv_wr32(priv, Preg, Pval & ~(4 << 28)); if (mpll) { Pval |= 8 << 20; nv_wr32(priv, 0x4020, Pval & ~(0xc << 28)); nv_wr32(priv, 0x4038, Pval & ~(0xc << 28)); } savedc040 = nv_rd32(priv, 0xc040); nv_wr32(priv, 0xc040, savedc040 & maskc040); nv_wr32(priv, NMNMreg, NMNM); if (NMNMreg == 0x4024) nv_wr32(priv, 0x403c, NMNM); nv_wr32(priv, Preg, Pval); if (mpll) { Pval &= ~(8 << 20); nv_wr32(priv, 0x4020, Pval); nv_wr32(priv, 0x4038, Pval); nv_wr32(priv, 0x4600, saved4600); } nv_wr32(priv, 0xc040, savedc040); if (mpll) { nv_wr32(priv, 0x4020, Pval & ~(1 << 28)); nv_wr32(priv, 0x4038, Pval & ~(1 << 28)); } }