Beispiel #1
0
/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
 * it affects only the 8 bit vga io regs, which we access using mmio at
 * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
 * in general, the set value of cr44 does not matter: reg access works as
 * expected and values can be set for the appropriate head by using a 0x2000
 * offset as required
 * however:
 * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
 *    cr44 must be set to 0 or 3 for accessing values on the correct head
 *    through the common 0xc03c* addresses
 * b) in tied mode (4) head B is programmed to the values set on head A, and
 *    access using the head B addresses can have strange results, ergo we leave
 *    tied mode in init once we know to what cr44 should be restored on exit
 *
 * the owner parameter is slightly abused:
 * 0 and 1 are treated as head values and so the set value is (owner * 3)
 * other values are treated as literal values to set
 */
u8
nv_rdvgaowner(void *obj)
{
	if (nv_device(obj)->card_type < NV_50) {
		if (nv_device(obj)->chipset == 0x11) {
			u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
			if (tied == 0) {
				u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
				u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
				u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
				u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
				if (slA && !tvA) return 0x00;
				if (slB && !tvB) return 0x03;
				if (slA) return 0x00;
				if (slB) return 0x03;
				return 0x00;
			}
			return 0x04;
		}

		return nv_rdvgac(obj, 0, 0x44);
	}

	nv_error(obj, "rdvgaowner after nv4x\n");
	return 0x00;
}
Beispiel #2
0
u8
nv_rdvgai(void *obj, int head, u16 port, u8 index)
{
	if (port == 0x03c4) return nv_rdvgas(obj, head, index);
	if (port == 0x03ce) return nv_rdvgag(obj, head, index);
	if (port == 0x03d4) return nv_rdvgac(obj, head, index);
	nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
	return 0x00;
}
int
nv04_devinit_init(struct nouveau_object *object)
{
	struct nv04_devinit_priv *priv = (void *)object;

	if (!priv->base.post) {
		u32 htotal = nv_rdvgac(priv, 0, 0x06);
		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
		htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
		htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
		if (!htotal) {
			nv_info(priv, "adaptor not initialised\n");
			priv->base.post = true;
		}
	}

	return nouveau_devinit_init(&priv->base);
}
Beispiel #4
0
void
nv_wrvgaowner(void *obj, u8 select)
{
	if (nv_device(obj)->card_type < NV_50) {
		u8 owner = (select == 1) ? 3 : select;
		if (nv_device(obj)->chipset == 0x11) {
			/* workaround hw lockup bug */
			nv_rdvgac(obj, 0, 0x1f);
			nv_rdvgac(obj, 1, 0x1f);
		}

		nv_wrvgac(obj, 0, 0x44, owner);

		if (nv_device(obj)->chipset == 0x11) {
			nv_wrvgac(obj, 0, 0x2e, owner);
			nv_wrvgac(obj, 0, 0x2e, owner);
		}
	} else
		nv_error(obj, "wrvgaowner after nv4x\n");
}
Beispiel #5
0
bool
nv_lockvgac(void *obj, bool lock)
{
	bool locked = !nv_rdvgac(obj, 0, 0x1f);
	u8 data = lock ? 0x99 : 0x57;
	nv_wrvgac(obj, 0, 0x1f, data);
	if (nv_device(obj)->chipset == 0x11) {
		if (!(nv_rd32(obj, 0x001084) & 0x10000000))
			nv_wrvgac(obj, 1, 0x1f, data);
	}
	return locked;
}
Beispiel #6
0
bool
nv_lockvgac(void *obj, bool lock)
{
	struct nouveau_device *dev = nv_device(obj);

	bool locked = !nv_rdvgac(obj, 0, 0x1f);
	u8 data = lock ? 0x99 : 0x57;
	if (dev->card_type < NV_50)
		nv_wrvgac(obj, 0, 0x1f, data);
	else
		nv_wrvgac(obj, 0, 0x3f, data);
	if (dev->chipset == 0x11) {
		if (!(nv_rd32(obj, 0x001084) & 0x10000000))
			nv_wrvgac(obj, 1, 0x1f, data);
	}
	return locked;
}
Beispiel #7
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,
	},
};