Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
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;
}
Beispiel #4
0
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;
}
Beispiel #5
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;
}
Beispiel #6
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);
}
Beispiel #7
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;
}
Beispiel #9
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));
	}
}