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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
f9aafdd30e
commit
855a95e4fc
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 *,
|
||||
|
@ -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, ®p->pllvals);
|
||||
nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, ®p->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);
|
||||
|
@ -109,7 +109,7 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
|
||||
struct nouveau_pll_vals *pv = ®p->pllvals;
|
||||
struct pll_lims pll_lim;
|
||||
|
||||
if (get_pll_limits(dev, nv_crtc->index ? VPLL2 : VPLL1, &pll_lim))
|
||||
if (get_pll_limits(dev, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, &pll_lim))
|
||||
return;
|
||||
|
||||
/* NM2 == 0 is used to determine single stage mode on two stage plls */
|
||||
|
Loading…
Reference in New Issue
Block a user