diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_pm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_pm.c | 178 |
1 files changed, 98 insertions, 80 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c index 51cee210354..0d34eb58117 100644 --- a/drivers/gpu/drm/nouveau/nvc0_pm.c +++ b/drivers/gpu/drm/nouveau/nvc0_pm.c @@ -22,18 +22,24 @@ * Authors: Ben Skeggs */ -#include <drm/drmP.h> -#include "nouveau_drv.h" +#include "nouveau_drm.h" #include "nouveau_bios.h" #include "nouveau_pm.h" +#include <subdev/bios/pll.h> +#include <subdev/bios.h> +#include <subdev/clock.h> +#include <subdev/timer.h> +#include <subdev/fb.h> + static u32 read_div(struct drm_device *, int, u32, u32); static u32 read_pll(struct drm_device *, u32); static u32 read_vco(struct drm_device *dev, u32 dsrc) { - u32 ssrc = nv_rd32(dev, dsrc); + struct nouveau_device *device = nouveau_dev(dev); + u32 ssrc = nv_rd32(device, dsrc); if (!(ssrc & 0x00000100)) return read_pll(dev, 0x00e800); return read_pll(dev, 0x00e820); @@ -42,8 +48,9 @@ read_vco(struct drm_device *dev, u32 dsrc) static u32 read_pll(struct drm_device *dev, u32 pll) { - u32 ctrl = nv_rd32(dev, pll + 0); - u32 coef = nv_rd32(dev, pll + 4); + struct nouveau_device *device = nouveau_dev(dev); + u32 ctrl = nv_rd32(device, pll + 0); + u32 coef = nv_rd32(device, pll + 4); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -83,8 +90,9 @@ read_pll(struct drm_device *dev, u32 pll) static u32 read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(dev, dsrc + (doff * 4)); - u32 sctl = nv_rd32(dev, dctl + (doff * 4)); + struct nouveau_device *device = nouveau_dev(dev); + u32 ssrc = nv_rd32(device, dsrc + (doff * 4)); + u32 sctl = nv_rd32(device, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: @@ -109,7 +117,8 @@ read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) static u32 read_mem(struct drm_device *dev) { - u32 ssel = nv_rd32(dev, 0x1373f0); + struct nouveau_device *device = nouveau_dev(dev); + u32 ssel = nv_rd32(device, 0x1373f0); if (ssel & 0x00000001) return read_div(dev, 0, 0x137300, 0x137310); return read_pll(dev, 0x132000); @@ -118,8 +127,9 @@ read_mem(struct drm_device *dev) static u32 read_clk(struct drm_device *dev, int clk) { - u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4)); - u32 ssel = nv_rd32(dev, 0x137100); + struct nouveau_device *device = nouveau_dev(dev); + u32 sctl = nv_rd32(device, 0x137250 + (clk * 4)); + u32 ssel = nv_rd32(device, 0x137100); u32 sclk, sdiv; if (ssel & (1 << clk)) { @@ -212,10 +222,12 @@ calc_src(struct drm_device *dev, int clk, u32 freq, u32 *dsrc, u32 *ddiv) static u32 calc_pll(struct drm_device *dev, int clk, u32 freq, u32 *coef) { - struct pll_lims limits; + struct nouveau_device *device = nouveau_dev(dev); + struct nouveau_bios *bios = nouveau_bios(device); + struct nvbios_pll limits; int N, M, P, ret; - ret = get_pll_limits(dev, 0x137000 + (clk * 0x20), &limits); + ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); if (ret) return 0; @@ -308,31 +320,33 @@ calc_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info, u32 freq) static int calc_mem(struct drm_device *dev, struct nvc0_pm_clock *info, u32 freq) { - struct pll_lims pll; + struct nouveau_device *device = nouveau_dev(dev); + struct nouveau_bios *bios = nouveau_bios(device); + struct nvbios_pll pll; int N, M, P, ret; u32 ctrl; /* mclk pll input freq comes from another pll, make sure it's on */ - ctrl = nv_rd32(dev, 0x132020); + ctrl = nv_rd32(device, 0x132020); if (!(ctrl & 0x00000001)) { /* if not, program it to 567MHz. nfi where this value comes * from - it looks like it's in the pll limits table for * 132000 but the binary driver ignores all my attempts to * change this value. */ - nv_wr32(dev, 0x137320, 0x00000103); - nv_wr32(dev, 0x137330, 0x81200606); - nv_wait(dev, 0x132020, 0x00010000, 0x00010000); - nv_wr32(dev, 0x132024, 0x0001150f); - nv_mask(dev, 0x132020, 0x00000001, 0x00000001); - nv_wait(dev, 0x137390, 0x00020000, 0x00020000); - nv_mask(dev, 0x132020, 0x00000004, 0x00000004); + nv_wr32(device, 0x137320, 0x00000103); + nv_wr32(device, 0x137330, 0x81200606); + nv_wait(device, 0x132020, 0x00010000, 0x00010000); + nv_wr32(device, 0x132024, 0x0001150f); + nv_mask(device, 0x132020, 0x00000001, 0x00000001); + nv_wait(device, 0x137390, 0x00020000, 0x00020000); + nv_mask(device, 0x132020, 0x00000004, 0x00000004); } /* for the moment, until the clock tree is better understood, use * pll mode for all clock frequencies */ - ret = get_pll_limits(dev, 0x132000, &pll); + ret = nvbios_pll_parse(bios, 0x132000, &pll); if (ret == 0) { pll.refclk = read_pll(dev, 0x132020); if (pll.refclk) { @@ -350,7 +364,7 @@ calc_mem(struct drm_device *dev, struct nvc0_pm_clock *info, u32 freq) void * nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = nouveau_dev(dev); struct nvc0_pm_state *info; int ret; @@ -364,7 +378,7 @@ nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) * are always the same freq with the binary driver even when the * performance table says they should differ. */ - if (dev_priv->chipset == 0xd9) + if (device->chipset == 0xd9) perflvl->rop = 0; if ((ret = calc_clk(dev, 0x00, &info->eng[0x00], perflvl->shader)) || @@ -394,38 +408,40 @@ nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) static void prog_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info) { + struct nouveau_device *device = nouveau_dev(dev); + /* program dividers at 137160/1371d0 first */ if (clk < 7 && !info->ssel) { - nv_mask(dev, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(dev, 0x137160 + (clk * 0x04), info->dsrc); + nv_mask(device, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); + nv_wr32(device, 0x137160 + (clk * 0x04), info->dsrc); } /* switch clock to non-pll mode */ - nv_mask(dev, 0x137100, (1 << clk), 0x00000000); - nv_wait(dev, 0x137100, (1 << clk), 0x00000000); + nv_mask(device, 0x137100, (1 << clk), 0x00000000); + nv_wait(device, 0x137100, (1 << clk), 0x00000000); /* reprogram pll */ if (clk < 7) { /* make sure it's disabled first... */ u32 base = 0x137000 + (clk * 0x20); - u32 ctrl = nv_rd32(dev, base + 0x00); + u32 ctrl = nv_rd32(device, base + 0x00); if (ctrl & 0x00000001) { - nv_mask(dev, base + 0x00, 0x00000004, 0x00000000); - nv_mask(dev, base + 0x00, 0x00000001, 0x00000000); + nv_mask(device, base + 0x00, 0x00000004, 0x00000000); + nv_mask(device, base + 0x00, 0x00000001, 0x00000000); } /* program it to new values, if necessary */ if (info->ssel) { - nv_wr32(dev, base + 0x04, info->coef); - nv_mask(dev, base + 0x00, 0x00000001, 0x00000001); - nv_wait(dev, base + 0x00, 0x00020000, 0x00020000); - nv_mask(dev, base + 0x00, 0x00020004, 0x00000004); + nv_wr32(device, base + 0x04, info->coef); + nv_mask(device, base + 0x00, 0x00000001, 0x00000001); + nv_wait(device, base + 0x00, 0x00020000, 0x00020000); + nv_mask(device, base + 0x00, 0x00020004, 0x00000004); } } /* select pll/non-pll mode, and program final clock divider */ - nv_mask(dev, 0x137100, (1 << clk), info->ssel); - nv_wait(dev, 0x137100, (1 << clk), info->ssel); - nv_mask(dev, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); + nv_mask(device, 0x137100, (1 << clk), info->ssel); + nv_wait(device, 0x137100, (1 << clk), info->ssel); + nv_mask(device, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); } static void @@ -441,7 +457,8 @@ mclk_refresh(struct nouveau_mem_exec_func *exec) static void mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) { - nv_wr32(exec->dev, 0x10f210, enable ? 0x80000000 : 0x00000000); + struct nouveau_device *device = nouveau_dev(exec->dev); + nv_wr32(device, 0x10f210, enable ? 0x80000000 : 0x00000000); } static void @@ -458,83 +475,84 @@ mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) static u32 mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) { - struct drm_device *dev = exec->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) { + struct nouveau_device *device = nouveau_dev(exec->dev); + struct nouveau_fb *pfb = nouveau_fb(device); + if (pfb->ram.type != NV_MEM_TYPE_GDDR5) { if (mr <= 1) - return nv_rd32(dev, 0x10f300 + ((mr - 0) * 4)); - return nv_rd32(dev, 0x10f320 + ((mr - 2) * 4)); + return nv_rd32(device, 0x10f300 + ((mr - 0) * 4)); + return nv_rd32(device, 0x10f320 + ((mr - 2) * 4)); } else { if (mr == 0) - return nv_rd32(dev, 0x10f300 + (mr * 4)); + return nv_rd32(device, 0x10f300 + (mr * 4)); else if (mr <= 7) - return nv_rd32(dev, 0x10f32c + (mr * 4)); - return nv_rd32(dev, 0x10f34c); + return nv_rd32(device, 0x10f32c + (mr * 4)); + return nv_rd32(device, 0x10f34c); } } static void mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) { - struct drm_device *dev = exec->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) { + struct nouveau_device *device = nouveau_dev(exec->dev); + struct nouveau_fb *pfb = nouveau_fb(device); + if (pfb->ram.type != NV_MEM_TYPE_GDDR5) { if (mr <= 1) { - nv_wr32(dev, 0x10f300 + ((mr - 0) * 4), data); - if (dev_priv->vram_rank_B) - nv_wr32(dev, 0x10f308 + ((mr - 0) * 4), data); + nv_wr32(device, 0x10f300 + ((mr - 0) * 4), data); + if (pfb->ram.ranks > 1) + nv_wr32(device, 0x10f308 + ((mr - 0) * 4), data); } else if (mr <= 3) { - nv_wr32(dev, 0x10f320 + ((mr - 2) * 4), data); - if (dev_priv->vram_rank_B) - nv_wr32(dev, 0x10f328 + ((mr - 2) * 4), data); + nv_wr32(device, 0x10f320 + ((mr - 2) * 4), data); + if (pfb->ram.ranks > 1) + nv_wr32(device, 0x10f328 + ((mr - 2) * 4), data); } } else { - if (mr == 0) nv_wr32(dev, 0x10f300 + (mr * 4), data); - else if (mr <= 7) nv_wr32(dev, 0x10f32c + (mr * 4), data); - else if (mr == 15) nv_wr32(dev, 0x10f34c, data); + if (mr == 0) nv_wr32(device, 0x10f300 + (mr * 4), data); + else if (mr <= 7) nv_wr32(device, 0x10f32c + (mr * 4), data); + else if (mr == 15) nv_wr32(device, 0x10f34c, data); } } static void mclk_clock_set(struct nouveau_mem_exec_func *exec) { + struct nouveau_device *device = nouveau_dev(exec->dev); struct nvc0_pm_state *info = exec->priv; - struct drm_device *dev = exec->dev; - u32 ctrl = nv_rd32(dev, 0x132000); + u32 ctrl = nv_rd32(device, 0x132000); - nv_wr32(dev, 0x137360, 0x00000001); - nv_wr32(dev, 0x137370, 0x00000000); - nv_wr32(dev, 0x137380, 0x00000000); + nv_wr32(device, 0x137360, 0x00000001); + nv_wr32(device, 0x137370, 0x00000000); + nv_wr32(device, 0x137380, 0x00000000); if (ctrl & 0x00000001) - nv_wr32(dev, 0x132000, (ctrl &= ~0x00000001)); + nv_wr32(device, 0x132000, (ctrl &= ~0x00000001)); - nv_wr32(dev, 0x132004, info->mem.coef); - nv_wr32(dev, 0x132000, (ctrl |= 0x00000001)); - nv_wait(dev, 0x137390, 0x00000002, 0x00000002); - nv_wr32(dev, 0x132018, 0x00005000); + nv_wr32(device, 0x132004, info->mem.coef); + nv_wr32(device, 0x132000, (ctrl |= 0x00000001)); + nv_wait(device, 0x137390, 0x00000002, 0x00000002); + nv_wr32(device, 0x132018, 0x00005000); - nv_wr32(dev, 0x137370, 0x00000001); - nv_wr32(dev, 0x137380, 0x00000001); - nv_wr32(dev, 0x137360, 0x00000000); + nv_wr32(device, 0x137370, 0x00000001); + nv_wr32(device, 0x137380, 0x00000001); + nv_wr32(device, 0x137360, 0x00000000); } static void mclk_timing_set(struct nouveau_mem_exec_func *exec) { + struct nouveau_device *device = nouveau_dev(exec->dev); struct nvc0_pm_state *info = exec->priv; struct nouveau_pm_level *perflvl = info->perflvl; int i; for (i = 0; i < 5; i++) - nv_wr32(exec->dev, 0x10f290 + (i * 4), perflvl->timing.reg[i]); + nv_wr32(device, 0x10f290 + (i * 4), perflvl->timing.reg[i]); } static void prog_mem(struct drm_device *dev, struct nvc0_pm_state *info) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = nouveau_dev(dev); struct nouveau_mem_exec_func exec = { .dev = dev, .precharge = mclk_precharge, @@ -549,17 +567,17 @@ prog_mem(struct drm_device *dev, struct nvc0_pm_state *info) .priv = info }; - if (dev_priv->chipset < 0xd0) - nv_wr32(dev, 0x611200, 0x00003300); + if (device->chipset < 0xd0) + nv_wr32(device, 0x611200, 0x00003300); else - nv_wr32(dev, 0x62c000, 0x03030000); + nv_wr32(device, 0x62c000, 0x03030000); nouveau_mem_exec(&exec, info->perflvl); - if (dev_priv->chipset < 0xd0) - nv_wr32(dev, 0x611200, 0x00003330); + if (device->chipset < 0xd0) + nv_wr32(device, 0x611200, 0x00003330); else - nv_wr32(dev, 0x62c000, 0x03030300); + nv_wr32(device, 0x62c000, 0x03030300); } int nvc0_pm_clocks_set(struct drm_device *dev, void *data) |