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; }
int nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, struct nouveau_pll_vals *pv) { int N1, M1, N2, M2, P; int ret = nv04_pll_calc(clock, info, clk, &N1, &M1, &N2, &M2, &P); if (ret) { pv->refclk = info->refclk; pv->N1 = N1; pv->M1 = M1; pv->N2 = N2; pv->M2 = M2; pv->log2P = P; } 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 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; }