Skip to content

Commit

Permalink
drm/nouveau/pm: introduce ram reclocking helper
Browse files Browse the repository at this point in the history
This will probably result in more lines of code, however, we're going to
have at least 3 slightly different implementations of this very soon and
I'd rather keep the ram reclocking logic separate from the hw specifics.

DDR2/DDR3/GDDR3 implemented thus far, others will be added as necessary.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Martin Peres <martin.peres@labri.fr>
  • Loading branch information
Ben Skeggs committed Mar 13, 2012
1 parent 085028c commit 2d85bc8
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
96 changes: 96 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,102 @@ nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
}
}

int
nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
struct nouveau_pm_level *perflvl)
{
struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
struct nouveau_pm_memtiming *info = &perflvl->timing;
u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0;
u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
u32 mr1_dlloff;

switch (dev_priv->vram_type) {
case NV_MEM_TYPE_DDR2:
tDLLK = 2000;
mr1_dlloff = 0x00000001;
break;
case NV_MEM_TYPE_DDR3:
tDLLK = 12000;
mr1_dlloff = 0x00000001;
break;
case NV_MEM_TYPE_GDDR3:
tDLLK = 40000;
mr1_dlloff = 0x00000040;
break;
default:
NV_ERROR(exec->dev, "cannot reclock unsupported memtype\n");
return -ENODEV;
}

/* fetch current MRs */
switch (dev_priv->vram_type) {
case NV_MEM_TYPE_DDR3:
mr[2] = exec->mrg(exec, 2);
default:
mr[1] = exec->mrg(exec, 1);
mr[0] = exec->mrg(exec, 0);
break;
}

/* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh */
if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) {
exec->precharge(exec);
exec->mrs (exec, 1, mr[1] | mr1_dlloff);
exec->wait(exec, tMRD);
}

/* enter self-refresh mode */
exec->precharge(exec);
exec->refresh(exec);
exec->refresh(exec);
exec->refresh_auto(exec, false);
exec->refresh_self(exec, true);
exec->wait(exec, tCKSRE);

/* modify input clock frequency */
exec->clock_set(exec);

/* exit self-refresh mode */
exec->wait(exec, tCKSRX);
exec->precharge(exec);
exec->refresh_self(exec, false);
exec->refresh_auto(exec, true);
exec->wait(exec, tXS);

/* update MRs */
if (mr[2] != info->mr[2]) {
exec->mrs (exec, 2, info->mr[2]);
exec->wait(exec, tMRD);
}

if (mr[1] != info->mr[1]) {
exec->mrs (exec, 1, info->mr[1]);
exec->wait(exec, tMRD);
}

if (mr[0] != info->mr[0]) {
exec->mrs (exec, 0, info->mr[0]);
exec->wait(exec, tMRD);
}

/* update PFB timing registers */
exec->timing_set(exec);

/* DLL reset */
if (!(info->mr[1] & mr1_dlloff)) {
exec->mrs (exec, 0, info->mr[0] | 0x00000100);
exec->wait(exec, tMRD);
exec->mrs (exec, 0, info->mr[0] | 0x00000000);
exec->wait(exec, tMRD);
exec->wait(exec, tDLLK);
if (dev_priv->vram_type == NV_MEM_TYPE_GDDR3)
exec->precharge(exec);
}

return 0;
}

int
nouveau_mem_vbios_type(struct drm_device *dev)
{
Expand Down
18 changes: 18 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@
#ifndef __NOUVEAU_PM_H__
#define __NOUVEAU_PM_H__

struct nouveau_mem_exec_func {
struct drm_device *dev;
void (*precharge)(struct nouveau_mem_exec_func *);
void (*refresh)(struct nouveau_mem_exec_func *);
void (*refresh_auto)(struct nouveau_mem_exec_func *, bool);
void (*refresh_self)(struct nouveau_mem_exec_func *, bool);
void (*wait)(struct nouveau_mem_exec_func *, u32 nsec);
u32 (*mrg)(struct nouveau_mem_exec_func *, int mr);
void (*mrs)(struct nouveau_mem_exec_func *, int mr, u32 data);
void (*clock_set)(struct nouveau_mem_exec_func *);
void (*timing_set)(struct nouveau_mem_exec_func *);
void *priv;
};

/* nouveau_mem.c */
int nouveau_mem_exec(struct nouveau_mem_exec_func *,
struct nouveau_pm_level *);

/* nouveau_pm.c */
int nouveau_pm_init(struct drm_device *dev);
void nouveau_pm_fini(struct drm_device *dev);
Expand Down

0 comments on commit 2d85bc8

Please sign in to comment.