summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvc0_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_pm.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_pm.c174
1 files changed, 97 insertions, 77 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index a14711c25176..0d34eb581179 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 "drmP.h"
-#include "nouveau_drv.h"
-#include <nouveau_bios.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 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 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,81 +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;
- if (nvfb_vram_type(dev) != 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;
- if (nvfb_vram_type(dev) != 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 (nvfb_vram_rank_B(dev))
- 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 (nvfb_vram_rank_B(dev))
- 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,
@@ -547,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)
OpenPOWER on IntegriCloud