mirror of https://gitee.com/openkylin/linux.git
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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
7ada785f18
commit
88524bc069
|
@ -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 ret;
|
||||
int shift = -4;
|
||||
|
||||
ret = nouveau_devinit_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
|
||||
return shift;
|
||||
|
||||
priv->base.meminit = nv04_devinit_meminit;
|
||||
priv->owner = -1;
|
||||
return 0;
|
||||
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
|
||||
nv04_devinit_dtor(struct nouveau_object *object)
|
||||
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 = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 void
|
||||
nv50_devinit_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_devinit_priv *priv = (void *)object;
|
||||
nouveau_devinit_destroy(&priv->base);
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
#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
|
Loading…
Reference in New Issue