Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 855a95e4 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: make the behaviour of get_pll_limits() consistent



This replaces all the pll_types definitions for ones that match the types
used in the tables in recent VBIOS versions.

get_pll_limits() will now accept either type or register value as input
across all limits table versions, and will store the actual register ID
that a PLL type refers to in the returned structure.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f9aafdd3
Loading
Loading
Loading
Loading
+104 −32
Original line number Diff line number Diff line
@@ -4675,6 +4675,92 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
	return 0;
}

struct pll_mapping {
	u8  type;
	u32 reg;
};

static struct pll_mapping nv04_pll_mapping[] = {
	{ PLL_CORE  , NV_PRAMDAC_NVPLL_COEFF },
	{ PLL_MEMORY, NV_PRAMDAC_MPLL_COEFF },
	{ PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
	{ PLL_VPLL1 , NV_RAMDAC_VPLL2 },
	{}
};

static struct pll_mapping nv40_pll_mapping[] = {
	{ PLL_CORE  , 0x004000 },
	{ PLL_MEMORY, 0x004020 },
	{ PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
	{ PLL_VPLL1 , NV_RAMDAC_VPLL2 },
	{}
};

static struct pll_mapping nv50_pll_mapping[] = {
	{ PLL_CORE  , 0x004028 },
	{ PLL_SHADER, 0x004020 },
	{ PLL_UNK03 , 0x004000 },
	{ PLL_MEMORY, 0x004008 },
	{ PLL_UNK40 , 0x00e810 },
	{ PLL_UNK41 , 0x00e818 },
	{ PLL_UNK42 , 0x00e824 },
	{ PLL_VPLL0 , 0x614100 },
	{ PLL_VPLL1 , 0x614900 },
	{}
};

static struct pll_mapping nv84_pll_mapping[] = {
	{ PLL_CORE  , 0x004028 },
	{ PLL_SHADER, 0x004020 },
	{ PLL_MEMORY, 0x004008 },
	{ PLL_UNK05 , 0x004030 },
	{ PLL_UNK41 , 0x00e818 },
	{ PLL_VPLL0 , 0x614100 },
	{ PLL_VPLL1 , 0x614900 },
	{}
};

u32
get_pll_register(struct drm_device *dev, enum pll_types type)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nvbios *bios = &dev_priv->vbios;
	struct pll_mapping *map;
	int i;

	if (dev_priv->card_type < NV_40)
		map = nv04_pll_mapping;
	else
	if (dev_priv->card_type < NV_50)
		map = nv40_pll_mapping;
	else {
		u8 *plim = &bios->data[bios->pll_limit_tbl_ptr];

		if (plim[0] >= 0x40) {
			u8 *entry = plim + plim[1];
			for (i = 0; i < plim[3]; i++, entry += plim[2]) {
				if (entry[0] == type)
					return ROM32(entry[3]);
			}

			return 0;
		}

		if (dev_priv->chipset == 0x50)
			map = nv50_pll_mapping;
		else
			map = nv84_pll_mapping;
	}

	while (map->reg) {
		if (map->type == type)
			return map->reg;
		map++;
	}

	return 0;
}

int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim)
{
	/*
@@ -4750,6 +4836,14 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
	/* initialize all members to zero */
	memset(pll_lim, 0, sizeof(struct pll_lims));

	/* if we were passed a type rather than a register, figure
	 * out the register and store it
	 */
	if (limit_match > PLL_MAX)
		pll_lim->reg = limit_match;
	else
		pll_lim->reg = get_pll_register(dev, limit_match);

	if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
		uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];

@@ -4785,7 +4879,6 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		pll_lim->max_usable_log2p = 0x6;
	} else if (pll_lim_ver == 0x20 || pll_lim_ver == 0x21) {
		uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen;
		uint32_t reg = 0; /* default match */
		uint8_t *pll_rec;
		int i;

@@ -4797,29 +4890,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
			NV_WARN(dev, "Default PLL limit entry has non-zero "
				       "register field\n");

		if (limit_match > MAX_PLL_TYPES)
			/* we've been passed a reg as the match */
			reg = limit_match;
		else /* limit match is a pll type */
			for (i = 1; i < entries && !reg; i++) {
				uint32_t cmpreg = ROM32(bios->data[plloffs + recordlen * i]);

				if (limit_match == NVPLL &&
				    (cmpreg == NV_PRAMDAC_NVPLL_COEFF || cmpreg == 0x4000))
					reg = cmpreg;
				if (limit_match == MPLL &&
				    (cmpreg == NV_PRAMDAC_MPLL_COEFF || cmpreg == 0x4020))
					reg = cmpreg;
				if (limit_match == VPLL1 &&
				    (cmpreg == NV_PRAMDAC_VPLL_COEFF || cmpreg == 0x4010))
					reg = cmpreg;
				if (limit_match == VPLL2 &&
				    (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018))
					reg = cmpreg;
			}

		for (i = 1; i < entries; i++)
			if (ROM32(bios->data[plloffs + recordlen * i]) == reg) {
			if (ROM32(bios->data[plloffs + recordlen * i]) == pll_lim->reg) {
				pllindex = i;
				break;
			}
@@ -4827,7 +4899,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		pll_rec = &bios->data[plloffs + recordlen * pllindex];

		BIOSLOG(bios, "Loading PLL limits for reg 0x%08x\n",
			pllindex ? reg : 0);
			pllindex ? pll_lim->reg : 0);

		/*
		 * Frequencies are stored in tables in MHz, kHz are more
@@ -4877,8 +4949,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		if (cv == 0x51 && !pll_lim->refclk) {
			uint32_t sel_clk = bios_rd32(bios, NV_PRAMDAC_SEL_CLK);

			if (((limit_match == NV_PRAMDAC_VPLL_COEFF || limit_match == VPLL1) && sel_clk & 0x20) ||
			    ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) {
			if ((pll_lim->reg == NV_PRAMDAC_VPLL_COEFF && sel_clk & 0x20) ||
			    (pll_lim->reg == NV_RAMDAC_VPLL2 && sel_clk & 0x80)) {
				if (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_CHIP_ID_INDEX) < 0xa3)
					pll_lim->refclk = 200000;
				else
@@ -4891,10 +4963,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		int i;

		BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
			limit_match);
			pll_lim->reg);

		for (i = 0; i < entries; i++, entry += recordlen) {
			if (ROM32(entry[3]) == limit_match) {
			if (ROM32(entry[3]) == pll_lim->reg) {
				record = &bios->data[ROM16(entry[1])];
				break;
			}
@@ -4902,7 +4974,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims

		if (!record) {
			NV_ERROR(dev, "Register 0x%08x not found in PLL "
				 "limits table", limit_match);
				 "limits table", pll_lim->reg);
			return -ENOENT;
		}

@@ -4931,10 +5003,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		int i;

		BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
			limit_match);
			pll_lim->reg);

		for (i = 0; i < entries; i++, entry += recordlen) {
			if (ROM32(entry[3]) == limit_match) {
			if (ROM32(entry[3]) == pll_lim->reg) {
				record = &bios->data[ROM16(entry[1])];
				break;
			}
@@ -4942,7 +5014,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims

		if (!record) {
			NV_ERROR(dev, "Register 0x%08x not found in PLL "
				 "limits table", limit_match);
				 "limits table", pll_lim->reg);
			return -ENOENT;
		}

+18 −6
Original line number Diff line number Diff line
@@ -170,16 +170,28 @@ enum LVDS_script {
	LVDS_PANEL_OFF
};

/* changing these requires matching changes to reg tables in nv_get_clock */
#define MAX_PLL_TYPES	4
/* these match types in pll limits table version 0x40,
 * nouveau uses them on all chipsets internally where a
 * specific pll needs to be referenced, but the exact
 * register isn't known.
 */
enum pll_types {
	NVPLL,
	MPLL,
	VPLL1,
	VPLL2
	PLL_CORE   = 0x01,
	PLL_SHADER = 0x02,
	PLL_UNK03  = 0x03,
	PLL_MEMORY = 0x04,
	PLL_UNK05  = 0x05,
	PLL_UNK40  = 0x40,
	PLL_UNK41  = 0x41,
	PLL_UNK42  = 0x42,
	PLL_VPLL0  = 0x80,
	PLL_VPLL1  = 0x81,
	PLL_MAX    = 0xff
};

struct pll_lims {
	u32 reg;

	struct {
		int minfreq;
		int maxfreq;
+2 −2
Original line number Diff line number Diff line
@@ -198,8 +198,8 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nv_fifo_info fifo_data;
	struct nv_sim_state sim_data;
	int MClk = nouveau_hw_get_clock(dev, MPLL);
	int NVClk = nouveau_hw_get_clock(dev, NVPLL);
	int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY);
	int NVClk = nouveau_hw_get_clock(dev, PLL_CORE);
	uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);

	sim_data.pclk_khz = VClk;
+1 −0
Original line number Diff line number Diff line
@@ -853,6 +853,7 @@ extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *,
						      enum dcb_gpio_tag);
extern struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *, int index);
extern u32 get_pll_register(struct drm_device *, enum pll_types);
extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
			  struct pll_lims *);
extern int nouveau_bios_run_display_table(struct drm_device *,
+9 −18
Original line number Diff line number Diff line
@@ -427,22 +427,11 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum pll_types plltype,
		       struct nouveau_pll_vals *pllvals)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	const uint32_t nv04_regs[MAX_PLL_TYPES] = { NV_PRAMDAC_NVPLL_COEFF,
						    NV_PRAMDAC_MPLL_COEFF,
						    NV_PRAMDAC_VPLL_COEFF,
						    NV_RAMDAC_VPLL2 };
	const uint32_t nv40_regs[MAX_PLL_TYPES] = { 0x4000,
						    0x4020,
						    NV_PRAMDAC_VPLL_COEFF,
						    NV_RAMDAC_VPLL2 };
	uint32_t reg1, pll1, pll2 = 0;
	uint32_t reg1 = get_pll_register(dev, plltype), pll1, pll2 = 0;
	struct pll_lims pll_lim;
	int ret;

	if (dev_priv->card_type < NV_40)
		reg1 = nv04_regs[plltype];
	else
		reg1 = nv40_regs[plltype];
	BUG_ON(reg1 == 0);

	pll1 = nvReadMC(dev, reg1);

@@ -492,7 +481,8 @@ nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
{
	struct nouveau_pll_vals pllvals;

	if (plltype == MPLL && (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
	if (plltype == PLL_MEMORY &&
	    (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
		uint32_t mpllP;

		pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
@@ -501,7 +491,8 @@ nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)

		return 400000 / mpllP;
	} else
	if (plltype == MPLL && (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
	if (plltype == PLL_MEMORY &&
	    (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
		uint32_t clock;

		pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
@@ -526,9 +517,9 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
	struct nouveau_pll_vals pv;
	uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;

	if (get_pll_limits(dev, head ? VPLL2 : VPLL1, &pll_lim))
	if (get_pll_limits(dev, pllreg, &pll_lim))
		return;
	nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &pv);
	nouveau_hw_get_pllvals(dev, pllreg, &pv);

	if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
	    pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -661,7 +652,7 @@ nv_save_state_ramdac(struct drm_device *dev, int head,
	if (dev_priv->card_type >= NV_10)
		regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC);

	nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &regp->pllvals);
	nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, &regp->pllvals);
	state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT);
	if (nv_two_heads(dev))
		state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
Loading