From: Ben Skeggs Date: Wed, 14 Jan 2015 04:47:24 +0000 (+1000) Subject: drm/nouveau/clk: namespace + nvidia gpu names (no binary change) X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7632b30e4b8be39270b098948c5b2f05fae8b691;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git drm/nouveau/clk: namespace + nvidia gpu names (no binary change) The namespace of NVKM is being changed to nvkm_ instead of nouveau_, which will be used for the DRM part of the driver. This is being done in order to make it very clear as to what part of the driver a given symbol belongs to, and as a minor step towards splitting the DRM driver out to be able to stand on its own (for virt). Because there's already a large amount of churn here anyway, this is as good a time as any to also switch to NVIDIA's device and chipset naming to ease collaboration with them. A comparison of objdump disassemblies proves no code changes. Signed-off-by: Ben Skeggs --- diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h index af07bbba9faf..70ad99dd01e6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h @@ -201,5 +201,23 @@ #define nouveau_bios_oclass nvkm_bios_oclass #define nouveau_pll_vals nvkm_pll_vals #define nouveau_therm_trip_point nvkm_therm_trip_point +#define nouveau_fb nvkm_fb +#define nouveau_fifo nvkm_fifo +#define nouveau_therm nvkm_therm +#define nouveau_therm_cstate nvkm_therm_cstate +#define nouveau_volt nvkm_volt +#define nouveau_timer nvkm_timer +#define nouveau_timer_wait_eq nvkm_timer_wait_eq +#define nva3_pll_calc gt215_pll_calc +#define nouveau_clk nvkm_clk +#define nouveau_domain nvkm_domain +#define nouveau_cstate nvkm_cstate +#define nouveau_pstate nvkm_pstate +#define nouveau_clk_astate nvkm_clk_astate +#define nouveau_clk_ustate nvkm_clk_ustate +#define nva3_clk_pre gt215_clk_pre +#define nva3_clk_post gt215_clk_post +#define nva3_clk_info gt215_clk_info +#define nva3_pll_info gt215_pll_info #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h index d42a08837d4f..f5d303850d8c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h @@ -1,12 +1,9 @@ -#ifndef __NOUVEAU_CLK_H__ -#define __NOUVEAU_CLK_H__ - -#include -#include +#ifndef __NVKM_CLK_H__ +#define __NVKM_CLK_H__ #include - -struct nouveau_pll_vals; +#include struct nvbios_pll; +struct nvkm_pll_vals; enum nv_clk_src { nv_clk_src_crystal, @@ -50,25 +47,34 @@ enum nv_clk_src { nv_clk_src_max, }; -struct nouveau_cstate { +struct nvkm_cstate { struct list_head head; u8 voltage; u32 domain[nv_clk_src_max]; }; -struct nouveau_pstate { +struct nvkm_pstate { struct list_head head; struct list_head list; /* c-states */ - struct nouveau_cstate base; + struct nvkm_cstate base; u8 pstate; u8 fanspeed; }; -struct nouveau_clk { - struct nouveau_subdev base; +struct nvkm_domain { + enum nv_clk_src name; + u8 bios; /* 0xff for none */ +#define NVKM_CLK_DOM_FLAG_CORE 0x01 + u8 flags; + const char *mname; + int mdiv; +}; - struct nouveau_domain *domains; - struct nouveau_pstate bstate; +struct nvkm_clk { + struct nvkm_subdev base; + + struct nvkm_domain *domains; + struct nvkm_pstate bstate; struct list_head states; int state_nr; @@ -88,80 +94,68 @@ struct nouveau_clk { bool allow_reclock; - int (*read)(struct nouveau_clk *, enum nv_clk_src); - int (*calc)(struct nouveau_clk *, struct nouveau_cstate *); - int (*prog)(struct nouveau_clk *); - void (*tidy)(struct nouveau_clk *); + int (*read)(struct nvkm_clk *, enum nv_clk_src); + int (*calc)(struct nvkm_clk *, struct nvkm_cstate *); + int (*prog)(struct nvkm_clk *); + void (*tidy)(struct nvkm_clk *); /*XXX: die, these are here *only* to support the completely - * bat-shit insane what-was-nouveau_hw.c code + * bat-shit insane what-was-nvkm_hw.c code */ - int (*pll_calc)(struct nouveau_clk *, struct nvbios_pll *, - int clk, struct nouveau_pll_vals *pv); - int (*pll_prog)(struct nouveau_clk *, u32 reg1, - struct nouveau_pll_vals *pv); + int (*pll_calc)(struct nvkm_clk *, struct nvbios_pll *, int clk, + struct nvkm_pll_vals *pv); + int (*pll_prog)(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *pv); }; -static inline struct nouveau_clk * -nouveau_clk(void *obj) +static inline struct nvkm_clk * +nvkm_clk(void *obj) { - return (void *)nouveau_subdev(obj, NVDEV_SUBDEV_CLK); + return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_CLK); } -struct nouveau_domain { - enum nv_clk_src name; - u8 bios; /* 0xff for none */ -#define NVKM_CLK_DOM_FLAG_CORE 0x01 - u8 flags; - const char *mname; - int mdiv; -}; - -#define nouveau_clk_create(p,e,o,i,r,s,n,d) \ - nouveau_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \ +#define nvkm_clk_create(p,e,o,i,r,s,n,d) \ + nvkm_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \ (void **)d) -#define nouveau_clk_destroy(p) ({ \ - struct nouveau_clk *clk = (p); \ - _nouveau_clk_dtor(nv_object(clk)); \ +#define nvkm_clk_destroy(p) ({ \ + struct nvkm_clk *clk = (p); \ + _nvkm_clk_dtor(nv_object(clk)); \ }) -#define nouveau_clk_init(p) ({ \ - struct nouveau_clk *clk = (p); \ - _nouveau_clk_init(nv_object(clk)); \ +#define nvkm_clk_init(p) ({ \ + struct nvkm_clk *clk = (p); \ + _nvkm_clk_init(nv_object(clk)); \ }) -#define nouveau_clk_fini(p,s) ({ \ - struct nouveau_clk *clk = (p); \ - _nouveau_clk_fini(nv_object(clk), (s)); \ +#define nvkm_clk_fini(p,s) ({ \ + struct nvkm_clk *clk = (p); \ + _nvkm_clk_fini(nv_object(clk), (s)); \ }) -int nouveau_clk_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, - struct nouveau_domain *, struct nouveau_pstate *, +int nvkm_clk_create_(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, + struct nvkm_domain *, struct nvkm_pstate *, int, bool, int, void **); -void _nouveau_clk_dtor(struct nouveau_object *); -int _nouveau_clk_init(struct nouveau_object *); -int _nouveau_clk_fini(struct nouveau_object *, bool); - -extern struct nouveau_oclass nv04_clk_oclass; -extern struct nouveau_oclass nv40_clk_oclass; -extern struct nouveau_oclass *nv50_clk_oclass; -extern struct nouveau_oclass *nv84_clk_oclass; -extern struct nouveau_oclass *nvaa_clk_oclass; -extern struct nouveau_oclass nva3_clk_oclass; -extern struct nouveau_oclass nvc0_clk_oclass; -extern struct nouveau_oclass nve0_clk_oclass; -extern struct nouveau_oclass gk20a_clk_oclass; - -int nv04_clk_pll_set(struct nouveau_clk *, u32 type, u32 freq); -int nv04_clk_pll_calc(struct nouveau_clk *, struct nvbios_pll *, - int clk, struct nouveau_pll_vals *); -int nv04_clk_pll_prog(struct nouveau_clk *, u32 reg1, - struct nouveau_pll_vals *); -int nva3_clk_pll_calc(struct nouveau_clk *, struct nvbios_pll *, - int clk, struct nouveau_pll_vals *); - -int nouveau_clk_ustate(struct nouveau_clk *, int req, int pwr); -int nouveau_clk_astate(struct nouveau_clk *, int req, int rel, bool wait); -int nouveau_clk_dstate(struct nouveau_clk *, int req, int rel); -int nouveau_clk_tstate(struct nouveau_clk *, int req, int rel); - +void _nvkm_clk_dtor(struct nvkm_object *); +int _nvkm_clk_init(struct nvkm_object *); +int _nvkm_clk_fini(struct nvkm_object *, bool); + +extern struct nvkm_oclass nv04_clk_oclass; +extern struct nvkm_oclass nv40_clk_oclass; +extern struct nvkm_oclass *nv50_clk_oclass; +extern struct nvkm_oclass *g84_clk_oclass; +extern struct nvkm_oclass *mcp77_clk_oclass; +extern struct nvkm_oclass gt215_clk_oclass; +extern struct nvkm_oclass gf100_clk_oclass; +extern struct nvkm_oclass gk104_clk_oclass; +extern struct nvkm_oclass gk20a_clk_oclass; + +int nv04_clk_pll_set(struct nvkm_clk *, u32 type, u32 freq); +int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk, + struct nvkm_pll_vals *); +int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *); +int gt215_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, + int clk, struct nvkm_pll_vals *); + +int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); +int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); +int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); +int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index f6004cc543c0..6dc59ffee68a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -65,7 +65,7 @@ gm100_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; @@ -107,7 +107,7 @@ gm100_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; #if 0 /* looks to be some non-trivial changes */ - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; /* priv ring says no to 0x10eb14 writes */ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index e60deaee4d2f..9df93c5b7489 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -93,7 +93,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -122,7 +122,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -151,7 +151,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -180,7 +180,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -209,7 +209,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -238,7 +238,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; @@ -267,7 +267,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv84_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; @@ -296,7 +296,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nvaa_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; @@ -325,7 +325,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nvaa_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; @@ -354,7 +354,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nva3_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; @@ -385,7 +385,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nva3_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; @@ -415,7 +415,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nva3_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; @@ -445,7 +445,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nva3_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvaf_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nvc0.c index 89ff7d0d630b..8d0304f5de73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nvc0.c @@ -65,7 +65,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -98,7 +98,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -131,7 +131,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -163,7 +163,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -196,7 +196,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -228,7 +228,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -260,7 +260,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -293,7 +293,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -325,7 +325,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nvc0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nve0.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nve0.c index 11805f72f4e9..9f0efb1d5349 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nve0.c @@ -65,7 +65,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -99,7 +99,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -133,7 +133,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -189,7 +189,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -223,7 +223,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -257,7 +257,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; @@ -290,7 +290,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nve0_clk_oclass; + device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild index 94d10a9e637a..9c2f688c9602 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild @@ -2,11 +2,11 @@ nvkm-y += nvkm/subdev/clk/base.o nvkm-y += nvkm/subdev/clk/nv04.o nvkm-y += nvkm/subdev/clk/nv40.o nvkm-y += nvkm/subdev/clk/nv50.o -nvkm-y += nvkm/subdev/clk/nv84.o -nvkm-y += nvkm/subdev/clk/nva3.o -nvkm-y += nvkm/subdev/clk/nvaa.o -nvkm-y += nvkm/subdev/clk/nvc0.o -nvkm-y += nvkm/subdev/clk/nve0.o +nvkm-y += nvkm/subdev/clk/g84.o +nvkm-y += nvkm/subdev/clk/gt215.o +nvkm-y += nvkm/subdev/clk/mcp77.o +nvkm-y += nvkm/subdev/clk/gf100.o +nvkm-y += nvkm/subdev/clk/gk104.o nvkm-y += nvkm/subdev/clk/gk20a.o nvkm-y += nvkm/subdev/clk/pllnv04.o -nvkm-y += nvkm/subdev/clk/pllnva3.o +nvkm-y += nvkm/subdev/clk/pllgt215.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index a0c21ec3f61d..adfd3d93e066 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -21,27 +21,25 @@ * * Authors: Ben Skeggs */ - -#include - #include -#include -#include -#include - #include #include #include #include +#include +#include +#include + +#include /****************************************************************************** * misc *****************************************************************************/ static u32 -nouveau_clk_adjust(struct nouveau_clk *clk, bool adjust, - u8 pstate, u8 domain, u32 input) +nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, + u8 pstate, u8 domain, u32 input) { - struct nouveau_bios *bios = nouveau_bios(clk); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_boostE boostE; u8 ver, hdr, cnt, len; u16 data; @@ -76,12 +74,11 @@ nouveau_clk_adjust(struct nouveau_clk *clk, bool adjust, * C-States *****************************************************************************/ static int -nouveau_cstate_prog(struct nouveau_clk *clk, - struct nouveau_pstate *pstate, int cstatei) +nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { - struct nouveau_therm *ptherm = nouveau_therm(clk); - struct nouveau_volt *volt = nouveau_volt(clk); - struct nouveau_cstate *cstate; + struct nvkm_therm *ptherm = nvkm_therm(clk); + struct nvkm_volt *volt = nvkm_volt(clk); + struct nvkm_cstate *cstate; int ret; if (!list_empty(&pstate->list)) { @@ -91,7 +88,7 @@ nouveau_cstate_prog(struct nouveau_clk *clk, } if (ptherm) { - ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1); + ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, +1); if (ret && ret != -ENODEV) { nv_error(clk, "failed to raise fan speed: %d\n", ret); return ret; @@ -119,7 +116,7 @@ nouveau_cstate_prog(struct nouveau_clk *clk, } if (ptherm) { - ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1); + ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, -1); if (ret && ret != -ENODEV) nv_error(clk, "failed to lower fan speed: %d\n", ret); } @@ -128,19 +125,18 @@ nouveau_cstate_prog(struct nouveau_clk *clk, } static void -nouveau_cstate_del(struct nouveau_cstate *cstate) +nvkm_cstate_del(struct nvkm_cstate *cstate) { list_del(&cstate->head); kfree(cstate); } static int -nouveau_cstate_new(struct nouveau_clk *clk, int idx, - struct nouveau_pstate *pstate) +nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) { - struct nouveau_bios *bios = nouveau_bios(clk); - struct nouveau_domain *domain = clk->domains; - struct nouveau_cstate *cstate = NULL; + struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_domain *domain = clk->domains; + struct nvkm_cstate *cstate = NULL; struct nvbios_cstepX cstepX; u8 ver, hdr; u16 data; @@ -158,10 +154,8 @@ nouveau_cstate_new(struct nouveau_clk *clk, int idx, while (domain && domain->name != nv_clk_src_max) { if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { - u32 freq = nouveau_clk_adjust(clk, true, - pstate->pstate, - domain->bios, - cstepX.freq); + u32 freq = nvkm_clk_adjust(clk, true, pstate->pstate, + domain->bios, cstepX.freq); cstate->domain[domain->name] = freq; } domain++; @@ -175,10 +169,10 @@ nouveau_cstate_new(struct nouveau_clk *clk, int idx, * P-States *****************************************************************************/ static int -nouveau_pstate_prog(struct nouveau_clk *clk, int pstatei) +nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { - struct nouveau_fb *pfb = nouveau_fb(clk); - struct nouveau_pstate *pstate; + struct nvkm_fb *pfb = nvkm_fb(clk); + struct nvkm_pstate *pstate; int ret, idx = 0; list_for_each_entry(pstate, &clk->states, head) { @@ -199,13 +193,13 @@ nouveau_pstate_prog(struct nouveau_clk *clk, int pstatei) pfb->ram->tidy(pfb); } - return nouveau_cstate_prog(clk, pstate, 0); + return nvkm_cstate_prog(clk, pstate, 0); } static void -nouveau_pstate_work(struct work_struct *work) +nvkm_pstate_work(struct work_struct *work) { - struct nouveau_clk *clk = container_of(work, typeof(*clk), work); + struct nvkm_clk *clk = container_of(work, typeof(*clk), work); int pstate; if (!atomic_xchg(&clk->waiting, 0)) @@ -227,7 +221,7 @@ nouveau_pstate_work(struct work_struct *work) nv_trace(clk, "-> %d\n", pstate); if (pstate != clk->pstate) { - int ret = nouveau_pstate_prog(clk, pstate); + int ret = nvkm_pstate_prog(clk, pstate); if (ret) { nv_error(clk, "error setting pstate %d: %d\n", pstate, ret); @@ -239,7 +233,7 @@ nouveau_pstate_work(struct work_struct *work) } static int -nouveau_pstate_calc(struct nouveau_clk *clk, bool wait) +nvkm_pstate_calc(struct nvkm_clk *clk, bool wait) { atomic_set(&clk->waiting, 1); schedule_work(&clk->work); @@ -249,10 +243,10 @@ nouveau_pstate_calc(struct nouveau_clk *clk, bool wait) } static void -nouveau_pstate_info(struct nouveau_clk *clk, struct nouveau_pstate *pstate) +nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) { - struct nouveau_domain *clock = clk->domains - 1; - struct nouveau_cstate *cstate; + struct nvkm_domain *clock = clk->domains - 1; + struct nvkm_cstate *cstate; char info[3][32] = { "", "", "" }; char name[4] = "--"; int i = -1; @@ -291,12 +285,12 @@ nouveau_pstate_info(struct nouveau_clk *clk, struct nouveau_pstate *pstate) } static void -nouveau_pstate_del(struct nouveau_pstate *pstate) +nvkm_pstate_del(struct nvkm_pstate *pstate) { - struct nouveau_cstate *cstate, *temp; + struct nvkm_cstate *cstate, *temp; list_for_each_entry_safe(cstate, temp, &pstate->list, head) { - nouveau_cstate_del(cstate); + nvkm_cstate_del(cstate); } list_del(&pstate->head); @@ -304,12 +298,12 @@ nouveau_pstate_del(struct nouveau_pstate *pstate) } static int -nouveau_pstate_new(struct nouveau_clk *clk, int idx) +nvkm_pstate_new(struct nvkm_clk *clk, int idx) { - struct nouveau_bios *bios = nouveau_bios(clk); - struct nouveau_domain *domain = clk->domains - 1; - struct nouveau_pstate *pstate; - struct nouveau_cstate *cstate; + struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_domain *domain = clk->domains - 1; + struct nvkm_pstate *pstate; + struct nvkm_cstate *cstate; struct nvbios_cstepE cstepE; struct nvbios_perfE perfE; u8 ver, hdr, cnt, len; @@ -346,10 +340,10 @@ nouveau_pstate_new(struct nouveau_clk *clk, int idx) continue; if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { - perfS.v40.freq = nouveau_clk_adjust(clk, false, - pstate->pstate, - domain->bios, - perfS.v40.freq); + perfS.v40.freq = nvkm_clk_adjust(clk, false, + pstate->pstate, + domain->bios, + perfS.v40.freq); } cstate->domain[domain->name] = perfS.v40.freq; @@ -359,11 +353,11 @@ nouveau_pstate_new(struct nouveau_clk *clk, int idx) if (data) { int idx = cstepE.index; do { - nouveau_cstate_new(clk, idx, pstate); + nvkm_cstate_new(clk, idx, pstate); } while(idx--); } - nouveau_pstate_info(clk, pstate); + nvkm_pstate_info(clk, pstate); list_add_tail(&pstate->head, &clk->states); clk->state_nr++; return 0; @@ -373,9 +367,9 @@ nouveau_pstate_new(struct nouveau_clk *clk, int idx) * Adjustment triggers *****************************************************************************/ static int -nouveau_clk_ustate_update(struct nouveau_clk *clk, int req) +nvkm_clk_ustate_update(struct nvkm_clk *clk, int req) { - struct nouveau_pstate *pstate; + struct nvkm_pstate *pstate; int i = 0; if (!clk->allow_reclock) @@ -397,7 +391,7 @@ nouveau_clk_ustate_update(struct nouveau_clk *clk, int req) } static int -nouveau_clk_nstate(struct nouveau_clk *clk, const char *mode, int arglen) +nvkm_clk_nstate(struct nvkm_clk *clk, const char *mode, int arglen) { int ret = 1; @@ -410,7 +404,7 @@ nouveau_clk_nstate(struct nouveau_clk *clk, const char *mode, int arglen) ((char *)mode)[arglen] = '\0'; if (!kstrtol(mode, 0, &v)) { - ret = nouveau_clk_ustate_update(clk, v); + ret = nvkm_clk_ustate_update(clk, v); if (ret < 0) ret = 1; } @@ -421,53 +415,53 @@ nouveau_clk_nstate(struct nouveau_clk *clk, const char *mode, int arglen) } int -nouveau_clk_ustate(struct nouveau_clk *clk, int req, int pwr) +nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr) { - int ret = nouveau_clk_ustate_update(clk, req); + int ret = nvkm_clk_ustate_update(clk, req); if (ret >= 0) { if (ret -= 2, pwr) clk->ustate_ac = ret; else clk->ustate_dc = ret; - return nouveau_pstate_calc(clk, true); + return nvkm_pstate_calc(clk, true); } return ret; } int -nouveau_clk_astate(struct nouveau_clk *clk, int req, int rel, bool wait) +nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait) { if (!rel) clk->astate = req; if ( rel) clk->astate += rel; clk->astate = min(clk->astate, clk->state_nr - 1); clk->astate = max(clk->astate, 0); - return nouveau_pstate_calc(clk, wait); + return nvkm_pstate_calc(clk, wait); } int -nouveau_clk_tstate(struct nouveau_clk *clk, int req, int rel) +nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel) { if (!rel) clk->tstate = req; if ( rel) clk->tstate += rel; clk->tstate = min(clk->tstate, 0); clk->tstate = max(clk->tstate, -(clk->state_nr - 1)); - return nouveau_pstate_calc(clk, true); + return nvkm_pstate_calc(clk, true); } int -nouveau_clk_dstate(struct nouveau_clk *clk, int req, int rel) +nvkm_clk_dstate(struct nvkm_clk *clk, int req, int rel) { if (!rel) clk->dstate = req; if ( rel) clk->dstate += rel; clk->dstate = min(clk->dstate, clk->state_nr - 1); clk->dstate = max(clk->dstate, 0); - return nouveau_pstate_calc(clk, true); + return nvkm_pstate_calc(clk, true); } static int -nouveau_clk_pwrsrc(struct nvkm_notify *notify) +nvkm_clk_pwrsrc(struct nvkm_notify *notify) { - struct nouveau_clk *clk = + struct nvkm_clk *clk = container_of(notify, typeof(*clk), pwrsrc_ntfy); - nouveau_pstate_calc(clk, false); + nvkm_pstate_calc(clk, false); return NVKM_NOTIFY_DROP; } @@ -476,21 +470,21 @@ nouveau_clk_pwrsrc(struct nvkm_notify *notify) *****************************************************************************/ int -_nouveau_clk_fini(struct nouveau_object *object, bool suspend) +_nvkm_clk_fini(struct nvkm_object *object, bool suspend) { - struct nouveau_clk *clk = (void *)object; + struct nvkm_clk *clk = (void *)object; nvkm_notify_put(&clk->pwrsrc_ntfy); - return nouveau_subdev_fini(&clk->base, suspend); + return nvkm_subdev_fini(&clk->base, suspend); } int -_nouveau_clk_init(struct nouveau_object *object) +_nvkm_clk_init(struct nvkm_object *object) { - struct nouveau_clk *clk = (void *)object; - struct nouveau_domain *clock = clk->domains; + struct nvkm_clk *clk = (void *)object; + struct nvkm_domain *clock = clk->domains; int ret; - ret = nouveau_subdev_init(&clk->base); + ret = nvkm_subdev_init(&clk->base); if (ret) return ret; @@ -508,47 +502,44 @@ _nouveau_clk_init(struct nouveau_object *object) clock++; } - nouveau_pstate_info(clk, &clk->bstate); + nvkm_pstate_info(clk, &clk->bstate); clk->astate = clk->state_nr - 1; clk->tstate = 0; clk->dstate = 0; clk->pstate = -1; - nouveau_pstate_calc(clk, true); + nvkm_pstate_calc(clk, true); return 0; } void -_nouveau_clk_dtor(struct nouveau_object *object) +_nvkm_clk_dtor(struct nvkm_object *object) { - struct nouveau_clk *clk = (void *)object; - struct nouveau_pstate *pstate, *temp; + struct nvkm_clk *clk = (void *)object; + struct nvkm_pstate *pstate, *temp; nvkm_notify_fini(&clk->pwrsrc_ntfy); list_for_each_entry_safe(pstate, temp, &clk->states, head) { - nouveau_pstate_del(pstate); + nvkm_pstate_del(pstate); } - nouveau_subdev_destroy(&clk->base); + nvkm_subdev_destroy(&clk->base); } int -nouveau_clk_create_(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, - struct nouveau_domain *clocks, - struct nouveau_pstate *pstates, int nb_pstates, - bool allow_reclock, - int length, void **object) +nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, struct nvkm_domain *clocks, + struct nvkm_pstate *pstates, int nb_pstates, + bool allow_reclock, int length, void **object) { - struct nouveau_device *device = nv_device(parent); - struct nouveau_clk *clk; + struct nvkm_device *device = nv_device(parent); + struct nvkm_clk *clk; int ret, idx, arglen; const char *mode; - ret = nouveau_subdev_create_(parent, engine, oclass, 0, "CLK", - "clock", length, object); + ret = nvkm_subdev_create_(parent, engine, oclass, 0, "CLK", + "clock", length, object); clk = *object; if (ret) return ret; @@ -558,7 +549,7 @@ nouveau_clk_create_(struct nouveau_object *parent, clk->ustate_ac = -1; clk->ustate_dc = -1; - INIT_WORK(&clk->work, nouveau_pstate_work); + INIT_WORK(&clk->work, nvkm_pstate_work); init_waitqueue_head(&clk->wait); atomic_set(&clk->waiting, 0); @@ -566,7 +557,7 @@ nouveau_clk_create_(struct nouveau_object *parent, if (!pstates) { idx = 0; do { - ret = nouveau_pstate_new(clk, idx++); + ret = nvkm_pstate_new(clk, idx++); } while (ret == 0); } else { for (idx = 0; idx < nb_pstates; idx++) @@ -576,25 +567,24 @@ nouveau_clk_create_(struct nouveau_object *parent, clk->allow_reclock = allow_reclock; - ret = nvkm_notify_init(NULL, &device->event, nouveau_clk_pwrsrc, true, + ret = nvkm_notify_init(NULL, &device->event, nvkm_clk_pwrsrc, true, NULL, 0, 0, &clk->pwrsrc_ntfy); if (ret) return ret; - mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen); + mode = nvkm_stropt(device->cfgopt, "NvClkMode", &arglen); if (mode) { - clk->ustate_ac = nouveau_clk_nstate(clk, mode, arglen); - clk->ustate_dc = nouveau_clk_nstate(clk, mode, arglen); + clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen); + clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); } - mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen); + mode = nvkm_stropt(device->cfgopt, "NvClkModeAC", &arglen); if (mode) - clk->ustate_ac = nouveau_clk_nstate(clk, mode, arglen); + clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen); - mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen); + mode = nvkm_stropt(device->cfgopt, "NvClkModeDC", &arglen); if (mode) - clk->ustate_dc = nouveau_clk_nstate(clk, mode, arglen); - + clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c new file mode 100644 index 000000000000..4c90b9769d64 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c @@ -0,0 +1,47 @@ +/* + * 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 "nv50.h" + +static struct nvkm_domain +g84_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0xff }, + { nv_clk_src_max } +}; + +struct nvkm_oclass * +g84_clk_oclass = &(struct nv50_clk_oclass) { + .base.handle = NV_SUBDEV(CLK, 0x84), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = nv50_clk_ctor, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, + }, + .domains = g84_domains, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c new file mode 100644 index 000000000000..e8125b5199a4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -0,0 +1,461 @@ +/* + * Copyright 2012 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 +#include "pll.h" + +#include +#include +#include + +struct gf100_clk_info { + u32 freq; + u32 ssel; + u32 mdiv; + u32 dsrc; + u32 ddiv; + u32 coef; +}; + +struct gf100_clk_priv { + struct nvkm_clk base; + struct gf100_clk_info eng[16]; +}; + +static u32 read_div(struct gf100_clk_priv *, int, u32, u32); + +static u32 +read_vco(struct gf100_clk_priv *priv, u32 dsrc) +{ + struct nvkm_clk *clk = &priv->base; + u32 ssrc = nv_rd32(priv, dsrc); + if (!(ssrc & 0x00000100)) + return clk->read(clk, nv_clk_src_sppll0); + return clk->read(clk, nv_clk_src_sppll1); +} + +static u32 +read_pll(struct gf100_clk_priv *priv, u32 pll) +{ + struct nvkm_clk *clk = &priv->base; + u32 ctrl = nv_rd32(priv, pll + 0x00); + u32 coef = nv_rd32(priv, pll + 0x04); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll) { + case 0x00e800: + case 0x00e820: + sclk = nv_device(priv)->crystal; + P = 1; + break; + case 0x132000: + sclk = clk->read(clk, nv_clk_src_mpllsrc); + break; + case 0x132020: + sclk = clk->read(clk, nv_clk_src_mpllsrcref); + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + break; + default: + return 0; + } + + return sclk * N / M / P; +} + +static u32 +read_div(struct gf100_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); + u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return nv_device(priv)->crystal; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(priv, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 +read_clk(struct gf100_clk_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + u32 ssel = nv_rd32(priv, 0x137100); + u32 sclk, sdiv; + + if (ssel & (1 << clk)) { + if (clk < 7) + sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + else + sclk = read_pll(priv, 0x1370e0); + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + } + + if (sctl & 0x80000000) + return (sclk * 2) / sdiv; + + return sclk; +} + +static int +gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + struct nvkm_device *device = nv_device(clk); + struct gf100_clk_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return device->crystal; + case nv_clk_src_href: + return 100000; + case nv_clk_src_sppll0: + return read_pll(priv, 0x00e800); + case nv_clk_src_sppll1: + return read_pll(priv, 0x00e820); + + case nv_clk_src_mpllsrcref: + return read_div(priv, 0, 0x137320, 0x137330); + case nv_clk_src_mpllsrc: + return read_pll(priv, 0x132020); + case nv_clk_src_mpll: + return read_pll(priv, 0x132000); + case nv_clk_src_mdiv: + return read_div(priv, 0, 0x137300, 0x137310); + case nv_clk_src_mem: + if (nv_rd32(priv, 0x1373f0) & 0x00000002) + return clk->read(clk, nv_clk_src_mpll); + return clk->read(clk, nv_clk_src_mdiv); + + case nv_clk_src_gpc: + return read_clk(priv, 0x00); + case nv_clk_src_rop: + return read_clk(priv, 0x01); + case nv_clk_src_hubk07: + return read_clk(priv, 0x02); + case nv_clk_src_hubk06: + return read_clk(priv, 0x07); + case nv_clk_src_hubk01: + return read_clk(priv, 0x08); + case nv_clk_src_copy: + return read_clk(priv, 0x09); + case nv_clk_src_daemon: + return read_clk(priv, 0x0c); + case nv_clk_src_vdec: + return read_clk(priv, 0x0e); + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + +static u32 +calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +{ + u32 div = min((ref * 2) / freq, (u32)65); + if (div < 2) + div = 2; + + *ddiv = div - 2; + return (ref * 2) / div; +} + +static u32 +calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +{ + u32 sclk; + + /* use one of the fixed frequencies if possible */ + *ddiv = 0x00000000; + switch (freq) { + case 27000: + case 108000: + *dsrc = 0x00000000; + if (freq == 108000) + *dsrc |= 0x00030000; + return freq; + case 100000: + *dsrc = 0x00000002; + return freq; + default: + *dsrc = 0x00000003; + break; + } + + /* otherwise, calculate the closest divider */ + sclk = read_vco(priv, 0x137160 + (clk * 4)); + if (clk < 7) + sclk = calc_div(priv, clk, sclk, freq, ddiv); + return sclk; +} + +static u32 +calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef) +{ + struct nvkm_bios *bios = nvkm_bios(priv); + struct nvbios_pll limits; + int N, M, P, ret; + + ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + if (ret) + return 0; + + limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + if (!limits.refclk) + return 0; + + ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + if (ret <= 0) + return 0; + + *coef = (P << 16) | (N << 8) | M; + return ret; +} + +static int +calc_clk(struct gf100_clk_priv *priv, + struct nvkm_cstate *cstate, int clk, int dom) +{ + struct gf100_clk_info *info = &priv->eng[clk]; + u32 freq = cstate->domain[dom]; + u32 src0, div0, div1D, div1P = 0; + u32 clk0, clk1 = 0; + + /* invalid clock domain */ + if (!freq) + return 0; + + /* first possible path, using only dividers */ + clk0 = calc_src(priv, clk, freq, &src0, &div0); + clk0 = calc_div(priv, clk, clk0, freq, &div1D); + + /* see if we can get any closer using PLLs */ + if (clk0 != freq && (0x00004387 & (1 << clk))) { + if (clk <= 7) + clk1 = calc_pll(priv, clk, freq, &info->coef); + else + clk1 = cstate->domain[nv_clk_src_hubk06]; + clk1 = calc_div(priv, clk, clk1, freq, &div1P); + } + + /* select the method which gets closest to target freq */ + if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { + info->dsrc = src0; + if (div0) { + info->ddiv |= 0x80000000; + info->ddiv |= div0 << 8; + info->ddiv |= div0; + } + if (div1D) { + info->mdiv |= 0x80000000; + info->mdiv |= div1D; + } + info->ssel = info->coef = 0; + info->freq = clk0; + } else { + if (div1P) { + info->mdiv |= 0x80000000; + info->mdiv |= div1P << 8; + } + info->ssel = (1 << clk); + info->freq = clk1; + } + + return 0; +} + +static int +gf100_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +{ + struct gf100_clk_priv *priv = (void *)clk; + int ret; + + if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) || + (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + return ret; + + return 0; +} + +static void +gf100_clk_prog_0(struct gf100_clk_priv *priv, int clk) +{ + struct gf100_clk_info *info = &priv->eng[clk]; + if (clk < 7 && !info->ssel) { + nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); + nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + } +} + +static void +gf100_clk_prog_1(struct gf100_clk_priv *priv, int clk) +{ + nv_mask(priv, 0x137100, (1 << clk), 0x00000000); + nv_wait(priv, 0x137100, (1 << clk), 0x00000000); +} + +static void +gf100_clk_prog_2(struct gf100_clk_priv *priv, int clk) +{ + struct gf100_clk_info *info = &priv->eng[clk]; + const u32 addr = 0x137000 + (clk * 0x20); + if (clk <= 7) { + nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + if (info->coef) { + nv_wr32(priv, addr + 0x04, info->coef); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + } + } +} + +static void +gf100_clk_prog_3(struct gf100_clk_priv *priv, int clk) +{ + struct gf100_clk_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137100, (1 << clk), info->ssel); + nv_wait(priv, 0x137100, (1 << clk), info->ssel); + } +} + +static void +gf100_clk_prog_4(struct gf100_clk_priv *priv, int clk) +{ + struct gf100_clk_info *info = &priv->eng[clk]; + nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); +} + +static int +gf100_clk_prog(struct nvkm_clk *clk) +{ + struct gf100_clk_priv *priv = (void *)clk; + struct { + void (*exec)(struct gf100_clk_priv *, int); + } stage[] = { + { gf100_clk_prog_0 }, /* div programming */ + { gf100_clk_prog_1 }, /* select div mode */ + { gf100_clk_prog_2 }, /* (maybe) program pll */ + { gf100_clk_prog_3 }, /* (maybe) select pll mode */ + { gf100_clk_prog_4 }, /* final divider */ + }; + int i, j; + + for (i = 0; i < ARRAY_SIZE(stage); i++) { + for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + if (!priv->eng[j].freq) + continue; + stage[i].exec(priv, j); + } + } + + return 0; +} + +static void +gf100_clk_tidy(struct nvkm_clk *clk) +{ + struct gf100_clk_priv *priv = (void *)clk; + memset(priv->eng, 0x00, sizeof(priv->eng)); +} + +static struct nvkm_domain +gf100_domain[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_hubk06 , 0x00 }, + { nv_clk_src_hubk01 , 0x01 }, + { nv_clk_src_copy , 0x02 }, + { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, + { nv_clk_src_rop , 0x04 }, + { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x0a }, + { nv_clk_src_hubk07 , 0x0b }, + { nv_clk_src_max } +}; + +static int +gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct gf100_clk_priv *priv; + int ret; + + ret = nvkm_clk_create(parent, engine, oclass, gf100_domain, + NULL, 0, false, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = gf100_clk_read; + priv->base.calc = gf100_clk_calc; + priv->base.prog = gf100_clk_prog; + priv->base.tidy = gf100_clk_tidy; + return 0; +} + +struct nvkm_oclass +gf100_clk_oclass = { + .handle = NV_SUBDEV(CLK, 0xc0), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_clk_ctor, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c new file mode 100644 index 000000000000..e380d62df232 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -0,0 +1,499 @@ +/* + * 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 +#include "pll.h" + +#include +#include +#include + +struct gk104_clk_info { + u32 freq; + u32 ssel; + u32 mdiv; + u32 dsrc; + u32 ddiv; + u32 coef; +}; + +struct gk104_clk_priv { + struct nvkm_clk base; + struct gk104_clk_info eng[16]; +}; + +static u32 read_div(struct gk104_clk_priv *, int, u32, u32); +static u32 read_pll(struct gk104_clk_priv *, u32); + +static u32 +read_vco(struct gk104_clk_priv *priv, u32 dsrc) +{ + u32 ssrc = nv_rd32(priv, dsrc); + if (!(ssrc & 0x00000100)) + return read_pll(priv, 0x00e800); + return read_pll(priv, 0x00e820); +} + +static u32 +read_pll(struct gk104_clk_priv *priv, u32 pll) +{ + u32 ctrl = nv_rd32(priv, pll + 0x00); + u32 coef = nv_rd32(priv, pll + 0x04); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk; + u16 fN = 0xf000; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll) { + case 0x00e800: + case 0x00e820: + sclk = nv_device(priv)->crystal; + P = 1; + break; + case 0x132000: + sclk = read_pll(priv, 0x132020); + P = (coef & 0x10000000) ? 2 : 1; + break; + case 0x132020: + sclk = read_div(priv, 0, 0x137320, 0x137330); + fN = nv_rd32(priv, pll + 0x10) >> 16; + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + break; + default: + return 0; + } + + if (P == 0) + P = 1; + + sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13); + return sclk / (M * P); +} + +static u32 +read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); + u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return nv_device(priv)->crystal; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(priv, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 +read_mem(struct gk104_clk_priv *priv) +{ + switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) { + case 1: return read_pll(priv, 0x132020); + case 2: return read_pll(priv, 0x132000); + default: + return 0; + } +} + +static u32 +read_clk(struct gk104_clk_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + u32 sclk, sdiv; + + if (clk < 7) { + u32 ssel = nv_rd32(priv, 0x137100); + if (ssel & (1 << clk)) { + sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + sdiv = 1; + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } else { + u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04)); + if ((ssrc & 0x00000003) == 0x00000003) { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + if (ssrc & 0x00000100) { + if (ssrc & 0x40000000) + sclk = read_pll(priv, 0x1370e0); + sdiv = 1; + } else { + sdiv = 0; + } + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } + + if (sctl & 0x80000000) { + if (sdiv) + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + else + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + return (sclk * 2) / sdiv; + } + + return sclk; +} + +static int +gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + struct nvkm_device *device = nv_device(clk); + struct gk104_clk_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return device->crystal; + case nv_clk_src_href: + return 100000; + case nv_clk_src_mem: + return read_mem(priv); + case nv_clk_src_gpc: + return read_clk(priv, 0x00); + case nv_clk_src_rop: + return read_clk(priv, 0x01); + case nv_clk_src_hubk07: + return read_clk(priv, 0x02); + case nv_clk_src_hubk06: + return read_clk(priv, 0x07); + case nv_clk_src_hubk01: + return read_clk(priv, 0x08); + case nv_clk_src_daemon: + return read_clk(priv, 0x0c); + case nv_clk_src_vdec: + return read_clk(priv, 0x0e); + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + +static u32 +calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +{ + u32 div = min((ref * 2) / freq, (u32)65); + if (div < 2) + div = 2; + + *ddiv = div - 2; + return (ref * 2) / div; +} + +static u32 +calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +{ + u32 sclk; + + /* use one of the fixed frequencies if possible */ + *ddiv = 0x00000000; + switch (freq) { + case 27000: + case 108000: + *dsrc = 0x00000000; + if (freq == 108000) + *dsrc |= 0x00030000; + return freq; + case 100000: + *dsrc = 0x00000002; + return freq; + default: + *dsrc = 0x00000003; + break; + } + + /* otherwise, calculate the closest divider */ + sclk = read_vco(priv, 0x137160 + (clk * 4)); + if (clk < 7) + sclk = calc_div(priv, clk, sclk, freq, ddiv); + return sclk; +} + +static u32 +calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef) +{ + struct nvkm_bios *bios = nvkm_bios(priv); + struct nvbios_pll limits; + int N, M, P, ret; + + ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + if (ret) + return 0; + + limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + if (!limits.refclk) + return 0; + + ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + if (ret <= 0) + return 0; + + *coef = (P << 16) | (N << 8) | M; + return ret; +} + +static int +calc_clk(struct gk104_clk_priv *priv, + struct nvkm_cstate *cstate, int clk, int dom) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + u32 freq = cstate->domain[dom]; + u32 src0, div0, div1D, div1P = 0; + u32 clk0, clk1 = 0; + + /* invalid clock domain */ + if (!freq) + return 0; + + /* first possible path, using only dividers */ + clk0 = calc_src(priv, clk, freq, &src0, &div0); + clk0 = calc_div(priv, clk, clk0, freq, &div1D); + + /* see if we can get any closer using PLLs */ + if (clk0 != freq && (0x0000ff87 & (1 << clk))) { + if (clk <= 7) + clk1 = calc_pll(priv, clk, freq, &info->coef); + else + clk1 = cstate->domain[nv_clk_src_hubk06]; + clk1 = calc_div(priv, clk, clk1, freq, &div1P); + } + + /* select the method which gets closest to target freq */ + if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { + info->dsrc = src0; + if (div0) { + info->ddiv |= 0x80000000; + info->ddiv |= div0; + } + if (div1D) { + info->mdiv |= 0x80000000; + info->mdiv |= div1D; + } + info->ssel = 0; + info->freq = clk0; + } else { + if (div1P) { + info->mdiv |= 0x80000000; + info->mdiv |= div1P << 8; + } + info->ssel = (1 << clk); + info->dsrc = 0x40000100; + info->freq = clk1; + } + + return 0; +} + +static int +gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +{ + struct gk104_clk_priv *priv = (void *)clk; + int ret; + + if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + return ret; + + return 0; +} + +static void +gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + if (!info->ssel) { + nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); + nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + } +} + +static void +gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk) +{ + nv_mask(priv, 0x137100, (1 << clk), 0x00000000); + nv_wait(priv, 0x137100, (1 << clk), 0x00000000); +} + +static void +gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk) +{ + nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000); +} + +static void +gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + const u32 addr = 0x137000 + (clk * 0x20); + nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + if (info->coef) { + nv_wr32(priv, addr + 0x04, info->coef); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + } +} + +static void +gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + if (info->ssel) + nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); + else + nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); +} + +static void +gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137100, (1 << clk), info->ssel); + nv_wait(priv, 0x137100, (1 << clk), info->ssel); + } +} + +static void +gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk) +{ + struct gk104_clk_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000); + nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100); + } +} + +static int +gk104_clk_prog(struct nvkm_clk *clk) +{ + struct gk104_clk_priv *priv = (void *)clk; + struct { + u32 mask; + void (*exec)(struct gk104_clk_priv *, int); + } stage[] = { + { 0x007f, gk104_clk_prog_0 }, /* div programming */ + { 0x007f, gk104_clk_prog_1_0 }, /* select div mode */ + { 0xff80, gk104_clk_prog_1_1 }, + { 0x00ff, gk104_clk_prog_2 }, /* (maybe) program pll */ + { 0xff80, gk104_clk_prog_3 }, /* final divider */ + { 0x007f, gk104_clk_prog_4_0 }, /* (maybe) select pll mode */ + { 0xff80, gk104_clk_prog_4_1 }, + }; + int i, j; + + for (i = 0; i < ARRAY_SIZE(stage); i++) { + for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + if (!(stage[i].mask & (1 << j))) + continue; + if (!priv->eng[j].freq) + continue; + stage[i].exec(priv, j); + } + } + + return 0; +} + +static void +gk104_clk_tidy(struct nvkm_clk *clk) +{ + struct gk104_clk_priv *priv = (void *)clk; + memset(priv->eng, 0x00, sizeof(priv->eng)); +} + +static struct nvkm_domain +gk104_domain[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, + { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_mem , 0x03, 0, "memory", 500 }, + { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_hubk01 , 0x05 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x07 }, + { nv_clk_src_max } +}; + +static int +gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct gk104_clk_priv *priv; + int ret; + + ret = nvkm_clk_create(parent, engine, oclass, gk104_domain, + NULL, 0, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = gk104_clk_read; + priv->base.calc = gk104_clk_calc; + priv->base.prog = gk104_clk_prog; + priv->base.tidy = gk104_clk_tidy; + return 0; +} + +struct nvkm_oclass +gk104_clk_oclass = { + .handle = NV_SUBDEV(CLK, 0xe0), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = gk104_clk_ctor, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 4529ba20af5e..94d3839fd444 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -22,6 +22,12 @@ * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c * */ +#include +#include + +#ifdef __KERNEL__ +#include +#endif #define MHZ (1000 * 1000) @@ -87,13 +93,6 @@ #define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \ (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT) -#include -#include - -#ifdef __KERNEL__ -#include -#endif - static const u8 pl_to_div[] = { /* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32, @@ -117,7 +116,7 @@ static const struct gk20a_clk_pllg_params gk20a_pllg_params = { }; struct gk20a_clk_priv { - struct nouveau_clk base; + struct nvkm_clk base; const struct gk20a_clk_pllg_params *params; u32 m, n, pl; u32 parent_rate; @@ -260,7 +259,6 @@ found_match: nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]); - return 0; } @@ -402,8 +400,8 @@ _gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv, bool allow_slide) nv_wr32(priv, GPCPLL_CFG, val); } - if (!nouveau_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, - GPCPLL_CFG_LOCK)) { + if (!nvkm_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, + GPCPLL_CFG_LOCK)) { nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__); return -ETIMEDOUT; } @@ -458,14 +456,14 @@ gk20a_pllg_disable(struct gk20a_clk_priv *priv) #define GK20A_CLK_GPC_MDIV 1000 -static struct nouveau_domain +static struct nvkm_domain gk20a_domains[] = { { nv_clk_src_crystal, 0xff }, { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, { nv_clk_src_max } }; -static struct nouveau_pstate +static struct nvkm_pstate gk20a_pstates[] = { { .base = { @@ -560,7 +558,7 @@ gk20a_pstates[] = { }; static int -gk20a_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) +gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) { struct gk20a_clk_priv *priv = (void *)clk; @@ -577,7 +575,7 @@ gk20a_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) } static int -gk20a_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) +gk20a_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) { struct gk20a_clk_priv *priv = (void *)clk; @@ -586,7 +584,7 @@ gk20a_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) } static int -gk20a_clk_prog(struct nouveau_clk *clk) +gk20a_clk_prog(struct nvkm_clk *clk) { struct gk20a_clk_priv *priv = (void *)clk; @@ -594,17 +592,17 @@ gk20a_clk_prog(struct nouveau_clk *clk) } static void -gk20a_clk_tidy(struct nouveau_clk *clk) +gk20a_clk_tidy(struct nvkm_clk *clk) { } static int -gk20a_clk_fini(struct nouveau_object *object, bool suspend) +gk20a_clk_fini(struct nvkm_object *object, bool suspend) { struct gk20a_clk_priv *priv = (void *)object; int ret; - ret = nouveau_clk_fini(&priv->base, false); + ret = nvkm_clk_fini(&priv->base, false); gk20a_pllg_disable(priv); @@ -612,14 +610,14 @@ gk20a_clk_fini(struct nouveau_object *object, bool suspend) } static int -gk20a_clk_init(struct nouveau_object *object) +gk20a_clk_init(struct nvkm_object *object) { struct gk20a_clk_priv *priv = (void *)object; int ret; nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); - ret = nouveau_clk_init(&priv->base); + ret = nvkm_clk_init(&priv->base); if (ret) return ret; @@ -633,9 +631,9 @@ gk20a_clk_init(struct nouveau_object *object) } static int -gk20a_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { struct gk20a_clk_priv *priv; struct nouveau_platform_device *plat; @@ -648,8 +646,9 @@ gk20a_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, gk20a_pstates[i].pstate = i + 1; } - ret = nouveau_clk_create(parent, engine, oclass, gk20a_domains, - gk20a_pstates, ARRAY_SIZE(gk20a_pstates), true, &priv); + ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains, + gk20a_pstates, ARRAY_SIZE(gk20a_pstates), + true, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -664,16 +663,15 @@ gk20a_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.calc = gk20a_clk_calc; priv->base.prog = gk20a_clk_prog; priv->base.tidy = gk20a_clk_tidy; - return 0; } -struct nouveau_oclass +struct nvkm_oclass gk20a_clk_oclass = { .handle = NV_SUBDEV(CLK, 0xea), - .ofuncs = &(struct nouveau_ofuncs) { + .ofuncs = &(struct nvkm_ofuncs) { .ctor = gk20a_clk_ctor, - .dtor = _nouveau_subdev_dtor, + .dtor = _nvkm_subdev_dtor, .init = gk20a_clk_init, .fini = gk20a_clk_fini, }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c new file mode 100644 index 000000000000..99e3ca3b0890 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -0,0 +1,532 @@ +/* + * Copyright 2012 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 + * Roy Spliet + */ +#include "gt215.h" +#include "pll.h" + +#include +#include +#include +#include + +struct gt215_clk_priv { + struct nvkm_clk base; + struct gt215_clk_info eng[nv_clk_src_max]; +}; + +static u32 read_clk(struct gt215_clk_priv *, int, bool); +static u32 read_pll(struct gt215_clk_priv *, int, u32); + +static u32 +read_vco(struct gt215_clk_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + + switch (sctl & 0x00000030) { + case 0x00000000: + return nv_device(priv)->crystal; + case 0x00000020: + return read_pll(priv, 0x41, 0x00e820); + case 0x00000030: + return read_pll(priv, 0x42, 0x00e8a0); + default: + return 0; + } +} + +static u32 +read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) +{ + u32 sctl, sdiv, sclk; + + /* refclk for the 0xe8xx plls is a fixed frequency */ + if (clk >= 0x40) { + if (nv_device(priv)->chipset == 0xaf) { + /* no joke.. seriously.. sigh.. */ + return nv_rd32(priv, 0x00471c) * 1000; + } + + return nv_device(priv)->crystal; + } + + sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + if (!ignore_en && !(sctl & 0x00000100)) + return 0; + + /* out_alt */ + if (sctl & 0x00000400) + return 108000; + + /* vco_out */ + switch (sctl & 0x00003000) { + case 0x00000000: + if (!(sctl & 0x00000200)) + return nv_device(priv)->crystal; + return 0; + case 0x00002000: + if (sctl & 0x00000040) + return 108000; + return 100000; + case 0x00003000: + /* vco_enable */ + if (!(sctl & 0x00000001)) + return 0; + + sclk = read_vco(priv, clk); + sdiv = ((sctl & 0x003f0000) >> 16) + 2; + return (sclk * 2) / sdiv; + default: + return 0; + } +} + +static u32 +read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) +{ + u32 ctrl = nv_rd32(priv, pll + 0); + u32 sclk = 0, P = 1, N = 1, M = 1; + + if (!(ctrl & 0x00000008)) { + if (ctrl & 0x00000001) { + u32 coef = nv_rd32(priv, pll + 4); + M = (coef & 0x000000ff) >> 0; + N = (coef & 0x0000ff00) >> 8; + P = (coef & 0x003f0000) >> 16; + + /* no post-divider on these.. + * XXX: it looks more like two post-"dividers" that + * cross each other out in the default RPLL config */ + if ((pll & 0x00ff00) == 0x00e800) + P = 1; + + sclk = read_clk(priv, 0x00 + clk, false); + } + } else { + sclk = read_clk(priv, 0x10 + clk, false); + } + + if (M * P) + return sclk * N / (M * P); + + return 0; +} + +static int +gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + struct gt215_clk_priv *priv = (void *)clk; + u32 hsrc; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_core: + case nv_clk_src_core_intm: + return read_pll(priv, 0x00, 0x4200); + case nv_clk_src_shader: + return read_pll(priv, 0x01, 0x4220); + case nv_clk_src_mem: + return read_pll(priv, 0x02, 0x4000); + case nv_clk_src_disp: + return read_clk(priv, 0x20, false); + case nv_clk_src_vdec: + return read_clk(priv, 0x21, false); + case nv_clk_src_daemon: + return read_clk(priv, 0x25, false); + case nv_clk_src_host: + hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28; + switch (hsrc) { + case 0: + return read_clk(priv, 0x1d, false); + case 2: + case 3: + return 277000; + default: + nv_error(clk, "unknown HOST clock source %d\n", hsrc); + return -EINVAL; + } + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } + + return 0; +} + +int +gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, + struct gt215_clk_info *info) +{ + struct gt215_clk_priv *priv = (void *)clock; + u32 oclk, sclk, sdiv, diff; + + info->clk = 0; + + switch (khz) { + case 27000: + info->clk = 0x00000100; + return khz; + case 100000: + info->clk = 0x00002100; + return khz; + case 108000: + info->clk = 0x00002140; + return khz; + default: + sclk = read_vco(priv, clk); + sdiv = min((sclk * 2) / khz, (u32)65); + oclk = (sclk * 2) / sdiv; + diff = ((khz + 3000) - oclk); + + /* When imprecise, play it safe and aim for a clock lower than + * desired rather than higher */ + if (diff < 0) { + sdiv++; + oclk = (sclk * 2) / sdiv; + } + + /* divider can go as low as 2, limited here because NVIDIA + * and the VBIOS on my NVA8 seem to prefer using the PLL + * for 810MHz - is there a good reason? + * XXX: PLLs with refclk 810MHz? */ + if (sdiv > 4) { + info->clk = (((sdiv - 2) << 16) | 0x00003100); + return oclk; + } + + break; + } + + return -ERANGE; +} + +int +gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, + struct gt215_clk_info *info) +{ + struct nvkm_bios *bios = nvkm_bios(clock); + struct gt215_clk_priv *priv = (void *)clock; + struct nvbios_pll limits; + int P, N, M, diff; + int ret; + + info->pll = 0; + + /* If we can get a within [-2, 3) MHz of a divider, we'll disable the + * PLL and use the divider instead. */ + ret = gt215_clk_info(clock, clk, khz, info); + diff = khz - ret; + if (!pll || (diff >= -2000 && diff < 3000)) { + goto out; + } + + /* Try with PLL */ + ret = nvbios_pll_parse(bios, pll, &limits); + if (ret) + return ret; + + ret = gt215_clk_info(clock, clk - 0x10, limits.refclk, info); + if (ret != limits.refclk) + return -EINVAL; + + ret = gt215_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); + if (ret >= 0) { + info->pll = (P << 16) | (N << 8) | M; + } + +out: + info->fb_delay = max(((khz + 7566) / 15133), (u32) 18); + return ret ? ret : -ERANGE; +} + +static int +calc_clk(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate, + int clk, u32 pll, int idx) +{ + int ret = gt215_pll_info(&priv->base, clk, pll, cstate->domain[idx], + &priv->eng[idx]); + if (ret >= 0) + return 0; + return ret; +} + +static int +calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) +{ + int ret = 0; + u32 kHz = cstate->domain[nv_clk_src_host]; + struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; + + if (kHz == 277000) { + info->clk = 0; + info->host_out = NVA3_HOST_277; + return 0; + } + + info->host_out = NVA3_HOST_CLK; + + ret = gt215_clk_info(&priv->base, 0x1d, kHz, info); + if (ret >= 0) + return 0; + + return ret; +} + +int +gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) +{ + struct nvkm_fifo *pfifo = nvkm_fifo(clk); + + /* halt and idle execution engines */ + nv_mask(clk, 0x020060, 0x00070000, 0x00000000); + nv_mask(clk, 0x002504, 0x00000001, 0x00000001); + /* Wait until the interrupt handler is finished */ + if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) + return -EBUSY; + + if (pfifo) + pfifo->pause(pfifo, flags); + + if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + return -EIO; + if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + return -EIO; + + return 0; +} + +void +gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) +{ + struct nvkm_fifo *pfifo = nvkm_fifo(clk); + + if (pfifo && flags) + pfifo->start(pfifo, flags); + + nv_mask(clk, 0x002504, 0x00000001, 0x00000000); + nv_mask(clk, 0x020060, 0x00070000, 0x00040000); +} + +static void +disable_clk_src(struct gt215_clk_priv *priv, u32 src) +{ + nv_mask(priv, src, 0x00000100, 0x00000000); + nv_mask(priv, src, 0x00000001, 0x00000000); +} + +static void +prog_pll(struct gt215_clk_priv *priv, int clk, u32 pll, int idx) +{ + struct gt215_clk_info *info = &priv->eng[idx]; + const u32 src0 = 0x004120 + (clk * 4); + const u32 src1 = 0x004160 + (clk * 4); + const u32 ctrl = pll + 0; + const u32 coef = pll + 4; + u32 bypass; + + if (info->pll) { + /* Always start from a non-PLL clock */ + bypass = nv_rd32(priv, ctrl) & 0x00000008; + if (!bypass) { + nv_mask(priv, src1, 0x00000101, 0x00000101); + nv_mask(priv, ctrl, 0x00000008, 0x00000008); + udelay(20); + } + + nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); + nv_wr32(priv, coef, info->pll); + nv_mask(priv, ctrl, 0x00000015, 0x00000015); + nv_mask(priv, ctrl, 0x00000010, 0x00000000); + if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) { + nv_mask(priv, ctrl, 0x00000010, 0x00000010); + nv_mask(priv, src0, 0x00000101, 0x00000000); + return; + } + nv_mask(priv, ctrl, 0x00000010, 0x00000010); + nv_mask(priv, ctrl, 0x00000008, 0x00000000); + disable_clk_src(priv, src1); + } else { + nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk); + nv_mask(priv, ctrl, 0x00000018, 0x00000018); + udelay(20); + nv_mask(priv, ctrl, 0x00000001, 0x00000000); + disable_clk_src(priv, src0); + } +} + +static void +prog_clk(struct gt215_clk_priv *priv, int clk, int idx) +{ + struct gt215_clk_info *info = &priv->eng[idx]; + nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); +} + +static void +prog_host(struct gt215_clk_priv *priv) +{ + struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; + u32 hsrc = (nv_rd32(priv, 0xc040)); + + switch (info->host_out) { + case NVA3_HOST_277: + if ((hsrc & 0x30000000) == 0) { + nv_wr32(priv, 0xc040, hsrc | 0x20000000); + disable_clk_src(priv, 0x4194); + } + break; + case NVA3_HOST_CLK: + prog_clk(priv, 0x1d, nv_clk_src_host); + if ((hsrc & 0x30000000) >= 0x20000000) { + nv_wr32(priv, 0xc040, hsrc & ~0x30000000); + } + break; + default: + break; + } + + /* This seems to be a clock gating factor on idle, always set to 64 */ + nv_wr32(priv, 0xc044, 0x3e); +} + +static void +prog_core(struct gt215_clk_priv *priv, int idx) +{ + struct gt215_clk_info *info = &priv->eng[idx]; + u32 fb_delay = nv_rd32(priv, 0x10002c); + + if (fb_delay < info->fb_delay) + nv_wr32(priv, 0x10002c, info->fb_delay); + + prog_pll(priv, 0x00, 0x004200, idx); + + if (fb_delay > info->fb_delay) + nv_wr32(priv, 0x10002c, info->fb_delay); +} + +static int +gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +{ + struct gt215_clk_priv *priv = (void *)clk; + struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + int ret; + + if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || + (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) || + (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) || + (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || + (ret = calc_host(priv, cstate))) + return ret; + + /* XXX: Should be reading the highest bit in the VBIOS clock to decide + * whether to use a PLL or not... but using a PLL defeats the purpose */ + if (core->pll) { + ret = gt215_clk_info(clk, 0x10, + cstate->domain[nv_clk_src_core_intm], + &priv->eng[nv_clk_src_core_intm]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int +gt215_clk_prog(struct nvkm_clk *clk) +{ + struct gt215_clk_priv *priv = (void *)clk; + struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + int ret = 0; + unsigned long flags; + unsigned long *f = &flags; + + ret = gt215_clk_pre(clk, f); + if (ret) + goto out; + + if (core->pll) + prog_core(priv, nv_clk_src_core_intm); + + prog_core(priv, nv_clk_src_core); + prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); + prog_clk(priv, 0x20, nv_clk_src_disp); + prog_clk(priv, 0x21, nv_clk_src_vdec); + prog_host(priv); + +out: + if (ret == -EBUSY) + f = NULL; + + gt215_clk_post(clk, f); + return ret; +} + +static void +gt215_clk_tidy(struct nvkm_clk *clk) +{ +} + +static struct nvkm_domain +gt215_domain[] = { + { nv_clk_src_crystal , 0xff }, + { nv_clk_src_core , 0x00, 0, "core", 1000 }, + { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, + { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x03 }, + { nv_clk_src_disp , 0x04 }, + { nv_clk_src_host , 0x05 }, + { nv_clk_src_core_intm, 0x06 }, + { nv_clk_src_max } +}; + +static int +gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct gt215_clk_priv *priv; + int ret; + + ret = nvkm_clk_create(parent, engine, oclass, gt215_domain, + NULL, 0, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = gt215_clk_read; + priv->base.calc = gt215_clk_calc; + priv->base.prog = gt215_clk_prog; + priv->base.tidy = gt215_clk_tidy; + return 0; +} + +struct nvkm_oclass +gt215_clk_oclass = { + .handle = NV_SUBDEV(CLK, 0xa3), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = gt215_clk_ctor, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h new file mode 100644 index 000000000000..b447d9cd4d37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_CLK_NVA3_H__ +#define __NVKM_CLK_NVA3_H__ +#include + +struct gt215_clk_info { + u32 clk; + u32 pll; + enum { + NVA3_HOST_277, + NVA3_HOST_CLK, + } host_out; + u32 fb_delay; +}; + +int gt215_pll_info(struct nvkm_clk *, int, u32, u32, struct gt215_clk_info *); +int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags); +void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c new file mode 100644 index 000000000000..d735de2dbd74 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -0,0 +1,428 @@ +/* + * Copyright 2012 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 "gt215.h" +#include "pll.h" + +#include +#include +#include + +struct mcp77_clk_priv { + struct nvkm_clk base; + enum nv_clk_src csrc, ssrc, vsrc; + u32 cctrl, sctrl; + u32 ccoef, scoef; + u32 cpost, spost; + u32 vdiv; +}; + +static u32 +read_div(struct nvkm_clk *clk) +{ + return nv_rd32(clk, 0x004600); +} + +static u32 +read_pll(struct nvkm_clk *clk, u32 base) +{ + u32 ctrl = nv_rd32(clk, base + 0); + u32 coef = nv_rd32(clk, base + 4); + u32 ref = clk->read(clk, nv_clk_src_href); + u32 post_div = 0; + u32 clock = 0; + int N1, M1; + + switch (base){ + case 0x4020: + post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); + break; + case 0x4028: + post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; + break; + default: + break; + } + + N1 = (coef & 0x0000ff00) >> 8; + M1 = (coef & 0x000000ff); + if ((ctrl & 0x80000000) && M1) { + clock = ref * N1 / M1; + clock = clock / post_div; + } + + return clock; +} + +static int +mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + struct mcp77_clk_priv *priv = (void *)clk; + u32 mast = nv_rd32(clk, 0x00c054); + u32 P = 0; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_href: + return 100000; /* PCIE reference clock */ + case nv_clk_src_hclkm4: + return clk->read(clk, nv_clk_src_href) * 4; + case nv_clk_src_hclkm2d3: + return clk->read(clk, nv_clk_src_href) * 2 / 3; + case nv_clk_src_host: + switch (mast & 0x000c0000) { + case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00040000: break; + case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); + case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); + } + break; + case nv_clk_src_core: + P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; + + switch (mast & 0x00000003) { + case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000001: return 0; + case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; + case 0x00000003: return read_pll(clk, 0x004028) >> P; + } + break; + case nv_clk_src_cclk: + if ((mast & 0x03000000) != 0x03000000) + return clk->read(clk, nv_clk_src_core); + + if ((mast & 0x00000200) == 0x00000000) + return clk->read(clk, nv_clk_src_core); + + switch (mast & 0x00000c00) { + case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); + case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); + default: return 0; + } + case nv_clk_src_shader: + P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; + switch (mast & 0x00000030) { + case 0x00000000: + if (mast & 0x00000040) + return clk->read(clk, nv_clk_src_href) >> P; + return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000010: break; + case 0x00000020: return read_pll(clk, 0x004028) >> P; + case 0x00000030: return read_pll(clk, 0x004020) >> P; + } + break; + case nv_clk_src_mem: + return 0; + break; + case nv_clk_src_vdec: + P = (read_div(clk) & 0x00000700) >> 8; + + switch (mast & 0x00400000) { + case 0x00400000: + return clk->read(clk, nv_clk_src_core) >> P; + break; + default: + return 500000 >> P; + break; + } + break; + default: + break; + } + + nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + return 0; +} + +static u32 +calc_pll(struct mcp77_clk_priv *priv, u32 reg, + u32 clock, int *N, int *M, int *P) +{ + struct nvkm_bios *bios = nvkm_bios(priv); + struct nvbios_pll pll; + struct nvkm_clk *clk = &priv->base; + int ret; + + ret = nvbios_pll_parse(bios, reg, &pll); + if (ret) + return 0; + + pll.vco2.max_freq = 0; + pll.refclk = clk->read(clk, nv_clk_src_href); + if (!pll.refclk) + return 0; + + return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); +} + +static inline u32 +calc_P(u32 src, u32 target, int *div) +{ + u32 clk0 = src, clk1 = src; + for (*div = 0; *div <= 7; (*div)++) { + if (clk0 <= target) { + clk1 = clk0 << (*div ? 1 : 0); + break; + } + clk0 >>= 1; + } + + if (target - clk0 <= clk1 - target) + return clk0; + (*div)--; + return clk1; +} + +static int +mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +{ + struct mcp77_clk_priv *priv = (void *)clk; + const int shader = cstate->domain[nv_clk_src_shader]; + const int core = cstate->domain[nv_clk_src_core]; + const int vdec = cstate->domain[nv_clk_src_vdec]; + u32 out = 0, clock = 0; + int N, M, P1, P2 = 0; + int divs = 0; + + /* cclk: find suitable source, disable PLL if we can */ + if (core < clk->read(clk, nv_clk_src_hclkm4)) + out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); + + /* Calculate clock * 2, so shader clock can use it too */ + clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); + + if (abs(core - out) <= abs(core - (clock >> 1))) { + priv->csrc = nv_clk_src_hclkm4; + priv->cctrl = divs << 16; + } else { + /* NVCTRL is actually used _after_ NVPOST, and after what we + * call NVPLL. To make matters worse, NVPOST is an integer + * divider instead of a right-shift number. */ + if(P1 > 2) { + P2 = P1 - 2; + P1 = 2; + } + + priv->csrc = nv_clk_src_core; + priv->ccoef = (N << 8) | M; + + priv->cctrl = (P2 + 1) << 16; + priv->cpost = (1 << P1) << 16; + } + + /* sclk: nvpll + divisor, href or spll */ + out = 0; + if (shader == clk->read(clk, nv_clk_src_href)) { + priv->ssrc = nv_clk_src_href; + } else { + clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); + if (priv->csrc == nv_clk_src_core) + out = calc_P((core << 1), shader, &divs); + + if (abs(shader - out) <= + abs(shader - clock) && + (divs + P2) <= 7) { + priv->ssrc = nv_clk_src_core; + priv->sctrl = (divs + P2) << 16; + } else { + priv->ssrc = nv_clk_src_shader; + priv->scoef = (N << 8) | M; + priv->sctrl = P1 << 16; + } + } + + /* vclk */ + out = calc_P(core, vdec, &divs); + clock = calc_P(500000, vdec, &P1); + if(abs(vdec - out) <= abs(vdec - clock)) { + priv->vsrc = nv_clk_src_cclk; + priv->vdiv = divs << 16; + } else { + priv->vsrc = nv_clk_src_vdec; + priv->vdiv = P1 << 16; + } + + /* Print strategy! */ + nv_debug(priv, "nvpll: %08x %08x %08x\n", + priv->ccoef, priv->cpost, priv->cctrl); + nv_debug(priv, " spll: %08x %08x %08x\n", + priv->scoef, priv->spost, priv->sctrl); + nv_debug(priv, " vdiv: %08x\n", priv->vdiv); + if (priv->csrc == nv_clk_src_hclkm4) + nv_debug(priv, "core: hrefm4\n"); + else + nv_debug(priv, "core: nvpll\n"); + + if (priv->ssrc == nv_clk_src_hclkm4) + nv_debug(priv, "shader: hrefm4\n"); + else if (priv->ssrc == nv_clk_src_core) + nv_debug(priv, "shader: nvpll\n"); + else + nv_debug(priv, "shader: spll\n"); + + if (priv->vsrc == nv_clk_src_hclkm4) + nv_debug(priv, "vdec: 500MHz\n"); + else + nv_debug(priv, "vdec: core\n"); + + return 0; +} + +static int +mcp77_clk_prog(struct nvkm_clk *clk) +{ + struct mcp77_clk_priv *priv = (void *)clk; + u32 pllmask = 0, mast; + unsigned long flags; + unsigned long *f = &flags; + int ret = 0; + + ret = gt215_clk_pre(clk, f); + if (ret) + goto out; + + /* First switch to safe clocks: href */ + mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); + mast &= ~0x00400e73; + mast |= 0x03000000; + + switch (priv->csrc) { + case nv_clk_src_hclkm4: + nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); + mast |= 0x00000002; + break; + case nv_clk_src_core: + nv_wr32(clk, 0x402c, priv->ccoef); + nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); + nv_wr32(clk, 0x4040, priv->cpost); + pllmask |= (0x3 << 8); + mast |= 0x00000003; + break; + default: + nv_warn(priv,"Reclocking failed: unknown core clock\n"); + goto resume; + } + + switch (priv->ssrc) { + case nv_clk_src_href: + nv_mask(clk, 0x4020, 0x00070000, 0x00000000); + /* mast |= 0x00000000; */ + break; + case nv_clk_src_core: + nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); + mast |= 0x00000020; + break; + case nv_clk_src_shader: + nv_wr32(clk, 0x4024, priv->scoef); + nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); + nv_wr32(clk, 0x4070, priv->spost); + pllmask |= (0x3 << 12); + mast |= 0x00000030; + break; + default: + nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); + goto resume; + } + + if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { + nv_warn(priv,"Reclocking failed: unstable PLLs\n"); + goto resume; + } + + switch (priv->vsrc) { + case nv_clk_src_cclk: + mast |= 0x00400000; + default: + nv_wr32(clk, 0x4600, priv->vdiv); + } + + nv_wr32(clk, 0xc054, mast); + +resume: + /* Disable some PLLs and dividers when unused */ + if (priv->csrc != nv_clk_src_core) { + nv_wr32(clk, 0x4040, 0x00000000); + nv_mask(clk, 0x4028, 0x80000000, 0x00000000); + } + + if (priv->ssrc != nv_clk_src_shader) { + nv_wr32(clk, 0x4070, 0x00000000); + nv_mask(clk, 0x4020, 0x80000000, 0x00000000); + } + +out: + if (ret == -EBUSY) + f = NULL; + + gt215_clk_post(clk, f); + return ret; +} + +static void +mcp77_clk_tidy(struct nvkm_clk *clk) +{ +} + +static struct nvkm_domain +mcp77_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, + { nv_clk_src_max } +}; + +static int +mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct mcp77_clk_priv *priv; + int ret; + + ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains, + NULL, 0, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = mcp77_clk_read; + priv->base.calc = mcp77_clk_calc; + priv->base.prog = mcp77_clk_prog; + priv->base.tidy = mcp77_clk_tidy; + return 0; +} + +struct nvkm_oclass * +mcp77_clk_oclass = &(struct nvkm_oclass) { + .handle = NV_SUBDEV(CLK, 0xaa), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = mcp77_clk_ctor, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c index de68f2f53204..63dbbb575228 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c @@ -21,21 +21,20 @@ * * Authors: Ben Skeggs */ +#include +#include "pll.h" #include #include -#include #include -#include "pll.h" - struct nv04_clk_priv { - struct nouveau_clk base; + struct nvkm_clk base; }; int -nv04_clk_pll_calc(struct nouveau_clk *clock, struct nvbios_pll *info, - int clk, struct nouveau_pll_vals *pv) +nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, + int clk, struct nvkm_pll_vals *pv) { int N1, M1, N2, M2, P; int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P); @@ -51,11 +50,10 @@ nv04_clk_pll_calc(struct nouveau_clk *clock, struct nvbios_pll *info, } int -nv04_clk_pll_prog(struct nouveau_clk *clk, u32 reg1, - struct nouveau_pll_vals *pv) +nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv) { - struct nouveau_devinit *devinit = nouveau_devinit(clk); - int cv = nouveau_bios(clk)->version.chip; + struct nvkm_devinit *devinit = nvkm_devinit(clk); + int cv = nvkm_bios(clk)->version.chip; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { @@ -69,21 +67,21 @@ nv04_clk_pll_prog(struct nouveau_clk *clk, u32 reg1, return 0; } -static struct nouveau_domain +static struct nvkm_domain nv04_domain[] = { { nv_clk_src_max } }; static int -nv04_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { struct nv04_clk_priv *priv; int ret; - ret = nouveau_clk_create(parent, engine, oclass, nv04_domain, NULL, 0, - false, &priv); + ret = nvkm_clk_create(parent, engine, oclass, nv04_domain, + NULL, 0, false, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -93,13 +91,13 @@ nv04_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass +struct nvkm_oclass nv04_clk_oclass = { .handle = NV_SUBDEV(CLK, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { + .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv04_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index 460ca4ab603b..ed838130c89d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -21,22 +21,22 @@ * * Authors: Ben Skeggs */ - #include +#include "pll.h" + +#include #include #include -#include "pll.h" - struct nv40_clk_priv { - struct nouveau_clk base; + struct nvkm_clk base; u32 ctrl; u32 npll_ctrl; u32 npll_coef; u32 spll; }; -static struct nouveau_domain +static struct nvkm_domain nv40_domain[] = { { nv_clk_src_crystal, 0xff }, { nv_clk_src_href , 0xff }, @@ -102,7 +102,7 @@ read_clk(struct nv40_clk_priv *priv, u32 src) } static int -nv40_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) +nv40_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) { struct nv40_clk_priv *priv = (void *)clk; u32 mast = nv_rd32(priv, 0x00c040); @@ -128,9 +128,9 @@ nv40_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) static int nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, - int *N1, int *M1, int *N2, int *M2, int *log2P) + int *N1, int *M1, int *N2, int *M2, int *log2P) { - struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_bios *bios = nvkm_bios(priv); struct nvbios_pll pll; int ret; @@ -144,11 +144,12 @@ nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P); if (ret == 0) return -ERANGE; + return ret; } static int -nv40_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) +nv40_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) { struct nv40_clk_priv *priv = (void *)clk; int gclk = cstate->domain[nv_clk_src_core]; @@ -158,7 +159,7 @@ nv40_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) /* core/geometric clock */ ret = nv40_clk_calc_pll(priv, 0x004000, gclk, - &N1, &M1, &N2, &M2, &log2P); + &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; @@ -173,7 +174,7 @@ nv40_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) /* use the second pll for shader/rop clock, if it differs from core */ if (sclk && sclk != gclk) { ret = nv40_clk_calc_pll(priv, 0x004008, sclk, - &N1, &M1, NULL, NULL, &log2P); + &N1, &M1, NULL, NULL, &log2P); if (ret < 0) return ret; @@ -188,7 +189,7 @@ nv40_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) } static int -nv40_clk_prog(struct nouveau_clk *clk) +nv40_clk_prog(struct nvkm_clk *clk) { struct nv40_clk_priv *priv = (void *)clk; nv_mask(priv, 0x00c040, 0x00000333, 0x00000000); @@ -201,20 +202,20 @@ nv40_clk_prog(struct nouveau_clk *clk) } static void -nv40_clk_tidy(struct nouveau_clk *clk) +nv40_clk_tidy(struct nvkm_clk *clk) { } static int -nv40_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { struct nv40_clk_priv *priv; int ret; - ret = nouveau_clk_create(parent, engine, oclass, nv40_domain, NULL, 0, - true, &priv); + ret = nvkm_clk_create(parent, engine, oclass, nv40_domain, + NULL, 0, true, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -228,13 +229,13 @@ nv40_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass +struct nvkm_oclass nv40_clk_oclass = { .handle = NV_SUBDEV(CLK, 0x40), - .ofuncs = &(struct nouveau_ofuncs) { + .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv40_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 3c462a24922c..9b4ffd6347ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -21,14 +21,14 @@ * * Authors: Ben Skeggs */ - -#include -#include - #include "nv50.h" #include "pll.h" #include "seq.h" +#include +#include +#include + static u32 read_div(struct nv50_clk_priv *priv) { @@ -51,7 +51,7 @@ read_div(struct nv50_clk_priv *priv) static u32 read_pll_src(struct nv50_clk_priv *priv, u32 base) { - struct nouveau_clk *clk = &priv->base; + struct nvkm_clk *clk = &priv->base; u32 coef, ref = clk->read(clk, nv_clk_src_crystal); u32 rsel = nv_rd32(priv, 0x00e18c); int P, N, M, id; @@ -116,13 +116,14 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) if (M) return (ref * N / M) >> P; + return 0; } static u32 read_pll_ref(struct nv50_clk_priv *priv, u32 base) { - struct nouveau_clk *clk = &priv->base; + struct nvkm_clk *clk = &priv->base; u32 src, mast = nv_rd32(priv, 0x00c040); switch (base) { @@ -147,13 +148,14 @@ read_pll_ref(struct nv50_clk_priv *priv, u32 base) if (src) return clk->read(clk, nv_clk_src_href); + return read_pll_src(priv, base); } static u32 read_pll(struct nv50_clk_priv *priv, u32 base) { - struct nouveau_clk *clk = &priv->base; + struct nvkm_clk *clk = &priv->base; u32 mast = nv_rd32(priv, 0x00c040); u32 ctrl = nv_rd32(priv, base + 0); u32 coef = nv_rd32(priv, base + 4); @@ -162,7 +164,7 @@ read_pll(struct nv50_clk_priv *priv, u32 base) int N1, N2, M1, M2; if (base == 0x004028 && (mast & 0x00100000)) { - /* wtf, appears to only disable post-divider on nva0 */ + /* wtf, appears to only disable post-divider on gt200 */ if (nv_device(priv)->chipset != 0xa0) return clk->read(clk, nv_clk_src_dom6); } @@ -185,7 +187,7 @@ read_pll(struct nv50_clk_priv *priv, u32 base) } static int -nv50_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) +nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) { struct nv50_clk_priv *priv = (void *)clk; u32 mast = nv_rd32(priv, 0x00c040); @@ -318,7 +320,7 @@ nv50_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) static u32 calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P) { - struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_bios *bios = nvkm_bios(priv); struct nvbios_pll pll; int ret; @@ -359,7 +361,7 @@ clk_same(u32 a, u32 b) } static int -nv50_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) +nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) { struct nv50_clk_priv *priv = (void *)clk; struct nv50_clk_hwsq *hwsq = &priv->hwsq; @@ -484,30 +486,30 @@ nv50_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) } static int -nv50_clk_prog(struct nouveau_clk *clk) +nv50_clk_prog(struct nvkm_clk *clk) { struct nv50_clk_priv *priv = (void *)clk; return clk_exec(&priv->hwsq, true); } static void -nv50_clk_tidy(struct nouveau_clk *clk) +nv50_clk_tidy(struct nvkm_clk *clk) { struct nv50_clk_priv *priv = (void *)clk; clk_exec(&priv->hwsq, false); } int -nv50_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { struct nv50_clk_oclass *pclass = (void *)oclass; struct nv50_clk_priv *priv; int ret; - ret = nouveau_clk_create(parent, engine, oclass, pclass->domains, - NULL, 0, false, &priv); + ret = nvkm_clk_create(parent, engine, oclass, pclass->domains, + NULL, 0, false, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -536,7 +538,7 @@ nv50_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static struct nouveau_domain +static struct nvkm_domain nv50_domains[] = { { nv_clk_src_crystal, 0xff }, { nv_clk_src_href , 0xff }, @@ -546,14 +548,14 @@ nv50_domains[] = { { nv_clk_src_max } }; -struct nouveau_oclass * +struct nvkm_oclass * nv50_clk_oclass = &(struct nv50_clk_oclass) { .base.handle = NV_SUBDEV(CLK, 0x50), - .base.ofuncs = &(struct nouveau_ofuncs) { + .base.ofuncs = &(struct nvkm_ofuncs) { .ctor = nv50_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, + .dtor = _nvkm_clk_dtor, + .init = _nvkm_clk_init, + .fini = _nvkm_clk_fini, }, .domains = nv50_domains, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h index ae6421fd28f4..0ead76a32f10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h @@ -1,7 +1,5 @@ #ifndef __NVKM_CLK_NV50_H__ #define __NVKM_CLK_NV50_H__ - -#include #include #include @@ -15,17 +13,16 @@ struct nv50_clk_hwsq { }; struct nv50_clk_priv { - struct nouveau_clk base; + struct nvkm_clk base; struct nv50_clk_hwsq hwsq; }; -int nv50_clk_ctor(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, void *, u32, - struct nouveau_object **); +int nv50_clk_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *, u32, + struct nvkm_object **); struct nv50_clk_oclass { - struct nouveau_oclass base; - struct nouveau_domain *domains; + struct nvkm_oclass base; + struct nvkm_domain *domains; }; - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv84.c deleted file mode 100644 index b5b00b3df6c4..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv84.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 "nv50.h" - -static struct nouveau_domain -nv84_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0xff }, - { nv_clk_src_max } -}; - -struct nouveau_oclass * -nv84_clk_oclass = &(struct nv50_clk_oclass) { - .base.handle = NV_SUBDEV(CLK, 0x84), - .base.ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, - }, - .domains = nv84_domains, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.c deleted file mode 100644 index 3002c60a3993..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright 2012 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 - * Roy Spliet - */ - -#include -#include -#include -#include - -#include "pll.h" - -#include "nva3.h" - -struct nva3_clk_priv { - struct nouveau_clk base; - struct nva3_clk_info eng[nv_clk_src_max]; -}; - -static u32 read_clk(struct nva3_clk_priv *, int, bool); -static u32 read_pll(struct nva3_clk_priv *, int, u32); - -static u32 -read_vco(struct nva3_clk_priv *priv, int clk) -{ - u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); - - switch (sctl & 0x00000030) { - case 0x00000000: - return nv_device(priv)->crystal; - case 0x00000020: - return read_pll(priv, 0x41, 0x00e820); - case 0x00000030: - return read_pll(priv, 0x42, 0x00e8a0); - default: - return 0; - } -} - -static u32 -read_clk(struct nva3_clk_priv *priv, int clk, bool ignore_en) -{ - u32 sctl, sdiv, sclk; - - /* refclk for the 0xe8xx plls is a fixed frequency */ - if (clk >= 0x40) { - if (nv_device(priv)->chipset == 0xaf) { - /* no joke.. seriously.. sigh.. */ - return nv_rd32(priv, 0x00471c) * 1000; - } - - return nv_device(priv)->crystal; - } - - sctl = nv_rd32(priv, 0x4120 + (clk * 4)); - if (!ignore_en && !(sctl & 0x00000100)) - return 0; - - /* out_alt */ - if (sctl & 0x00000400) - return 108000; - - /* vco_out */ - switch (sctl & 0x00003000) { - case 0x00000000: - if (!(sctl & 0x00000200)) - return nv_device(priv)->crystal; - return 0; - case 0x00002000: - if (sctl & 0x00000040) - return 108000; - return 100000; - case 0x00003000: - /* vco_enable */ - if (!(sctl & 0x00000001)) - return 0; - - sclk = read_vco(priv, clk); - sdiv = ((sctl & 0x003f0000) >> 16) + 2; - return (sclk * 2) / sdiv; - default: - return 0; - } -} - -static u32 -read_pll(struct nva3_clk_priv *priv, int clk, u32 pll) -{ - u32 ctrl = nv_rd32(priv, pll + 0); - u32 sclk = 0, P = 1, N = 1, M = 1; - - if (!(ctrl & 0x00000008)) { - if (ctrl & 0x00000001) { - u32 coef = nv_rd32(priv, pll + 4); - M = (coef & 0x000000ff) >> 0; - N = (coef & 0x0000ff00) >> 8; - P = (coef & 0x003f0000) >> 16; - - /* no post-divider on these.. - * XXX: it looks more like two post-"dividers" that - * cross each other out in the default RPLL config */ - if ((pll & 0x00ff00) == 0x00e800) - P = 1; - - sclk = read_clk(priv, 0x00 + clk, false); - } - } else { - sclk = read_clk(priv, 0x10 + clk, false); - } - - if (M * P) - return sclk * N / (M * P); - return 0; -} - -static int -nva3_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) -{ - struct nva3_clk_priv *priv = (void *)clk; - u32 hsrc; - - switch (src) { - case nv_clk_src_crystal: - return nv_device(priv)->crystal; - case nv_clk_src_core: - case nv_clk_src_core_intm: - return read_pll(priv, 0x00, 0x4200); - case nv_clk_src_shader: - return read_pll(priv, 0x01, 0x4220); - case nv_clk_src_mem: - return read_pll(priv, 0x02, 0x4000); - case nv_clk_src_disp: - return read_clk(priv, 0x20, false); - case nv_clk_src_vdec: - return read_clk(priv, 0x21, false); - case nv_clk_src_daemon: - return read_clk(priv, 0x25, false); - case nv_clk_src_host: - hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28; - switch (hsrc) { - case 0: - return read_clk(priv, 0x1d, false); - case 2: - case 3: - return 277000; - default: - nv_error(clk, "unknown HOST clock source %d\n", hsrc); - return -EINVAL; - } - default: - nv_error(clk, "invalid clock source %d\n", src); - return -EINVAL; - } - - return 0; -} - -int -nva3_clk_info(struct nouveau_clk *clock, int clk, u32 khz, - struct nva3_clk_info *info) -{ - struct nva3_clk_priv *priv = (void *)clock; - u32 oclk, sclk, sdiv, diff; - - info->clk = 0; - - switch (khz) { - case 27000: - info->clk = 0x00000100; - return khz; - case 100000: - info->clk = 0x00002100; - return khz; - case 108000: - info->clk = 0x00002140; - return khz; - default: - sclk = read_vco(priv, clk); - sdiv = min((sclk * 2) / khz, (u32)65); - oclk = (sclk * 2) / sdiv; - diff = ((khz + 3000) - oclk); - - /* When imprecise, play it safe and aim for a clock lower than - * desired rather than higher */ - if (diff < 0) { - sdiv++; - oclk = (sclk * 2) / sdiv; - } - - /* divider can go as low as 2, limited here because NVIDIA - * and the VBIOS on my NVA8 seem to prefer using the PLL - * for 810MHz - is there a good reason? - * XXX: PLLs with refclk 810MHz? */ - if (sdiv > 4) { - info->clk = (((sdiv - 2) << 16) | 0x00003100); - return oclk; - } - - break; - } - - return -ERANGE; -} - -int -nva3_pll_info(struct nouveau_clk *clock, int clk, u32 pll, u32 khz, - struct nva3_clk_info *info) -{ - struct nouveau_bios *bios = nouveau_bios(clock); - struct nva3_clk_priv *priv = (void *)clock; - struct nvbios_pll limits; - int P, N, M, diff; - int ret; - - info->pll = 0; - - /* If we can get a within [-2, 3) MHz of a divider, we'll disable the - * PLL and use the divider instead. */ - ret = nva3_clk_info(clock, clk, khz, info); - diff = khz - ret; - if (!pll || (diff >= -2000 && diff < 3000)) { - goto out; - } - - /* Try with PLL */ - ret = nvbios_pll_parse(bios, pll, &limits); - if (ret) - return ret; - - ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info); - if (ret != limits.refclk) - return -EINVAL; - - ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); - if (ret >= 0) { - info->pll = (P << 16) | (N << 8) | M; - } - -out: - info->fb_delay = max(((khz + 7566) / 15133), (u32) 18); - - return ret ? ret : -ERANGE; -} - -static int -calc_clk(struct nva3_clk_priv *priv, struct nouveau_cstate *cstate, - int clk, u32 pll, int idx) -{ - int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx], - &priv->eng[idx]); - if (ret >= 0) - return 0; - return ret; -} - -static int -calc_host(struct nva3_clk_priv *priv, struct nouveau_cstate *cstate) -{ - int ret = 0; - u32 kHz = cstate->domain[nv_clk_src_host]; - struct nva3_clk_info *info = &priv->eng[nv_clk_src_host]; - - if (kHz == 277000) { - info->clk = 0; - info->host_out = NVA3_HOST_277; - return 0; - } - - info->host_out = NVA3_HOST_CLK; - - ret = nva3_clk_info(&priv->base, 0x1d, kHz, info); - if (ret >= 0) - return 0; - return ret; -} - -int -nva3_clk_pre(struct nouveau_clk *clk, unsigned long *flags) -{ - struct nouveau_fifo *pfifo = nouveau_fifo(clk); - - /* halt and idle execution engines */ - nv_mask(clk, 0x020060, 0x00070000, 0x00000000); - nv_mask(clk, 0x002504, 0x00000001, 0x00000001); - /* Wait until the interrupt handler is finished */ - if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) - return -EBUSY; - - if (pfifo) - pfifo->pause(pfifo, flags); - - if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) - return -EIO; - if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) - return -EIO; - - return 0; -} - -void -nva3_clk_post(struct nouveau_clk *clk, unsigned long *flags) -{ - struct nouveau_fifo *pfifo = nouveau_fifo(clk); - - if (pfifo && flags) - pfifo->start(pfifo, flags); - - nv_mask(clk, 0x002504, 0x00000001, 0x00000000); - nv_mask(clk, 0x020060, 0x00070000, 0x00040000); -} - -static void -disable_clk_src(struct nva3_clk_priv *priv, u32 src) -{ - nv_mask(priv, src, 0x00000100, 0x00000000); - nv_mask(priv, src, 0x00000001, 0x00000000); -} - -static void -prog_pll(struct nva3_clk_priv *priv, int clk, u32 pll, int idx) -{ - struct nva3_clk_info *info = &priv->eng[idx]; - const u32 src0 = 0x004120 + (clk * 4); - const u32 src1 = 0x004160 + (clk * 4); - const u32 ctrl = pll + 0; - const u32 coef = pll + 4; - u32 bypass; - - if (info->pll) { - /* Always start from a non-PLL clock */ - bypass = nv_rd32(priv, ctrl) & 0x00000008; - if (!bypass) { - nv_mask(priv, src1, 0x00000101, 0x00000101); - nv_mask(priv, ctrl, 0x00000008, 0x00000008); - udelay(20); - } - - nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); - nv_wr32(priv, coef, info->pll); - nv_mask(priv, ctrl, 0x00000015, 0x00000015); - nv_mask(priv, ctrl, 0x00000010, 0x00000000); - if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) { - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, src0, 0x00000101, 0x00000000); - return; - } - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, ctrl, 0x00000008, 0x00000000); - disable_clk_src(priv, src1); - } else { - nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk); - nv_mask(priv, ctrl, 0x00000018, 0x00000018); - udelay(20); - nv_mask(priv, ctrl, 0x00000001, 0x00000000); - disable_clk_src(priv, src0); - } -} - -static void -prog_clk(struct nva3_clk_priv *priv, int clk, int idx) -{ - struct nva3_clk_info *info = &priv->eng[idx]; - nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); -} - -static void -prog_host(struct nva3_clk_priv *priv) -{ - struct nva3_clk_info *info = &priv->eng[nv_clk_src_host]; - u32 hsrc = (nv_rd32(priv, 0xc040)); - - switch (info->host_out) { - case NVA3_HOST_277: - if ((hsrc & 0x30000000) == 0) { - nv_wr32(priv, 0xc040, hsrc | 0x20000000); - disable_clk_src(priv, 0x4194); - } - break; - case NVA3_HOST_CLK: - prog_clk(priv, 0x1d, nv_clk_src_host); - if ((hsrc & 0x30000000) >= 0x20000000) { - nv_wr32(priv, 0xc040, hsrc & ~0x30000000); - } - break; - default: - break; - } - - /* This seems to be a clock gating factor on idle, always set to 64 */ - nv_wr32(priv, 0xc044, 0x3e); -} - -static void -prog_core(struct nva3_clk_priv *priv, int idx) -{ - struct nva3_clk_info *info = &priv->eng[idx]; - u32 fb_delay = nv_rd32(priv, 0x10002c); - - if (fb_delay < info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); - - prog_pll(priv, 0x00, 0x004200, idx); - - if (fb_delay > info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); -} - -static int -nva3_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) -{ - struct nva3_clk_priv *priv = (void *)clk; - struct nva3_clk_info *core = &priv->eng[nv_clk_src_core]; - int ret; - - if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || - (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) || - (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) || - (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || - (ret = calc_host(priv, cstate))) - return ret; - - /* XXX: Should be reading the highest bit in the VBIOS clock to decide - * whether to use a PLL or not... but using a PLL defeats the purpose */ - if (core->pll) { - ret = nva3_clk_info(clk, 0x10, - cstate->domain[nv_clk_src_core_intm], - &priv->eng[nv_clk_src_core_intm]); - if (ret < 0) - return ret; - } - - return 0; -} - -static int -nva3_clk_prog(struct nouveau_clk *clk) -{ - struct nva3_clk_priv *priv = (void *)clk; - struct nva3_clk_info *core = &priv->eng[nv_clk_src_core]; - int ret = 0; - unsigned long flags; - unsigned long *f = &flags; - - ret = nva3_clk_pre(clk, f); - if (ret) - goto out; - - if (core->pll) - prog_core(priv, nv_clk_src_core_intm); - - prog_core(priv, nv_clk_src_core); - prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); - prog_clk(priv, 0x20, nv_clk_src_disp); - prog_clk(priv, 0x21, nv_clk_src_vdec); - prog_host(priv); - -out: - if (ret == -EBUSY) - f = NULL; - - nva3_clk_post(clk, f); - - return ret; -} - -static void -nva3_clk_tidy(struct nouveau_clk *clk) -{ -} - -static struct nouveau_domain -nva3_domain[] = { - { nv_clk_src_crystal , 0xff }, - { nv_clk_src_core , 0x00, 0, "core", 1000 }, - { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, - { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x03 }, - { nv_clk_src_disp , 0x04 }, - { nv_clk_src_host , 0x05 }, - { nv_clk_src_core_intm, 0x06 }, - { nv_clk_src_max } -}; - -static int -nva3_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nva3_clk_priv *priv; - int ret; - - ret = nouveau_clk_create(parent, engine, oclass, nva3_domain, NULL, 0, - true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.read = nva3_clk_read; - priv->base.calc = nva3_clk_calc; - priv->base.prog = nva3_clk_prog; - priv->base.tidy = nva3_clk_tidy; - return 0; -} - -struct nouveau_oclass -nva3_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xa3), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nva3_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.h deleted file mode 100644 index ce0fc83345e3..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nva3.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __NVKM_CLK_NVA3_H__ -#define __NVKM_CLK_NVA3_H__ - -#include - -struct nva3_clk_info { - u32 clk; - u32 pll; - enum { - NVA3_HOST_277, - NVA3_HOST_CLK, - } host_out; - u32 fb_delay; -}; - -int nva3_pll_info(struct nouveau_clk *, int, u32, u32, - struct nva3_clk_info *); -int nva3_clk_pre(struct nouveau_clk *clk, unsigned long *flags); -void nva3_clk_post(struct nouveau_clk *clk, unsigned long *flags); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvaa.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvaa.c deleted file mode 100644 index d6d2bd190144..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvaa.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright 2012 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 -#include -#include -#include -#include - -#include "nva3.h" -#include "pll.h" - -struct nvaa_clk_priv { - struct nouveau_clk base; - enum nv_clk_src csrc, ssrc, vsrc; - u32 cctrl, sctrl; - u32 ccoef, scoef; - u32 cpost, spost; - u32 vdiv; -}; - -static u32 -read_div(struct nouveau_clk *clk) -{ - return nv_rd32(clk, 0x004600); -} - -static u32 -read_pll(struct nouveau_clk *clk, u32 base) -{ - u32 ctrl = nv_rd32(clk, base + 0); - u32 coef = nv_rd32(clk, base + 4); - u32 ref = clk->read(clk, nv_clk_src_href); - u32 post_div = 0; - u32 clock = 0; - int N1, M1; - - switch (base){ - case 0x4020: - post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); - break; - case 0x4028: - post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; - break; - default: - break; - } - - N1 = (coef & 0x0000ff00) >> 8; - M1 = (coef & 0x000000ff); - if ((ctrl & 0x80000000) && M1) { - clock = ref * N1 / M1; - clock = clock / post_div; - } - - return clock; -} - -static int -nvaa_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) -{ - struct nvaa_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(clk, 0x00c054); - u32 P = 0; - - switch (src) { - case nv_clk_src_crystal: - return nv_device(priv)->crystal; - case nv_clk_src_href: - return 100000; /* PCIE reference clock */ - case nv_clk_src_hclkm4: - return clk->read(clk, nv_clk_src_href) * 4; - case nv_clk_src_hclkm2d3: - return clk->read(clk, nv_clk_src_href) * 2 / 3; - case nv_clk_src_host: - switch (mast & 0x000c0000) { - case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); - case 0x00040000: break; - case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); - case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); - } - break; - case nv_clk_src_core: - P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; - - switch (mast & 0x00000003) { - case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; - case 0x00000001: return 0; - case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; - case 0x00000003: return read_pll(clk, 0x004028) >> P; - } - break; - case nv_clk_src_cclk: - if ((mast & 0x03000000) != 0x03000000) - return clk->read(clk, nv_clk_src_core); - - if ((mast & 0x00000200) == 0x00000000) - return clk->read(clk, nv_clk_src_core); - - switch (mast & 0x00000c00) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); - case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); - case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); - default: return 0; - } - case nv_clk_src_shader: - P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; - switch (mast & 0x00000030) { - case 0x00000000: - if (mast & 0x00000040) - return clk->read(clk, nv_clk_src_href) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; - case 0x00000010: break; - case 0x00000020: return read_pll(clk, 0x004028) >> P; - case 0x00000030: return read_pll(clk, 0x004020) >> P; - } - break; - case nv_clk_src_mem: - return 0; - break; - case nv_clk_src_vdec: - P = (read_div(clk) & 0x00000700) >> 8; - - switch (mast & 0x00400000) { - case 0x00400000: - return clk->read(clk, nv_clk_src_core) >> P; - break; - default: - return 500000 >> P; - break; - } - break; - default: - break; - } - - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); - return 0; -} - -static u32 -calc_pll(struct nvaa_clk_priv *priv, u32 reg, - u32 clock, int *N, int *M, int *P) -{ - struct nouveau_bios *bios = nouveau_bios(priv); - struct nvbios_pll pll; - struct nouveau_clk *clk = &priv->base; - int ret; - - ret = nvbios_pll_parse(bios, reg, &pll); - if (ret) - return 0; - - pll.vco2.max_freq = 0; - pll.refclk = clk->read(clk, nv_clk_src_href); - if (!pll.refclk) - return 0; - - return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); -} - -static inline u32 -calc_P(u32 src, u32 target, int *div) -{ - u32 clk0 = src, clk1 = src; - for (*div = 0; *div <= 7; (*div)++) { - if (clk0 <= target) { - clk1 = clk0 << (*div ? 1 : 0); - break; - } - clk0 >>= 1; - } - - if (target - clk0 <= clk1 - target) - return clk0; - (*div)--; - return clk1; -} - -static int -nvaa_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) -{ - struct nvaa_clk_priv *priv = (void *)clk; - const int shader = cstate->domain[nv_clk_src_shader]; - const int core = cstate->domain[nv_clk_src_core]; - const int vdec = cstate->domain[nv_clk_src_vdec]; - u32 out = 0, clock = 0; - int N, M, P1, P2 = 0; - int divs = 0; - - /* cclk: find suitable source, disable PLL if we can */ - if (core < clk->read(clk, nv_clk_src_hclkm4)) - out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); - - /* Calculate clock * 2, so shader clock can use it too */ - clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); - - if (abs(core - out) <= - abs(core - (clock >> 1))) { - priv->csrc = nv_clk_src_hclkm4; - priv->cctrl = divs << 16; - } else { - /* NVCTRL is actually used _after_ NVPOST, and after what we - * call NVPLL. To make matters worse, NVPOST is an integer - * divider instead of a right-shift number. */ - if(P1 > 2) { - P2 = P1 - 2; - P1 = 2; - } - - priv->csrc = nv_clk_src_core; - priv->ccoef = (N << 8) | M; - - priv->cctrl = (P2 + 1) << 16; - priv->cpost = (1 << P1) << 16; - } - - /* sclk: nvpll + divisor, href or spll */ - out = 0; - if (shader == clk->read(clk, nv_clk_src_href)) { - priv->ssrc = nv_clk_src_href; - } else { - clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); - if (priv->csrc == nv_clk_src_core) { - out = calc_P((core << 1), shader, &divs); - } - - if (abs(shader - out) <= - abs(shader - clock) && - (divs + P2) <= 7) { - priv->ssrc = nv_clk_src_core; - priv->sctrl = (divs + P2) << 16; - } else { - priv->ssrc = nv_clk_src_shader; - priv->scoef = (N << 8) | M; - priv->sctrl = P1 << 16; - } - } - - /* vclk */ - out = calc_P(core, vdec, &divs); - clock = calc_P(500000, vdec, &P1); - if(abs(vdec - out) <= - abs(vdec - clock)) { - priv->vsrc = nv_clk_src_cclk; - priv->vdiv = divs << 16; - } else { - priv->vsrc = nv_clk_src_vdec; - priv->vdiv = P1 << 16; - } - - /* Print strategy! */ - nv_debug(priv, "nvpll: %08x %08x %08x\n", - priv->ccoef, priv->cpost, priv->cctrl); - nv_debug(priv, " spll: %08x %08x %08x\n", - priv->scoef, priv->spost, priv->sctrl); - nv_debug(priv, " vdiv: %08x\n", priv->vdiv); - if (priv->csrc == nv_clk_src_hclkm4) - nv_debug(priv, "core: hrefm4\n"); - else - nv_debug(priv, "core: nvpll\n"); - - if (priv->ssrc == nv_clk_src_hclkm4) - nv_debug(priv, "shader: hrefm4\n"); - else if (priv->ssrc == nv_clk_src_core) - nv_debug(priv, "shader: nvpll\n"); - else - nv_debug(priv, "shader: spll\n"); - - if (priv->vsrc == nv_clk_src_hclkm4) - nv_debug(priv, "vdec: 500MHz\n"); - else - nv_debug(priv, "vdec: core\n"); - - return 0; -} - -static int -nvaa_clk_prog(struct nouveau_clk *clk) -{ - struct nvaa_clk_priv *priv = (void *)clk; - u32 pllmask = 0, mast; - unsigned long flags; - unsigned long *f = &flags; - int ret = 0; - - ret = nva3_clk_pre(clk, f); - if (ret) - goto out; - - /* First switch to safe clocks: href */ - mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); - mast &= ~0x00400e73; - mast |= 0x03000000; - - switch (priv->csrc) { - case nv_clk_src_hclkm4: - nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); - mast |= 0x00000002; - break; - case nv_clk_src_core: - nv_wr32(clk, 0x402c, priv->ccoef); - nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); - nv_wr32(clk, 0x4040, priv->cpost); - pllmask |= (0x3 << 8); - mast |= 0x00000003; - break; - default: - nv_warn(priv,"Reclocking failed: unknown core clock\n"); - goto resume; - } - - switch (priv->ssrc) { - case nv_clk_src_href: - nv_mask(clk, 0x4020, 0x00070000, 0x00000000); - /* mast |= 0x00000000; */ - break; - case nv_clk_src_core: - nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); - mast |= 0x00000020; - break; - case nv_clk_src_shader: - nv_wr32(clk, 0x4024, priv->scoef); - nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); - nv_wr32(clk, 0x4070, priv->spost); - pllmask |= (0x3 << 12); - mast |= 0x00000030; - break; - default: - nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); - goto resume; - } - - if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { - nv_warn(priv,"Reclocking failed: unstable PLLs\n"); - goto resume; - } - - switch (priv->vsrc) { - case nv_clk_src_cclk: - mast |= 0x00400000; - default: - nv_wr32(clk, 0x4600, priv->vdiv); - } - - nv_wr32(clk, 0xc054, mast); - -resume: - /* Disable some PLLs and dividers when unused */ - if (priv->csrc != nv_clk_src_core) { - nv_wr32(clk, 0x4040, 0x00000000); - nv_mask(clk, 0x4028, 0x80000000, 0x00000000); - } - - if (priv->ssrc != nv_clk_src_shader) { - nv_wr32(clk, 0x4070, 0x00000000); - nv_mask(clk, 0x4020, 0x80000000, 0x00000000); - } - -out: - if (ret == -EBUSY) - f = NULL; - - nva3_clk_post(clk, f); - - return ret; -} - -static void -nvaa_clk_tidy(struct nouveau_clk *clk) -{ -} - -static struct nouveau_domain -nvaa_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, - { nv_clk_src_max } -}; - -static int -nvaa_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvaa_clk_priv *priv; - int ret; - - ret = nouveau_clk_create(parent, engine, oclass, nvaa_domains, NULL, - 0, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.read = nvaa_clk_read; - priv->base.calc = nvaa_clk_calc; - priv->base.prog = nvaa_clk_prog; - priv->base.tidy = nvaa_clk_tidy; - return 0; -} - -struct nouveau_oclass * -nvaa_clk_oclass = &(struct nouveau_oclass) { - .handle = NV_SUBDEV(CLK, 0xaa), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvaa_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvc0.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvc0.c deleted file mode 100644 index 791a9f5198eb..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nvc0.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright 2012 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 -#include -#include -#include - -#include "pll.h" - -struct nvc0_clk_info { - u32 freq; - u32 ssel; - u32 mdiv; - u32 dsrc; - u32 ddiv; - u32 coef; -}; - -struct nvc0_clk_priv { - struct nouveau_clk base; - struct nvc0_clk_info eng[16]; -}; - -static u32 read_div(struct nvc0_clk_priv *, int, u32, u32); - -static u32 -read_vco(struct nvc0_clk_priv *priv, u32 dsrc) -{ - struct nouveau_clk *clk = &priv->base; - u32 ssrc = nv_rd32(priv, dsrc); - if (!(ssrc & 0x00000100)) - return clk->read(clk, nv_clk_src_sppll0); - return clk->read(clk, nv_clk_src_sppll1); -} - -static u32 -read_pll(struct nvc0_clk_priv *priv, u32 pll) -{ - struct nouveau_clk *clk = &priv->base; - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); - u32 P = (coef & 0x003f0000) >> 16; - u32 N = (coef & 0x0000ff00) >> 8; - u32 M = (coef & 0x000000ff) >> 0; - u32 sclk; - - if (!(ctrl & 0x00000001)) - return 0; - - switch (pll) { - case 0x00e800: - case 0x00e820: - sclk = nv_device(priv)->crystal; - P = 1; - break; - case 0x132000: - sclk = clk->read(clk, nv_clk_src_mpllsrc); - break; - case 0x132020: - sclk = clk->read(clk, nv_clk_src_mpllsrcref); - break; - case 0x137000: - case 0x137020: - case 0x137040: - case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); - break; - default: - return 0; - } - - return sclk * N / M / P; -} - -static u32 -read_div(struct nvc0_clk_priv *priv, int doff, u32 dsrc, u32 dctl) -{ - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); - - switch (ssrc & 0x00000003) { - case 0: - if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; - return 108000; - case 2: - return 100000; - case 3: - if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); - u32 sdiv = (sctl & 0x0000003f) + 2; - return (sclk * 2) / sdiv; - } - - return read_vco(priv, dsrc + (doff * 4)); - default: - return 0; - } -} - -static u32 -read_clk(struct nvc0_clk_priv *priv, int clk) -{ - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); - u32 ssel = nv_rd32(priv, 0x137100); - u32 sclk, sdiv; - - if (ssel & (1 << clk)) { - if (clk < 7) - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); - else - sclk = read_pll(priv, 0x1370e0); - sdiv = ((sctl & 0x00003f00) >> 8) + 2; - } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); - sdiv = ((sctl & 0x0000003f) >> 0) + 2; - } - - if (sctl & 0x80000000) - return (sclk * 2) / sdiv; - - return sclk; -} - -static int -nvc0_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) -{ - struct nouveau_device *device = nv_device(clk); - struct nvc0_clk_priv *priv = (void *)clk; - - switch (src) { - case nv_clk_src_crystal: - return device->crystal; - case nv_clk_src_href: - return 100000; - case nv_clk_src_sppll0: - return read_pll(priv, 0x00e800); - case nv_clk_src_sppll1: - return read_pll(priv, 0x00e820); - - case nv_clk_src_mpllsrcref: - return read_div(priv, 0, 0x137320, 0x137330); - case nv_clk_src_mpllsrc: - return read_pll(priv, 0x132020); - case nv_clk_src_mpll: - return read_pll(priv, 0x132000); - case nv_clk_src_mdiv: - return read_div(priv, 0, 0x137300, 0x137310); - case nv_clk_src_mem: - if (nv_rd32(priv, 0x1373f0) & 0x00000002) - return clk->read(clk, nv_clk_src_mpll); - return clk->read(clk, nv_clk_src_mdiv); - - case nv_clk_src_gpc: - return read_clk(priv, 0x00); - case nv_clk_src_rop: - return read_clk(priv, 0x01); - case nv_clk_src_hubk07: - return read_clk(priv, 0x02); - case nv_clk_src_hubk06: - return read_clk(priv, 0x07); - case nv_clk_src_hubk01: - return read_clk(priv, 0x08); - case nv_clk_src_copy: - return read_clk(priv, 0x09); - case nv_clk_src_daemon: - return read_clk(priv, 0x0c); - case nv_clk_src_vdec: - return read_clk(priv, 0x0e); - default: - nv_error(clk, "invalid clock source %d\n", src); - return -EINVAL; - } -} - -static u32 -calc_div(struct nvc0_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) -{ - u32 div = min((ref * 2) / freq, (u32)65); - if (div < 2) - div = 2; - - *ddiv = div - 2; - return (ref * 2) / div; -} - -static u32 -calc_src(struct nvc0_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) -{ - u32 sclk; - - /* use one of the fixed frequencies if possible */ - *ddiv = 0x00000000; - switch (freq) { - case 27000: - case 108000: - *dsrc = 0x00000000; - if (freq == 108000) - *dsrc |= 0x00030000; - return freq; - case 100000: - *dsrc = 0x00000002; - return freq; - default: - *dsrc = 0x00000003; - break; - } - - /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); - return sclk; -} - -static u32 -calc_pll(struct nvc0_clk_priv *priv, int clk, u32 freq, u32 *coef) -{ - struct nouveau_bios *bios = nouveau_bios(priv); - struct nvbios_pll limits; - int N, M, P, ret; - - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); - if (ret) - return 0; - - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); - if (!limits.refclk) - return 0; - - ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); - if (ret <= 0) - return 0; - - *coef = (P << 16) | (N << 8) | M; - return ret; -} - -static int -calc_clk(struct nvc0_clk_priv *priv, - struct nouveau_cstate *cstate, int clk, int dom) -{ - struct nvc0_clk_info *info = &priv->eng[clk]; - u32 freq = cstate->domain[dom]; - u32 src0, div0, div1D, div1P = 0; - u32 clk0, clk1 = 0; - - /* invalid clock domain */ - if (!freq) - return 0; - - /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); - - /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x00004387 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); - else - clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); - } - - /* select the method which gets closest to target freq */ - if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { - info->dsrc = src0; - if (div0) { - info->ddiv |= 0x80000000; - info->ddiv |= div0 << 8; - info->ddiv |= div0; - } - if (div1D) { - info->mdiv |= 0x80000000; - info->mdiv |= div1D; - } - info->ssel = info->coef = 0; - info->freq = clk0; - } else { - if (div1P) { - info->mdiv |= 0x80000000; - info->mdiv |= div1P << 8; - } - info->ssel = (1 << clk); - info->freq = clk1; - } - - return 0; -} - -static int -nvc0_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) -{ - struct nvc0_clk_priv *priv = (void *)clk; - int ret; - - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) - return ret; - - return 0; -} - -static void -nvc0_clk_prog_0(struct nvc0_clk_priv *priv, int clk) -{ - struct nvc0_clk_info *info = &priv->eng[clk]; - if (clk < 7 && !info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); - } -} - -static void -nvc0_clk_prog_1(struct nvc0_clk_priv *priv, int clk) -{ - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); -} - -static void -nvc0_clk_prog_2(struct nvc0_clk_priv *priv, int clk) -{ - struct nvc0_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - if (clk <= 7) { - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); - if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); - } - } -} - -static void -nvc0_clk_prog_3(struct nvc0_clk_priv *priv, int clk) -{ - struct nvc0_clk_info *info = &priv->eng[clk]; - if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); - } -} - -static void -nvc0_clk_prog_4(struct nvc0_clk_priv *priv, int clk) -{ - struct nvc0_clk_info *info = &priv->eng[clk]; - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); -} - -static int -nvc0_clk_prog(struct nouveau_clk *clk) -{ - struct nvc0_clk_priv *priv = (void *)clk; - struct { - void (*exec)(struct nvc0_clk_priv *, int); - } stage[] = { - { nvc0_clk_prog_0 }, /* div programming */ - { nvc0_clk_prog_1 }, /* select div mode */ - { nvc0_clk_prog_2 }, /* (maybe) program pll */ - { nvc0_clk_prog_3 }, /* (maybe) select pll mode */ - { nvc0_clk_prog_4 }, /* final divider */ - }; - int i, j; - - for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { - if (!priv->eng[j].freq) - continue; - stage[i].exec(priv, j); - } - } - - return 0; -} - -static void -nvc0_clk_tidy(struct nouveau_clk *clk) -{ - struct nvc0_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); -} - -static struct nouveau_domain -nvc0_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_hubk06 , 0x00 }, - { nv_clk_src_hubk01 , 0x01 }, - { nv_clk_src_copy , 0x02 }, - { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, - { nv_clk_src_rop , 0x04 }, - { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x0a }, - { nv_clk_src_hubk07 , 0x0b }, - { nv_clk_src_max } -}; - -static int -nvc0_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_clk_priv *priv; - int ret; - - ret = nouveau_clk_create(parent, engine, oclass, nvc0_domain, NULL, 0, - false, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.read = nvc0_clk_read; - priv->base.calc = nvc0_clk_calc; - priv->base.prog = nvc0_clk_prog; - priv->base.tidy = nvc0_clk_tidy; - return 0; -} - -struct nouveau_oclass -nvc0_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nve0.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nve0.c deleted file mode 100644 index ffd2139e0a49..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nve0.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * 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 -#include -#include -#include - -#include "pll.h" - -struct nve0_clk_info { - u32 freq; - u32 ssel; - u32 mdiv; - u32 dsrc; - u32 ddiv; - u32 coef; -}; - -struct nve0_clk_priv { - struct nouveau_clk base; - struct nve0_clk_info eng[16]; -}; - -static u32 read_div(struct nve0_clk_priv *, int, u32, u32); -static u32 read_pll(struct nve0_clk_priv *, u32); - -static u32 -read_vco(struct nve0_clk_priv *priv, u32 dsrc) -{ - u32 ssrc = nv_rd32(priv, dsrc); - if (!(ssrc & 0x00000100)) - return read_pll(priv, 0x00e800); - return read_pll(priv, 0x00e820); -} - -static u32 -read_pll(struct nve0_clk_priv *priv, u32 pll) -{ - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); - u32 P = (coef & 0x003f0000) >> 16; - u32 N = (coef & 0x0000ff00) >> 8; - u32 M = (coef & 0x000000ff) >> 0; - u32 sclk; - u16 fN = 0xf000; - - if (!(ctrl & 0x00000001)) - return 0; - - switch (pll) { - case 0x00e800: - case 0x00e820: - sclk = nv_device(priv)->crystal; - P = 1; - break; - case 0x132000: - sclk = read_pll(priv, 0x132020); - P = (coef & 0x10000000) ? 2 : 1; - break; - case 0x132020: - sclk = read_div(priv, 0, 0x137320, 0x137330); - fN = nv_rd32(priv, pll + 0x10) >> 16; - break; - case 0x137000: - case 0x137020: - case 0x137040: - case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); - break; - default: - return 0; - } - - if (P == 0) - P = 1; - - sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13); - return sclk / (M * P); -} - -static u32 -read_div(struct nve0_clk_priv *priv, int doff, u32 dsrc, u32 dctl) -{ - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); - - switch (ssrc & 0x00000003) { - case 0: - if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; - return 108000; - case 2: - return 100000; - case 3: - if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); - u32 sdiv = (sctl & 0x0000003f) + 2; - return (sclk * 2) / sdiv; - } - - return read_vco(priv, dsrc + (doff * 4)); - default: - return 0; - } -} - -static u32 -read_mem(struct nve0_clk_priv *priv) -{ - switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) { - case 1: return read_pll(priv, 0x132020); - case 2: return read_pll(priv, 0x132000); - default: - return 0; - } -} - -static u32 -read_clk(struct nve0_clk_priv *priv, int clk) -{ - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); - u32 sclk, sdiv; - - if (clk < 7) { - u32 ssel = nv_rd32(priv, 0x137100); - if (ssel & (1 << clk)) { - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); - sdiv = 1; - } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); - sdiv = 0; - } - } else { - u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04)); - if ((ssrc & 0x00000003) == 0x00000003) { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); - if (ssrc & 0x00000100) { - if (ssrc & 0x40000000) - sclk = read_pll(priv, 0x1370e0); - sdiv = 1; - } else { - sdiv = 0; - } - } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); - sdiv = 0; - } - } - - if (sctl & 0x80000000) { - if (sdiv) - sdiv = ((sctl & 0x00003f00) >> 8) + 2; - else - sdiv = ((sctl & 0x0000003f) >> 0) + 2; - return (sclk * 2) / sdiv; - } - - return sclk; -} - -static int -nve0_clk_read(struct nouveau_clk *clk, enum nv_clk_src src) -{ - struct nouveau_device *device = nv_device(clk); - struct nve0_clk_priv *priv = (void *)clk; - - switch (src) { - case nv_clk_src_crystal: - return device->crystal; - case nv_clk_src_href: - return 100000; - case nv_clk_src_mem: - return read_mem(priv); - case nv_clk_src_gpc: - return read_clk(priv, 0x00); - case nv_clk_src_rop: - return read_clk(priv, 0x01); - case nv_clk_src_hubk07: - return read_clk(priv, 0x02); - case nv_clk_src_hubk06: - return read_clk(priv, 0x07); - case nv_clk_src_hubk01: - return read_clk(priv, 0x08); - case nv_clk_src_daemon: - return read_clk(priv, 0x0c); - case nv_clk_src_vdec: - return read_clk(priv, 0x0e); - default: - nv_error(clk, "invalid clock source %d\n", src); - return -EINVAL; - } -} - -static u32 -calc_div(struct nve0_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) -{ - u32 div = min((ref * 2) / freq, (u32)65); - if (div < 2) - div = 2; - - *ddiv = div - 2; - return (ref * 2) / div; -} - -static u32 -calc_src(struct nve0_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) -{ - u32 sclk; - - /* use one of the fixed frequencies if possible */ - *ddiv = 0x00000000; - switch (freq) { - case 27000: - case 108000: - *dsrc = 0x00000000; - if (freq == 108000) - *dsrc |= 0x00030000; - return freq; - case 100000: - *dsrc = 0x00000002; - return freq; - default: - *dsrc = 0x00000003; - break; - } - - /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); - return sclk; -} - -static u32 -calc_pll(struct nve0_clk_priv *priv, int clk, u32 freq, u32 *coef) -{ - struct nouveau_bios *bios = nouveau_bios(priv); - struct nvbios_pll limits; - int N, M, P, ret; - - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); - if (ret) - return 0; - - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); - if (!limits.refclk) - return 0; - - ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); - if (ret <= 0) - return 0; - - *coef = (P << 16) | (N << 8) | M; - return ret; -} - -static int -calc_clk(struct nve0_clk_priv *priv, - struct nouveau_cstate *cstate, int clk, int dom) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - u32 freq = cstate->domain[dom]; - u32 src0, div0, div1D, div1P = 0; - u32 clk0, clk1 = 0; - - /* invalid clock domain */ - if (!freq) - return 0; - - /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); - - /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x0000ff87 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); - else - clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); - } - - /* select the method which gets closest to target freq */ - if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { - info->dsrc = src0; - if (div0) { - info->ddiv |= 0x80000000; - info->ddiv |= div0; - } - if (div1D) { - info->mdiv |= 0x80000000; - info->mdiv |= div1D; - } - info->ssel = 0; - info->freq = clk0; - } else { - if (div1P) { - info->mdiv |= 0x80000000; - info->mdiv |= div1P << 8; - } - info->ssel = (1 << clk); - info->dsrc = 0x40000100; - info->freq = clk1; - } - - return 0; -} - -static int -nve0_clk_calc(struct nouveau_clk *clk, struct nouveau_cstate *cstate) -{ - struct nve0_clk_priv *priv = (void *)clk; - int ret; - - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) - return ret; - - return 0; -} - -static void -nve0_clk_prog_0(struct nve0_clk_priv *priv, int clk) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - if (!info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); - } -} - -static void -nve0_clk_prog_1_0(struct nve0_clk_priv *priv, int clk) -{ - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); -} - -static void -nve0_clk_prog_1_1(struct nve0_clk_priv *priv, int clk) -{ - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000); -} - -static void -nve0_clk_prog_2(struct nve0_clk_priv *priv, int clk) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); - if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); - } -} - -static void -nve0_clk_prog_3(struct nve0_clk_priv *priv, int clk) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - if (info->ssel) - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); - else - nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); -} - -static void -nve0_clk_prog_4_0(struct nve0_clk_priv *priv, int clk) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); - } -} - -static void -nve0_clk_prog_4_1(struct nve0_clk_priv *priv, int clk) -{ - struct nve0_clk_info *info = &priv->eng[clk]; - if (info->ssel) { - nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000); - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100); - } -} - -static int -nve0_clk_prog(struct nouveau_clk *clk) -{ - struct nve0_clk_priv *priv = (void *)clk; - struct { - u32 mask; - void (*exec)(struct nve0_clk_priv *, int); - } stage[] = { - { 0x007f, nve0_clk_prog_0 }, /* div programming */ - { 0x007f, nve0_clk_prog_1_0 }, /* select div mode */ - { 0xff80, nve0_clk_prog_1_1 }, - { 0x00ff, nve0_clk_prog_2 }, /* (maybe) program pll */ - { 0xff80, nve0_clk_prog_3 }, /* final divider */ - { 0x007f, nve0_clk_prog_4_0 }, /* (maybe) select pll mode */ - { 0xff80, nve0_clk_prog_4_1 }, - }; - int i, j; - - for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { - if (!(stage[i].mask & (1 << j))) - continue; - if (!priv->eng[j].freq) - continue; - stage[i].exec(priv, j); - } - } - - return 0; -} - -static void -nve0_clk_tidy(struct nouveau_clk *clk) -{ - struct nve0_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); -} - -static struct nouveau_domain -nve0_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, - { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_mem , 0x03, 0, "memory", 500 }, - { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_hubk01 , 0x05 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x07 }, - { nv_clk_src_max } -}; - -static int -nve0_clk_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nve0_clk_priv *priv; - int ret; - - ret = nouveau_clk_create(parent, engine, oclass, nve0_domain, NULL, 0, - true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.read = nve0_clk_read; - priv->base.calc = nve0_clk_calc; - priv->base.prog = nve0_clk_prog; - priv->base.tidy = nve0_clk_tidy; - return 0; -} - -struct nouveau_oclass -nve0_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xe0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nve0_clk_ctor, - .dtor = _nouveau_clk_dtor, - .init = _nouveau_clk_init, - .fini = _nouveau_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h index 445b14c33a98..44020a30dee8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h @@ -1,9 +1,11 @@ -#ifndef __NOUVEAU_PLL_H__ -#define __NOUVEAU_PLL_H__ +#ifndef __NVKM_PLL_H__ +#define __NVKM_PLL_H__ +#include +struct nvkm_subdev; +struct nvbios_pll; -int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq, +int nv04_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq, int *N1, int *M1, int *N2, int *M2, int *P); -int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq, +int gt215_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq, int *N, int *fN, int *M, int *P); - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c new file mode 100644 index 000000000000..783a3e78d632 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c @@ -0,0 +1,87 @@ +/* + * Copyright 2010 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 "pll.h" + +#include +#include + +int +gt215_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, + u32 freq, int *pN, int *pfN, int *pM, int *P) +{ + u32 best_err = ~0, err; + int M, lM, hM, N, fN; + + *P = info->vco1.max_freq / freq; + if (*P > info->max_p) + *P = info->max_p; + if (*P < info->min_p) + *P = info->min_p; + + lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq; + lM = max(lM, (int)info->vco1.min_m); + hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq; + hM = min(hM, (int)info->vco1.max_m); + lM = min(lM, hM); + + for (M = lM; M <= hM; M++) { + u32 tmp = freq * *P * M; + N = tmp / info->refclk; + fN = tmp % info->refclk; + + if (!pfN) { + if (fN >= info->refclk / 2) + N++; + } else { + if (fN < info->refclk / 2) + N--; + fN = tmp - (N * info->refclk); + } + + if (N < info->vco1.min_n) + continue; + if (N > info->vco1.max_n) + break; + + err = abs(freq - (info->refclk * N / M / *P)); + if (err < best_err) { + best_err = err; + *pN = N; + *pM = M; + } + + if (pfN) { + *pfN = ((fN << 13) + info->refclk / 2) / info->refclk; + *pfN = (*pfN - 4096) & 0xffff; + return freq; + } + } + + if (unlikely(best_err == ~0)) { + nv_error(subdev, "unable to find matching pll values\n"); + return -EINVAL; + } + + return info->refclk * *pN / *pM / *P; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c index b47d543ab2e3..f2292895a1a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c @@ -20,14 +20,13 @@ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "pll.h" #include #include -#include "pll.h" - static int -getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, +getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, int *pN, int *pM, int *pP) { /* Find M, N and P for a single stage PLL @@ -38,7 +37,7 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - struct nouveau_bios *bios = nouveau_bios(subdev); + struct nvkm_bios *bios = nvkm_bios(subdev); int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; int minM = info->vco1.min_m, maxM = info->vco1.max_m; int minN = info->vco1.min_n, maxN = info->vco1.max_n; @@ -126,7 +125,7 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, } static int -getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, +getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, int *pN1, int *pM1, int *pN2, int *pM2, int *pP) { /* Find M, N and P for a two stage PLL @@ -137,7 +136,7 @@ getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int chip_version = nouveau_bios(subdev)->version.chip; + int chip_version = nvkm_bios(subdev)->version.chip; int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq; int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq; int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq; @@ -225,7 +224,7 @@ getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, } int -nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq, +nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq, int *N1, int *M1, int *N2, int *M2, int *P) { int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnva3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnva3.c deleted file mode 100644 index bc17fcc83bfe..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnva3.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2010 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 -#include -#include - -#include "pll.h" - -int -nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, - u32 freq, int *pN, int *pfN, int *pM, int *P) -{ - u32 best_err = ~0, err; - int M, lM, hM, N, fN; - - *P = info->vco1.max_freq / freq; - if (*P > info->max_p) - *P = info->max_p; - if (*P < info->min_p) - *P = info->min_p; - - lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq; - lM = max(lM, (int)info->vco1.min_m); - hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq; - hM = min(hM, (int)info->vco1.max_m); - lM = min(lM, hM); - - for (M = lM; M <= hM; M++) { - u32 tmp = freq * *P * M; - N = tmp / info->refclk; - fN = tmp % info->refclk; - - if (!pfN) { - if (fN >= info->refclk / 2) - N++; - } else { - if (fN < info->refclk / 2) - N--; - fN = tmp - (N * info->refclk); - } - - if (N < info->vco1.min_n) - continue; - if (N > info->vco1.max_n) - break; - - err = abs(freq - (info->refclk * N / M / *P)); - if (err < best_err) { - best_err = err; - *pN = N; - *pM = M; - } - - if (pfN) { - *pfN = ((fN << 13) + info->refclk / 2) / info->refclk; - *pfN = (*pfN - 4096) & 0xffff; - return freq; - } - } - - if (unlikely(best_err == ~0)) { - nv_error(subdev, "unable to find matching pll values\n"); - return -EINVAL; - } - - return info->refclk * *pN / *pM / *P; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h index fb33f06ebd59..d717e8b8f679 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h @@ -1,7 +1,5 @@ #ifndef __NVKM_CLK_SEQ_H__ #define __NVKM_CLK_SEQ_H__ - -#include #include #define clk_init(s,p) hwsq_init(&(s)->base, (p)) @@ -13,5 +11,4 @@ #define clk_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d)) #define clk_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d)) #define clk_nsec(s,n) hwsq_nsec(&(s)->base, (n)) - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnva3.c index 50e8dee513cc..f3cc7a19f931 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnva3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnva3.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include