Esempio n. 1
0
static struct nouveau_i2c_port *
nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
{
	struct nouveau_bios *bios = nouveau_bios(i2c);
	struct nouveau_i2c_port *port;

	if (index == NV_I2C_DEFAULT(0) ||
	    index == NV_I2C_DEFAULT(1)) {
		u8  ver, hdr, cnt, len;
		u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
		if (i2c && ver >= 0x30) {
			u8 auxidx = nv_ro08(bios, i2c + 4);
			if (index == NV_I2C_DEFAULT(0))
				index = (auxidx & 0x0f) >> 0;
			else
Esempio n. 2
0
File: temp.c Progetto: 24hours/linux
int
nouveau_therm_sensor_ctor(struct nouveau_therm *therm)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	struct nouveau_bios *bios = nouveau_bios(therm);

	nouveau_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback);

	nouveau_therm_temp_set_defaults(therm);
	if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
				      &priv->bios_sensor))
		nv_error(therm, "nvbios_therm_sensor_parse failed\n");
	nouveau_therm_temp_safety_checks(therm);

	return 0;
}
Esempio n. 3
0
int
nouveau_therm_fan_ctor(struct nouveau_therm *therm)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	struct nouveau_bios *bios = nouveau_bios(therm);

	nouveau_therm_fan_set_defaults(therm);
	nvbios_perf_fan_parse(bios, &priv->bios_perf_fan);
	if (nvbios_therm_fan_parse(bios, &priv->bios_fan))
		nv_error(therm, "parsing the thermal table failed\n");
	nouveau_therm_fan_safety_checks(therm);

	nouveau_therm_fan_set_mode(therm, FAN_CONTROL_NONE);

	return 0;
}
Esempio n. 4
0
int
nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
		    struct nouveau_pll_vals *pv)
{
	struct nv04_clock_priv *priv = (void *)clk;
	int cv = nouveau_bios(clk)->version.chip;

	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
	    cv >= 0x40) {
		if (reg1 > 0x405c)
			setPLL_double_highregs(priv, reg1, pv);
		else
			setPLL_double_lowregs(priv, reg1, pv);
	} else
		setPLL_single(priv, reg1, pv);

	return 0;
}
Esempio n. 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;
}
Esempio n. 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);
}
Esempio n. 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;
}
Esempio n. 8
0
int
nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
{
	struct nv50_disp_priv *priv = (void *)object->engine;
	struct nouveau_bios *bios = nouveau_bios(priv);
	const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
	const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
	const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
	const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
	const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
	struct dcb_output outp;
	u8  ver, hdr;
	u32 data;
	int ret = -EINVAL;

	if (size < sizeof(u32))
		return -EINVAL;
	data = *(u32 *)args;

	if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
		return -ENODEV;

	switch (mthd & ~0x3f) {
	case NV50_DISP_SOR_PWR:
		ret = priv->sor.power(priv, or, data);
		break;
	case NVA3_DISP_SOR_HDA_ELD:
		ret = priv->sor.hda_eld(priv, or, args, size);
		break;
	case NV84_DISP_SOR_HDMI_PWR:
		ret = priv->sor.hdmi(priv, head, or, data);
		break;
	case NV50_DISP_SOR_LVDS_SCRIPT:
		priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
		ret = 0;
		break;
	default:
		BUG_ON(1);
	}

	return ret;
}
Esempio n. 9
0
static int
nouveau_volt_map(struct nouveau_volt *volt, u8 id)
{
	struct nouveau_bios *bios = nouveau_bios(volt);
	struct nvbios_vmap_entry info;
	u8  ver, len;
	u16 vmap;

	vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
	if (vmap) {
		if (info.link != 0xff) {
			int ret = nouveau_volt_map(volt, info.link);
			if (ret < 0)
				return ret;
			info.min += ret;
		}
		return info.min;
	}

	return id ? id * 10000 : -ENODEV;
}
Esempio n. 10
0
void
setPLL_single(struct nouveau_devinit *devinit, u32 reg,
	      struct nouveau_pll_vals *pv)
{
	int chip_version = nouveau_bios(devinit)->version.chip;
	uint32_t oldpll = nv_rd32(devinit, reg);
	int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
	uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
	uint32_t saved_powerctrl_1 = 0;
	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);

	if (oldpll == pll)
		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 (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
		/* upclock -- write new post divider first */
		nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
	else
		/* downclock -- write new NM first */
		nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);

	if ((chip_version < 0x17 || chip_version == 0x1a) &&
	    chip_version != 0x11)
		/* wait a bit on older chips */
		msleep(64);
	nv_rd32(devinit, reg);

	/* then write the other half as well */
	nv_wr32(devinit, reg, pll);

	if (shift_powerctrl_1 >= 0)
		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
}
Esempio n. 11
0
static u16
exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
	    struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
	    struct nvbios_outp *info)
{
	struct nouveau_bios *bios = nouveau_bios(priv);
	u16 mask, type, data;

	if (outp < 4) {
		type = DCB_OUTPUT_ANALOG;
		mask = 0;
	} else {
		outp -= 4;
		switch (ctrl & 0x00000f00) {
		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
		default:
			nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
			return 0x0000;
		}
		dcb->sorconf.link = mask;
	}

	mask  = 0x00c0 & (mask << 6);
	mask |= 0x0001 << outp;
	mask |= 0x0100 << head;

	data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
	if (!data)
		return 0x0000;

	return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
}
Esempio n. 12
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;
}
Esempio n. 13
0
static int
nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
{
	struct nouveau_clock *clk = nouveau_clock(pfb);
	struct nouveau_bios *bios = nouveau_bios(pfb);
	struct nvc0_ram *ram = (void *)pfb->ram;
	struct nvc0_ramfuc *fuc = &ram->fuc;
	u8  ver, cnt, len, strap;
	struct {
		u32 data;
		u8  size;
	} rammap, ramcfg, timing;
	int ref, div, out;
	int from, mode;
	int N1, M1, P;
	int ret;

	/* lookup memory config data relevant to the target frequency */
	rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
				     &cnt, &ramcfg.size);
	if (!rammap.data || ver != 0x10 || rammap.size < 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;
	}

	ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
	if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
		nv_error(pfb, "invalid/missing ramcfg entry\n");
		return -EINVAL;
	}

	/* lookup memory timings, if bios says they're present */
	strap = nv_ro08(bios, ramcfg.data + 0x01);
	if (strap != 0xff) {
		timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
					     &cnt, &len);
		if (!timing.data || ver != 0x10 || timing.size < 0x19) {
			nv_error(pfb, "invalid/missing timing entry\n");
			return -EINVAL;
		}
	} else {
		timing.data = 0;
	}

	ret = ram_init(fuc, pfb);
	if (ret)
		return ret;

	/* determine current mclk configuration */
	from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */

	/* determine target mclk configuration */
	if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
		ref = clk->read(clk, nv_clk_src_sppll0);
	else
		ref = clk->read(clk, nv_clk_src_sppll1);
	div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
	out = (ref * 2) / (div + 2);
	mode = freq != out;

	ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);

	if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
		ram_nuke(fuc, 0x132000);
		ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
		ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
	}

	if (mode == 1) {
		ram_nuke(fuc, 0x10fe20);
		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
	}

// 0x00020034 // 0x0000000a
	ram_wr32(fuc, 0x132100, 0x00000001);

	if (mode == 1 && from == 0) {
		/* calculate refpll */
		ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll,
				    ram->mempll.refclk, &N1, NULL, &M1, &P);
		if (ret <= 0) {
			nv_error(pfb, "unable to calc refpll\n");
			return ret ? ret : -ERANGE;
		}

		ram_wr32(fuc, 0x10fe20, 0x20010000);
		ram_wr32(fuc, 0x137320, 0x00000003);
		ram_wr32(fuc, 0x137330, 0x81200006);
		ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
		ram_wr32(fuc, 0x10fe20, 0x20010001);
		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);

		/* calculate mempll */
		ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
				   &N1, NULL, &M1, &P);
		if (ret <= 0) {
			nv_error(pfb, "unable to calc refpll\n");
			return ret ? ret : -ERANGE;
		}

		ram_wr32(fuc, 0x10fe20, 0x20010005);
		ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
		ram_wr32(fuc, 0x132000, 0x18010101);
		ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
	} else
	if (mode == 0) {
		ram_wr32(fuc, 0x137300, 0x00000003);
	}

	if (from == 0) {
		ram_nuke(fuc, 0x10fb04);
		ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
		ram_nuke(fuc, 0x10fb08);
		ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
		ram_wr32(fuc, 0x10f988, 0x2004ff00);
		ram_wr32(fuc, 0x10f98c, 0x003fc040);
		ram_wr32(fuc, 0x10f990, 0x20012001);
		ram_wr32(fuc, 0x10f998, 0x00011a00);
		ram_wr32(fuc, 0x13d8f4, 0x00000000);
	} else {
		ram_wr32(fuc, 0x10f988, 0x20010000);
		ram_wr32(fuc, 0x10f98c, 0x00000000);
		ram_wr32(fuc, 0x10f990, 0x20012001);
		ram_wr32(fuc, 0x10f998, 0x00010a00);
	}

	if (from == 0) {
// 0x00020039 // 0x000000ba
	}

// 0x0002003a // 0x00000002
	ram_wr32(fuc, 0x100b0c, 0x00080012);
// 0x00030014 // 0x00000000 // 0x02b5f070
// 0x00030014 // 0x00010000 // 0x02b5f070
	ram_wr32(fuc, 0x611200, 0x00003300);
// 0x00020034 // 0x0000000a
// 0x00030020 // 0x00000001 // 0x00000000

	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
	ram_wr32(fuc, 0x10f210, 0x00000000);
	ram_nsec(fuc, 1000);
	if (mode == 0)
		nvc0_ram_train(fuc, 0x000c1001);
	ram_wr32(fuc, 0x10f310, 0x00000001);
	ram_nsec(fuc, 1000);
	ram_wr32(fuc, 0x10f090, 0x00000061);
	ram_wr32(fuc, 0x10f090, 0xc000007f);
	ram_nsec(fuc, 1000);

	if (from == 0) {
		ram_wr32(fuc, 0x10f824, 0x00007fd4);
	} else {
		ram_wr32(fuc, 0x1373ec, 0x00020404);
	}

	if (mode == 0) {
		ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
		ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
		ram_wr32(fuc, 0x10f830, 0x41500010);
		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
		ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
		ram_wr32(fuc, 0x10f050, 0xff000090);
		ram_wr32(fuc, 0x1373ec, 0x00020f0f);
		ram_wr32(fuc, 0x1373f0, 0x00000003);
		ram_wr32(fuc, 0x137310, 0x81201616);
		ram_wr32(fuc, 0x132100, 0x00000001);
// 0x00020039 // 0x000000ba
		ram_wr32(fuc, 0x10f830, 0x00300017);
		ram_wr32(fuc, 0x1373f0, 0x00000001);
		ram_wr32(fuc, 0x10f824, 0x00007e77);
		ram_wr32(fuc, 0x132000, 0x18030001);
		ram_wr32(fuc, 0x10f090, 0x4000007e);
		ram_nsec(fuc, 2000);
		ram_wr32(fuc, 0x10f314, 0x00000001);
		ram_wr32(fuc, 0x10f210, 0x80000000);
		ram_wr32(fuc, 0x10f338, 0x00300220);
		ram_wr32(fuc, 0x10f300, 0x0000011d);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f290, 0x02060505);
		ram_wr32(fuc, 0x10f294, 0x34208288);
		ram_wr32(fuc, 0x10f298, 0x44050411);
		ram_wr32(fuc, 0x10f29c, 0x0000114c);
		ram_wr32(fuc, 0x10f2a0, 0x42e10069);
		ram_wr32(fuc, 0x10f614, 0x40044f77);
		ram_wr32(fuc, 0x10f610, 0x40044f77);
		ram_wr32(fuc, 0x10f344, 0x00600009);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f348, 0x00700008);
		ram_wr32(fuc, 0x61c140, 0x19240000);
		ram_wr32(fuc, 0x10f830, 0x00300017);
		nvc0_ram_train(fuc, 0x80021001);
		nvc0_ram_train(fuc, 0x80081001);
		ram_wr32(fuc, 0x10f340, 0x00500004);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f830, 0x01300017);
		ram_wr32(fuc, 0x10f830, 0x00300017);
// 0x00030020 // 0x00000000 // 0x00000000
// 0x00020034 // 0x0000000b
		ram_wr32(fuc, 0x100b0c, 0x00080028);
		ram_wr32(fuc, 0x611200, 0x00003330);
	} else {
		ram_wr32(fuc, 0x10f800, 0x00001800);
		ram_wr32(fuc, 0x13d8f4, 0x00000000);
		ram_wr32(fuc, 0x1373ec, 0x00020404);
		ram_wr32(fuc, 0x1373f0, 0x00000003);
		ram_wr32(fuc, 0x10f830, 0x40700010);
		ram_wr32(fuc, 0x10f830, 0x40500010);
		ram_wr32(fuc, 0x13d8f4, 0x00000000);
		ram_wr32(fuc, 0x1373f8, 0x00000000);
		ram_wr32(fuc, 0x132100, 0x00000101);
		ram_wr32(fuc, 0x137310, 0x89201616);
		ram_wr32(fuc, 0x10f050, 0xff000090);
		ram_wr32(fuc, 0x1373ec, 0x00030404);
		ram_wr32(fuc, 0x1373f0, 0x00000002);
	// 0x00020039 // 0x00000011
		ram_wr32(fuc, 0x132100, 0x00000001);
		ram_wr32(fuc, 0x1373f8, 0x00002000);
		ram_nsec(fuc, 2000);
		ram_wr32(fuc, 0x10f808, 0x7aaa0050);
		ram_wr32(fuc, 0x10f830, 0x00500010);
		ram_wr32(fuc, 0x10f200, 0x00ce1000);
		ram_wr32(fuc, 0x10f090, 0x4000007e);
		ram_nsec(fuc, 2000);
		ram_wr32(fuc, 0x10f314, 0x00000001);
		ram_wr32(fuc, 0x10f210, 0x80000000);
		ram_wr32(fuc, 0x10f338, 0x00300200);
		ram_wr32(fuc, 0x10f300, 0x0000084d);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f290, 0x0b343825);
		ram_wr32(fuc, 0x10f294, 0x3483028e);
		ram_wr32(fuc, 0x10f298, 0x440c0600);
		ram_wr32(fuc, 0x10f29c, 0x0000214c);
		ram_wr32(fuc, 0x10f2a0, 0x42e20069);
		ram_wr32(fuc, 0x10f200, 0x00ce0000);
		ram_wr32(fuc, 0x10f614, 0x60044e77);
		ram_wr32(fuc, 0x10f610, 0x60044e77);
		ram_wr32(fuc, 0x10f340, 0x00500000);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f344, 0x00600228);
		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f348, 0x00700000);
		ram_wr32(fuc, 0x13d8f4, 0x00000000);
		ram_wr32(fuc, 0x61c140, 0x09a40000);

		nvc0_ram_train(fuc, 0x800e1008);

		ram_nsec(fuc, 1000);
		ram_wr32(fuc, 0x10f800, 0x00001804);
	// 0x00030020 // 0x00000000 // 0x00000000
	// 0x00020034 // 0x0000000b
		ram_wr32(fuc, 0x13d8f4, 0x00000000);
		ram_wr32(fuc, 0x100b0c, 0x00080028);
		ram_wr32(fuc, 0x611200, 0x00003330);
		ram_nsec(fuc, 100000);
		ram_wr32(fuc, 0x10f9b0, 0x05313f41);
		ram_wr32(fuc, 0x10f9b4, 0x00002f50);

		nvc0_ram_train(fuc, 0x010c1001);
	}

	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
// 0x00020016 // 0x00000000

	if (mode == 0)
		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
	return 0;
}
Esempio n. 14
0
File: nv50.c Progetto: 24hours/linux
static bool
exec_script(struct nv50_disp_priv *priv, int head, int id)
{
	struct nouveau_bios *bios = nouveau_bios(priv);
	struct nvbios_outp info;
	struct dcb_output dcb;
	u8  ver, hdr, cnt, len;
	u16 data;
	u32 ctrl = 0x00000000;
	u32 reg;
	int i;

	/* DAC */
	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
		ctrl = nv_rd32(priv, 0x610b5c + (i * 8));

	/* SOR */
	if (!(ctrl & (1 << head))) {
		if (nv_device(priv)->chipset  < 0x90 ||
		    nv_device(priv)->chipset == 0x92 ||
		    nv_device(priv)->chipset == 0xa0) {
			reg = 0x610b74;
		} else {
			reg = 0x610798;
		}
		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
			ctrl = nv_rd32(priv, reg + (i * 8));
		i += 4;
	}

	/* PIOR */
	if (!(ctrl & (1 << head))) {
		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
			ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
		i += 8;
	}

	if (!(ctrl & (1 << head)))
		return false;
	i--;

	data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
	if (data) {
		struct nvbios_init init = {
			.subdev = nv_subdev(priv),
			.bios = bios,
			.offset = info.script[id],
			.outp = &dcb,
			.crtc = head,
			.execute = 1,
		};

		return nvbios_exec(&init) == 0;
	}

	return false;
}

static u32
exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
	    struct dcb_output *outp)
{
	struct nouveau_bios *bios = nouveau_bios(priv);
	struct nvbios_outp info1;
	struct nvbios_ocfg info2;
	u8  ver, hdr, cnt, len;
	u32 ctrl = 0x00000000;
	u32 data, conf = ~0;
	u32 reg;
	int i;

	/* DAC */
	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
		ctrl = nv_rd32(priv, 0x610b58 + (i * 8));

	/* SOR */
	if (!(ctrl & (1 << head))) {
		if (nv_device(priv)->chipset  < 0x90 ||
		    nv_device(priv)->chipset == 0x92 ||
		    nv_device(priv)->chipset == 0xa0) {
			reg = 0x610b70;
		} else {
			reg = 0x610794;
		}
		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
			ctrl = nv_rd32(priv, reg + (i * 8));
		i += 4;
	}

	/* PIOR */
	if (!(ctrl & (1 << head))) {
		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
			ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
		i += 8;
	}

	if (!(ctrl & (1 << head)))
		return conf;
	i--;

	data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
	if (!data)
		return conf;

	if (outp->location == 0) {
		switch (outp->type) {
		case DCB_OUTPUT_TMDS:
			conf = (ctrl & 0x00000f00) >> 8;
			if (pclk >= 165000)
				conf |= 0x0100;
			break;
		case DCB_OUTPUT_LVDS:
			conf = priv->sor.lvdsconf;
			break;
		case DCB_OUTPUT_DP:
			conf = (ctrl & 0x00000f00) >> 8;
			break;
		case DCB_OUTPUT_ANALOG:
		default:
			conf = 0x00ff;
			break;
		}
	} else {
		conf = (ctrl & 0x00000f00) >> 8;
		pclk = pclk / 2;
	}

	data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
	if (data && id < 0xff) {
		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
		if (data) {
			struct nvbios_init init = {
				.subdev = nv_subdev(priv),
				.bios = bios,
				.offset = data,
				.outp = outp,
				.crtc = head,
				.execute = 1,
			};

			nvbios_exec(&init);
		}
	}

	return conf;
}
Esempio n. 15
0
int
nouveau_volt_create_(struct nouveau_object *parent,
		     struct nouveau_object *engine,
		     struct nouveau_oclass *oclass, int length, void **pobject)
{
	struct nouveau_bios *bios = nouveau_bios(parent);
	struct nouveau_volt *volt;
	struct nvbios_volt_entry ivid;
	struct nvbios_volt info;
	u8  ver, hdr, cnt, len;
	u16 data;
	int ret, i;

	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
				     "voltage", length, pobject);
	volt = *pobject;
	if (ret)
		return ret;

	volt->get = nouveau_volt_get;
	volt->set = nouveau_volt_set;
	volt->set_id = nouveau_volt_set_id;

	data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
	if (data && info.vidmask && info.base && info.step) {
		for (i = 0; i < info.vidmask + 1; i++) {
			if (info.base >= info.min &&
			    info.base <= info.max) {
				volt->vid[volt->vid_nr].uv = info.base;
				volt->vid[volt->vid_nr].vid = i;
				volt->vid_nr++;
			}
			info.base += info.step;
		}
		volt->vid_mask = info.vidmask;
	} else
	if (data && info.vidmask) {
		for (i = 0; i < cnt; i++) {
			data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
						      &ivid);
			if (data) {
				volt->vid[volt->vid_nr].uv = ivid.voltage;
				volt->vid[volt->vid_nr].vid = ivid.vid;
				volt->vid_nr++;
			}
		}
		volt->vid_mask = info.vidmask;
	}

	if (volt->vid_nr) {
		for (i = 0; i < volt->vid_nr; i++) {
			nv_debug(volt, "VID %02x: %duv\n",
				 volt->vid[i].vid, volt->vid[i].uv);
		}

		/*XXX: this is an assumption.. there probably exists boards
		 * out there with i2c-connected voltage controllers too..
		 */
		ret = nouveau_voltgpio_init(volt);
		if (ret == 0) {
			volt->vid_get = nouveau_voltgpio_get;
			volt->vid_set = nouveau_voltgpio_set;
		}
	}

	return ret;
}
Esempio n. 16
0
static bool
exec_script(struct nv50_disp_priv *priv, int head, int id)
{
    struct nouveau_bios *bios = nouveau_bios(priv);
    struct nvbios_outp info;
    struct dcb_output dcb;
    u8  ver, hdr, cnt, len;
    u32 ctrl = 0x00000000;
    u16 data;
    int outp;

    for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) {
        ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20));
        if (ctrl & (1 << head))
            break;
    }

    if (outp == 8)
        return false;

    data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
    if (data) {
        struct nvbios_init init = {
            .subdev = nv_subdev(priv),
            .bios = bios,
            .offset = info.script[id],
            .outp = &dcb,
            .crtc = head,
            .execute = 1,
        };

        return nvbios_exec(&init) == 0;
    }

    return false;
}

static u32
exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
            u32 pclk, struct dcb_output *dcb)
{
    struct nouveau_bios *bios = nouveau_bios(priv);
    struct nvbios_outp info1;
    struct nvbios_ocfg info2;
    u8  ver, hdr, cnt, len;
    u32 ctrl = 0x00000000;
    u32 data, conf = ~0;
    int outp;

    for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) {
        ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20));
        if (ctrl & (1 << head))
            break;
    }

    if (outp == 8)
        return false;

    data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1);
    if (data == 0x0000)
        return conf;

    switch (dcb->type) {
    case DCB_OUTPUT_TMDS:
        conf = (ctrl & 0x00000f00) >> 8;
        if (pclk >= 165000)
            conf |= 0x0100;
        break;
    case DCB_OUTPUT_LVDS:
        conf = priv->sor.lvdsconf;
        break;
    case DCB_OUTPUT_DP:
        conf = (ctrl & 0x00000f00) >> 8;
        break;
    case DCB_OUTPUT_ANALOG:
    default:
        conf = 0x00ff;
        break;
    }

    data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
    if (data && id < 0xff) {
        data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
        if (data) {
            struct nvbios_init init = {
                .subdev = nv_subdev(priv),
                .bios = bios,
                .offset = data,
                .outp = dcb,
                .crtc = head,
                .execute = 1,
            };

            nvbios_exec(&init);
        }
    }

    return conf;
}

static void
nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
{
    exec_script(priv, head, 1);
}
Esempio n. 17
0
int
nv50_devinit_init(struct nouveau_object *object)
{
	struct nouveau_bios *bios = nouveau_bios(object);
	struct nv50_devinit_priv *priv = (void *)object;
	struct nvbios_outp info;
	struct dcb_output outp;
	u8  ver = 0xff, hdr, cnt, len;
	int ret, i = 0;

	if (!priv->base.post) {
		if (!nv_rdvgac(priv, 0, 0x00) &&
		    !nv_rdvgac(priv, 0, 0x1a)) {
			nv_info(priv, "adaptor not initialised\n");
			priv->base.post = true;
		}
	}

	ret = nouveau_devinit_init(&priv->base);
	if (ret)
		return ret;

	/* if we ran the init tables, we have to execute the first script
	 * pointer of each dcb entry's display encoder table in order
	 * to properly initialise each encoder.
	 */
	while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
		if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
				     &ver, &hdr, &cnt, &len, &info)) {
			struct nvbios_init init = {
				.subdev = nv_subdev(priv),
				.bios = bios,
				.offset = info.script[0],
				.outp = &outp,
				.crtc = -1,
				.execute = 1,
			};

			nvbios_exec(&init);
		}
		i++;
	}

	return 0;
}

static int
nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
		  struct nouveau_oclass *oclass, void *data, u32 size,
		  struct nouveau_object **pobject)
{
	struct nv50_devinit_priv *priv;
	int ret;

	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
	*pobject = nv_object(priv);
	if (ret)
		return ret;

	priv->base.pll_set = nv50_devinit_pll_set;
	return 0;
}

struct nouveau_oclass
nv50_devinit_oclass = {
	.handle = NV_SUBDEV(DEVINIT, 0x50),
	.ofuncs = &(struct nouveau_ofuncs) {
		.ctor = nv50_devinit_ctor,
		.dtor = _nouveau_devinit_dtor,
		.init = nv50_devinit_init,
		.fini = _nouveau_devinit_fini,
	},
};
Esempio n. 18
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));
	}
}
Esempio n. 19
0
static void
setPLL_double_highregs(struct nv04_clock_priv *priv, u32 reg1,
		       struct nouveau_pll_vals *pv)
{
	int chip_version = nouveau_bios(priv)->version.chip;
	bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
	uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
	uint32_t oldpll1 = nv_rd32(priv, reg1);
	uint32_t oldpll2 = !nv3035 ? nv_rd32(priv, 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(priv, 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(priv, 0x001584);
		nv_wr32(priv, 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(priv, 0xc040);
		if (shift_c040 != 14)
			nv_wr32(priv, 0xc040, savedc040 & ~(3 << shift_c040));
	}

	if (oldramdac580 != ramdac580)
		nv_wr32(priv, 0x680580, ramdac580);

	if (!nv3035)
		nv_wr32(priv, reg2, pll2);
	nv_wr32(priv, reg1, pll1);

	if (shift_powerctrl_1 >= 0)
		nv_wr32(priv, 0x001584, saved_powerctrl_1);
	if (chip_version >= 0x40)
		nv_wr32(priv, 0xc040, savedc040);
}
Esempio n. 20
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;
}