diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-03-05 00:53:54 (GMT) |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-07-01 03:43:54 (GMT) |
commit | 88524bc06926b243c75e5751eb3403c602b6a904 (patch) | |
tree | d804ea8d06b1e55eaf2e2c7fcade47a192c7d5eb | |
parent | 7ada785f186b5e68309c402249cd86b910a131c7 (diff) | |
download | linux-88524bc06926b243c75e5751eb3403c602b6a904.tar.xz |
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>
24 files changed, 628 insertions, 487 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 998e8b4..f689d31 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c index 5e8c3de..5c1db3e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index a36e64e..1df3578 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index 8a84d52..4e6ef62 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 6a38402..8b42f45 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 019eacd8..3ed10b0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -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); } diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 41b7a6a..89ee289 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -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 */ diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h index 29e4cc1..685c9b1 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index c434d39..0687e64 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -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); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c index 3c2fb68..a142775 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c index a4b2b7e..0db5dbf 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c index 5e9d5e2..d09d3e7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c @@ -33,50 +33,6 @@ struct nv50_clock_priv { }; 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, struct nouveau_object **pobject) @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index 2cedfd7..f074cd2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 495b21f..439d81c2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -33,41 +33,6 @@ struct nvc0_clock_priv { }; 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, struct nouveau_object **pobject) @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 5a07a39..79c81d3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -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; @@ -49,6 +41,17 @@ nouveau_devinit_fini(struct nouveau_devinit *devinit, bool 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, struct nouveau_oclass *oclass, diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index 7a72d93..b22357d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c index 191447d..b1912a8a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c index eb76ffa..463b08f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c index 5b2ba63..e9743cd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c index eb32e99..6cc6080 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c index 4a85778..6df7224 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c @@ -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; + } - 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, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c new file mode 100644 index 0000000..76a68b2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c @@ -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, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c new file mode 100644 index 0000000..dd78efb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c @@ -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, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h new file mode 100644 index 0000000..7d622e2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h @@ -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 |