]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/nouveau/nvc0_pm.c
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
[~andy/linux] / drivers / gpu / drm / nouveau / nvc0_pm.c
index 51cee210354414095a8a41907c1be84bbde835ff..0d34eb5811795813f4aa1a37890a662ad4062c8d 100644 (file)
  * 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)