Esempio n. 1
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. 2
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);
}