Commit 88524bc0 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/devinit: move simple pll setting routines to devinit

These are pretty much useless for reclocking purposes.  Lets make it
clearer what they're for and move them to DEVINIT to signify they're
for the very simple PLL setting requirements of running the init
tables.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7ada785f
......@@ -60,6 +60,8 @@ nouveau-y += core/subdev/devinit/nv10.o
nouveau-y += core/subdev/devinit/nv1a.o
nouveau-y += core/subdev/devinit/nv20.o
nouveau-y += core/subdev/devinit/nv50.o
nouveau-y += core/subdev/devinit/nva3.o
nouveau-y += core/subdev/devinit/nvc0.o
nouveau-y += core/subdev/fb/base.o
nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o
......
......@@ -319,7 +319,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -346,7 +346,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -372,7 +372,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -398,7 +398,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......
......@@ -62,7 +62,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -91,7 +91,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -120,7 +120,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -148,7 +148,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -177,7 +177,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -206,7 +206,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -234,7 +234,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -263,7 +263,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......
......@@ -62,7 +62,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -92,7 +92,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -122,7 +122,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -152,7 +152,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......
......@@ -34,9 +34,9 @@
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
#include <subdev/devinit.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/clock.h>
#include "nv50.h"
......@@ -987,10 +987,10 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
static void
nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
{
struct nouveau_clock *clk = nouveau_clock(priv);
struct nouveau_devinit *devinit = nouveau_devinit(priv);
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
if (pclk)
clk->pll_set(clk, PLL_VPLL0 + head, pclk);
devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
}
static void
......
......@@ -29,15 +29,14 @@
#include <engine/disp.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/clock.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
#include <subdev/devinit.h>
#include <subdev/fb.h>
#include <subdev/timer.h>
#include "nv50.h"
......@@ -738,10 +737,10 @@ nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
static void
nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
{
struct nouveau_clock *clk = nouveau_clock(priv);
struct nouveau_devinit *devinit = nouveau_devinit(priv);
u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
if (pclk)
clk->pll_set(clk, PLL_VPLL0 + head, pclk);
devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
}
......
......@@ -10,8 +10,6 @@ struct nvbios_pll;
struct nouveau_clock {
struct nouveau_subdev base;
int (*pll_set)(struct nouveau_clock *, u32 type, u32 freq);
/*XXX: die, these are here *only* to support the completely
* bat-shit insane what-was-nouveau_hw.c code
*/
......
......@@ -8,6 +8,8 @@ struct nouveau_devinit {
struct nouveau_subdev base;
bool post;
void (*meminit)(struct nouveau_devinit *);
int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
};
static inline struct nouveau_devinit *
......@@ -20,11 +22,20 @@ nouveau_devinit(void *obj)
nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_devinit_destroy(p) \
nouveau_subdev_destroy(&(p)->base)
#define nouveau_devinit_init(p) ({ \
struct nouveau_devinit *d = (p); \
_nouveau_devinit_init(nv_object(d)); \
})
#define nouveau_devinit_fini(p,s) ({ \
struct nouveau_devinit *d = (p); \
_nouveau_devinit_fini(nv_object(d), (s)); \
})
int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **);
int nouveau_devinit_init(struct nouveau_devinit *);
int nouveau_devinit_fini(struct nouveau_devinit *, bool suspend);
#define _nouveau_devinit_dtor _nouveau_subdev_dtor
int _nouveau_devinit_init(struct nouveau_object *);
int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
extern struct nouveau_oclass nv04_devinit_oclass;
extern struct nouveau_oclass nv05_devinit_oclass;
......@@ -32,9 +43,7 @@ extern struct nouveau_oclass nv10_devinit_oclass;
extern struct nouveau_oclass nv1a_devinit_oclass;
extern struct nouveau_oclass nv20_devinit_oclass;
extern struct nouveau_oclass nv50_devinit_oclass;
void nv04_devinit_dtor(struct nouveau_object *);
int nv04_devinit_init(struct nouveau_object *);
int nv04_devinit_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass nva3_devinit_oclass;
extern struct nouveau_oclass nvc0_devinit_oclass;
#endif
......@@ -10,7 +10,6 @@
#include <subdev/bios/gpio.h>
#include <subdev/bios/init.h>
#include <subdev/devinit.h>
#include <subdev/clock.h>
#include <subdev/i2c.h>
#include <subdev/vga.h>
#include <subdev/gpio.h>
......@@ -300,9 +299,9 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
static void
init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
{
struct nouveau_clock *clk = nouveau_clock(init->bios);
if (clk && clk->pll_set && init_exec(init)) {
int ret = clk->pll_set(clk, id, freq);
struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
if (devinit->pll_set && init_exec(init)) {
int ret = devinit->pll_set(devinit, id, freq);
if (ret)
warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
}
......
......@@ -22,9 +22,10 @@
* Authors: Ben Skeggs
*/
#include <subdev/clock.h>
#include <subdev/bios.h>
#include <subdev/bios/pll.h>
#include <subdev/clock.h>
#include <subdev/devinit/priv.h>
#include "pll.h"
......@@ -32,266 +33,6 @@ struct nv04_clock_priv {
struct nouveau_clock base;
};
static int
powerctrl_1_shift(int chip_version, int reg)
{
int shift = -4;
if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
return shift;
switch (reg) {
case 0x680520:
shift += 4;
case 0x680508:
shift += 4;
case 0x680504:
shift += 4;
case 0x680500:
shift += 4;
}
/*
* the shift for vpll regs is only used for nv3x chips with a single
* stage pll
*/
if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
chip_version == 0x36 || chip_version >= 0x40))
shift = -4;
return shift;
}
static void
setPLL_single(struct nv04_clock_priv *priv, u32 reg,
struct nouveau_pll_vals *pv)
{
int chip_version = nouveau_bios(priv)->version.chip;
uint32_t oldpll = nv_rd32(priv, 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(priv, 0x001584);
nv_wr32(priv, 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(priv, reg, pv->log2P << 16 | (oldpll & 0xffff));
else
/* downclock -- write new NM first */
nv_wr32(priv, reg, (oldpll & 0xffff0000) | pv->NM1);
if (chip_version < 0x17 && chip_version != 0x11)
/* wait a bit on older chips */
msleep(64);
nv_rd32(priv, reg);
/* then write the other half as well */
nv_wr32(priv, reg, pll);
if (shift_powerctrl_1 >= 0)
nv_wr32(priv, 0x001584, saved_powerctrl_1);
}
static uint32_t
new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
{
bool head_a = (reg1 == 0x680508);
if (ss) /* single stage pll mode */
ramdac580 |= head_a ? 0x00000100 : 0x10000000;
else
ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
return ramdac580;
}
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);
}
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));
}
}
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);
}
int
nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
int clk, struct nouveau_pll_vals *pv)
......@@ -313,17 +54,17 @@ int
nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
struct nouveau_pll_vals *pv)
{
struct nv04_clock_priv *priv = (void *)clk;
struct nouveau_devinit *devinit = nouveau_devinit(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);
setPLL_double_highregs(devinit, reg1, pv);
else
setPLL_double_lowregs(priv, reg1, pv);
setPLL_double_lowregs(devinit, reg1, pv);
} else
setPLL_single(priv, reg1, pv);
setPLL_single(devinit, reg1, pv);
return 0;
}
......@@ -341,7 +82,6 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nv04_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
priv->base.pll_prog = nv04_clock_pll_prog;
return 0;
......
......@@ -41,7 +41,6 @@ nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nv04_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
priv->base.pll_prog = nv04_clock_pll_prog;
return 0;
......
......@@ -32,50 +32,6 @@ struct nv50_clock_priv {
struct nouveau_clock base;
};
static int
nv50_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
{
struct nv50_clock_priv *priv = (void *)clk;
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(clk, "failed to retrieve pll data, %d\n", ret);
return ret;
}
ret = nv04_pll_calc(nv_subdev(clk), &info, freq, &N1, &M1, &N2, &M2, &P);
if (!ret) {
nv_error(clk, "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;
}
static int
nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
......@@ -89,7 +45,6 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nv50_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
return 0;
}
......
......@@ -32,40 +32,6 @@ struct nva3_clock_priv {
struct nouveau_clock base;
};
static int
nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
{
struct nva3_clock_priv *priv = (void *)clk;
struct nouveau_bios *bios = nouveau_bios(priv);
struct nvbios_pll info;
int N, fN, M, P;
int ret;
ret = nvbios_pll_parse(bios, type, &info);
if (ret)
return ret;
ret = nva3_pll_calc(nv_subdev(clk), &info, freq, &N, &fN, &M, &P);
if (ret < 0)
return ret;
switch (info.type) {
case PLL_VPLL0:
case PLL_VPLL1:
nv_wr32(priv, info.reg + 0, 0x50000610);
nv_mask(priv, info.reg + 4, 0x003fffff,
(P << 16) | (M << 8) | N);
nv_wr32(priv, info.reg + 8, fN);
break;
default:
nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
ret = -EINVAL;
break;
}
return ret;
}
int
nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
int clk, struct nouveau_pll_vals *pv)
......@@ -97,7 +63,6 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nva3_clock_pll_set;
priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
......
......@@ -32,41 +32,6 @@ struct nvc0_clock_priv {
struct nouveau_clock base;
};
static int
nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
{
struct nvc0_clock_priv *priv = (void *)clk;
struct nouveau_bios *bios = nouveau_bios(priv);
struct nvbios_pll info;
int N, fN, M, P;
int ret;
ret = nvbios_pll_parse(bios, type, &info);
if (ret)
return ret;
ret = nva3_pll_calc(nv_subdev(clk), &info, freq, &N, &fN, &M, &P);
if (ret < 0)
return ret;
switch (info.type) {
case PLL_VPLL0:
case PLL_VPLL1:
case PLL_VPLL2:
case PLL_VPLL3:
nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
nv_wr32(priv, info.reg + 0x10, fN << 16);
break;
default:
nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
ret = -EINVAL;
break;
}
return ret;
}
static int
nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
......@@ -80,7 +45,6 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nvc0_clock_pll_set;
priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
......
......@@ -29,18 +29,10 @@
#include <subdev/bios/init.h>
int
nouveau_devinit_init(struct nouveau_devinit *devinit)
_nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
{
int ret = nouveau_subdev_init(&devinit->base);
if (ret)
return ret;
struct nouveau_devinit *devinit = (void *)object;
return nvbios_init(&devinit->base, devinit->post);
}
int
nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend)
{
/* force full reinit on resume */
if (suspend)
devinit->post = true;
......@@ -48,6 +40,17 @@ nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend)
return nouveau_subdev_fini(&devinit->base, suspend);
}
int
_nouveau_devinit_init(struct nouveau_object *object)
{
struct nouveau_devinit *devinit = (void *)object;
int ret = nouveau_subdev_init(&devinit->base);
if (ret)
return ret;
return nvbios_init(&devinit->base, devinit->post);
}
int
nouveau_devinit_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
......
......@@ -24,10 +24,10 @@
*
*/
#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "fbmem.h"
#include "priv.h"
struct nv04_devinit_priv {
struct nouveau_devinit base;
......@@ -111,33 +111,298 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit)
}
static int
nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
powerctrl_1_shift(int chip_version, int reg)
{
struct nv04_devinit_priv *priv;
int shift = -4;
if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
return shift;
switch (reg) {
case 0x680520:
shift += 4;
case 0x680508:
shift += 4;
case 0x680504:
shift += 4;
case 0x680500:
shift += 4;
}
/*
* the shift for vpll regs is only used for nv3x chips with a single
* stage pll
*/
if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
chip_version == 0x36 || chip_version >= 0x40))
shift = -4;
return shift;
}
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 != 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);
}
static uint32_t
new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
{
bool head_a = (reg1 == 0x680508);
if (ss) /* single stage pll mode */
ramdac580 |= head_a ? 0x00000100 : 0x10000000;
else
ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
return ramdac580;
}
void
setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1,
struct nouveau_pll_vals *pv)
{
int chip_version = nouveau_bios(devinit)->version.chip;
bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
uint32_t oldpll1 = nv_rd32(devinit, reg1);
uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, 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(devinit, 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(devinit, 0x001584);
nv_wr32(devinit, 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(devinit, 0xc040);
if (shift_c040 != 14)
nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
}
if (oldramdac580 != ramdac580)
nv_wr32(devinit, 0x680580, ramdac580);
if (!nv3035)
nv_wr32(devinit, reg2, pll2);
nv_wr32(devinit, reg1, pll1);
if (shift_powerctrl_1 >= 0)
nv_wr32(devinit, 0x001584, saved_powerctrl_1);
if (chip_version >= 0x40)
nv_wr32(devinit, 0xc040, savedc040);
}
void
setPLL_double_lowregs(struct nouveau_devinit *devinit, 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(devinit, 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(devinit, 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(devinit), 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(devinit, 0x4600);
nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
}
if (single_stage)
Pval |= mpll ? 1 << 12 : 1 << 8;
nv_wr32(devinit, Preg, oldPval | 1 << 28);
nv_wr32(devinit, Preg, Pval & ~(4 << 28));
if (mpll) {
Pval |= 8 << 20;
nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
}
savedc040 = nv_rd32(devinit, 0xc040);
nv_wr32(devinit, 0xc040, savedc040 & maskc040);
nv_wr32(devinit, NMNMreg, NMNM);
if (NMNMreg == 0x4024)
nv_wr32(devinit, 0x403c, NMNM);
nv_wr32(devinit, Preg, Pval);
if (mpll) {
Pval &= ~(8 << 20);
nv_wr32(devinit, 0x4020, Pval);
nv_wr32(devinit, 0x4038, Pval);
nv_wr32(devinit, 0x4600, saved4600);
}
nv_wr32(devinit, 0xc040, savedc040);
if (mpll) {
nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
}
}
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 = nouveau_devinit_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
if (ret)
return ret;
priv->base.meminit = nv04_devinit_meminit;
priv->owner = -1;
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;
}
void
nv04_devinit_dtor(struct nouveau_object *object)
int
nv04_devinit_fini(struct nouveau_object *object, bool suspend)
{
struct nv04_devinit_priv *priv = (void *)object;
/* restore vga owner saved at first init, and lock crtc regs */
nv_wrvgaowner(priv, priv->owner);
nv_lockvgac(priv, true);
/* make i2c busses accessible */
nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
nouveau_devinit_destroy(&priv->base);
/* unlock extended vga crtc regs, and unslave crtcs */
nv_lockvgac(priv, false);
if (priv->owner < 0)
priv->owner = nv_rdvgaowner(priv);
nv_wrvgaowner(priv, 0);
return nouveau_devinit_fini(&priv->base, suspend);
}
int
......@@ -160,21 +425,35 @@ nv04_devinit_init(struct nouveau_object *object)
return nouveau_devinit_init(&priv->base);
}
int
nv04_devinit_fini(struct nouveau_object *object, bool suspend)
void
nv04_devinit_dtor(struct nouveau_object *object)
{
struct nv04_devinit_priv *priv = (void *)object;
/* make i2c busses accessible */
nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
/* restore vga owner saved at first init, and lock crtc regs */
nv_wrvgaowner(priv, priv->owner);
nv_lockvgac(priv, true);
/* unlock extended vga crtc regs, and unslave crtcs */
nv_lockvgac(priv, false);
if (priv->owner < 0)
priv->owner = nv_rdvgaowner(priv);
nv_wrvgaowner(priv, 0);
nouveau_devinit_destroy(&priv->base);
}
return nouveau_devinit_fini(&priv->base, suspend);
static int
nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_devinit_priv *priv;
int ret;
ret = nouveau_devinit_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.meminit = nv04_devinit_meminit;
priv->base.pll_set = nv04_devinit_pll_set;
priv->owner = -1;
return 0;
}
struct nouveau_oclass
......
......@@ -24,12 +24,12 @@
*
*/
#include <subdev/devinit.h>
#include <subdev/bios.h>
#include <subdev/bios/bmp.h>
#include <subdev/vga.h>
#include "fbmem.h"
#include "priv.h"
struct nv05_devinit_priv {
struct nouveau_devinit base;
......@@ -144,6 +144,7 @@ nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv05_devinit_meminit;
priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
......
......@@ -24,10 +24,10 @@
*
*/
#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "fbmem.h"
#include "priv.h"
struct nv10_devinit_priv {
struct nouveau_devinit base;
......@@ -109,6 +109,7 @@ nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv10_devinit_meminit;
priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
......
......@@ -22,8 +22,7 @@
* Authors: Ben Skeggs
*/
#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "priv.h"
struct nv1a_devinit_priv {
struct nouveau_devinit base;
......@@ -43,6 +42,7 @@ nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
......
......@@ -24,9 +24,7 @@
*
*/
#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "priv.h"
#include "fbmem.h"
struct nv20_devinit_priv {
......@@ -81,6 +79,7 @@ nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv20_devinit_meminit;
priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
......
/*
* Copyright 2012 Red Hat Inc.
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -26,37 +26,55 @@
#include <subdev/bios/dcb.h>
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/devinit.h>
#include <subdev/vga.h>
struct nv50_devinit_priv {
struct nouveau_devinit base;
};
#include "priv.h"
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)
nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
{
struct nv50_devinit_priv *priv;
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 = nouveau_devinit_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
ret = nvbios_pll_parse(bios, type, &info);
if (ret) {
nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
return ret;
}
return 0;
}
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;
}
static void
nv50_devinit_dtor(struct nouveau_object *object)
{
struct nv50_devinit_priv *priv = (void *)object;
nouveau_devinit_destroy(&priv->base);
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;
}
static int
int
nv50_devinit_init(struct nouveau_object *object)
{
struct nouveau_bios *bios = nouveau_bios(object);
......@@ -103,10 +121,20 @@ nv50_devinit_init(struct nouveau_object *object)
}
static int
nv50_devinit_fini(struct nouveau_object *object, bool suspend)
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 = (void *)object;
return nouveau_devinit_fini(&priv->base, suspend);
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
......@@ -114,8 +142,8 @@ nv50_devinit_oclass = {
.handle = NV_SUBDEV(DEVINIT, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_devinit_ctor,
.dtor = nv50_devinit_dtor,
.dtor = _nouveau_devinit_dtor,
.init = nv50_devinit_init,
.fini = nv50_devinit_fini,
.fini = _nouveau_devinit_fini,
},
};
/*
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
static int
nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
{
struct nva3_devinit_priv *priv = (void *)devinit;
struct nouveau_bios *bios = nouveau_bios(priv);
struct nvbios_pll info;
int N, fN, M, P;
int ret;
ret = nvbios_pll_parse(bios, type, &info);
if (ret)
return ret;
ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
if (ret < 0)
return ret;
switch (info.type) {
case PLL_VPLL0:
case PLL_VPLL1:
nv_wr32(priv, info.reg + 0, 0x50000610);
nv_mask(priv, info.reg + 4, 0x003fffff,
(P << 16) | (M << 8) | N);
nv_wr32(priv, info.reg + 8, fN);
break;
default:
nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
ret = -EINVAL;
break;
}
return ret;
}
static int
nva3_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 = nva3_devinit_pll_set;
return 0;
}
struct nouveau_oclass
nva3_devinit_oclass = {
.handle = NV_SUBDEV(DEVINIT, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nva3_devinit_ctor,
.dtor = _nouveau_devinit_dtor,
.init = nv50_devinit_init,
.fini = _nouveau_devinit_fini,
},
};
/*
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
static int
nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
{
struct nvc0_devinit_priv *priv = (void *)devinit;
struct nouveau_bios *bios = nouveau_bios(priv);
struct nvbios_pll info;
int N, fN, M, P;
int ret;
ret = nvbios_pll_parse(bios, type, &info);
if (ret)
return ret;
ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
if (ret < 0)
return ret;
switch (info.type) {
case PLL_VPLL0:
case PLL_VPLL1:
case PLL_VPLL2:
case PLL_VPLL3:
nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
nv_wr32(priv, info.reg + 0x10, fN << 16);
break;
default:
nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
ret = -EINVAL;
break;
}
return ret;
}
static int
nvc0_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 = nvc0_devinit_pll_set;
return 0;
}
struct nouveau_oclass
nvc0_devinit_oclass = {
.handle = NV_SUBDEV(DEVINIT, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_devinit_ctor,
.dtor = _nouveau_devinit_dtor,
.init = nv50_devinit_init,
.fini = _nouveau_devinit_fini,
},
};
#ifndef __NVKM_DEVINIT_PRIV_H__
#define __NVKM_DEVINIT_PRIV_H__
#include <subdev/bios.h>
#include <subdev/bios/pll.h>
#include <subdev/clock/pll.h>
#include <subdev/devinit.h>
void nv04_devinit_dtor(struct nouveau_object *);
int nv04_devinit_init(struct nouveau_object *);
int nv04_devinit_fini(struct nouveau_object *, bool);
int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
struct nv50_devinit_priv {
struct nouveau_devinit base;
};
int nv50_devinit_init(struct nouveau_object *);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment