mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-27 04:54:41 +08:00
drm/nouveau/fb/ramnva3: Reclocking script for GDDR3
Signed-off-by: Roy Spliet <rspliet@eclipso.eu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
b0c7336b1a
commit
598a39e79a
@ -33,6 +33,8 @@
|
|||||||
#include <subdev/clock/nva3.h>
|
#include <subdev/clock/nva3.h>
|
||||||
#include <subdev/clock/pll.h>
|
#include <subdev/clock/pll.h>
|
||||||
|
|
||||||
|
#include <subdev/gpio.h>
|
||||||
|
|
||||||
#include <subdev/timer.h>
|
#include <subdev/timer.h>
|
||||||
|
|
||||||
#include <engine/fifo.h>
|
#include <engine/fifo.h>
|
||||||
@ -43,6 +45,9 @@
|
|||||||
|
|
||||||
#include "nv50.h"
|
#include "nv50.h"
|
||||||
|
|
||||||
|
/* XXX: Remove when memx gains GPIO support */
|
||||||
|
extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
|
||||||
|
|
||||||
struct nva3_ramfuc {
|
struct nva3_ramfuc {
|
||||||
struct ramfuc base;
|
struct ramfuc base;
|
||||||
struct ramfuc_reg r_0x001610;
|
struct ramfuc_reg r_0x001610;
|
||||||
@ -81,6 +86,7 @@ struct nva3_ramfuc {
|
|||||||
struct ramfuc_reg r_0x111400;
|
struct ramfuc_reg r_0x111400;
|
||||||
struct ramfuc_reg r_0x611200;
|
struct ramfuc_reg r_0x611200;
|
||||||
struct ramfuc_reg r_mr[4];
|
struct ramfuc_reg r_mr[4];
|
||||||
|
struct ramfuc_reg r_gpioFBVREF;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nva3_ltrain {
|
struct nva3_ltrain {
|
||||||
@ -357,15 +363,22 @@ nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
|
|||||||
struct nva3_ram *ram = (void *)pfb->ram;
|
struct nva3_ram *ram = (void *)pfb->ram;
|
||||||
struct nvbios_ramcfg *cfg = &ram->base.target.bios;
|
struct nvbios_ramcfg *cfg = &ram->base.target.bios;
|
||||||
int tUNK_base, tUNK_40_0, prevCL;
|
int tUNK_base, tUNK_40_0, prevCL;
|
||||||
u32 cur3, cur7, cur8;
|
u32 cur2, cur3, cur7, cur8;
|
||||||
|
|
||||||
|
cur2 = nv_rd32(pfb, 0x100228);
|
||||||
cur3 = nv_rd32(pfb, 0x10022c);
|
cur3 = nv_rd32(pfb, 0x10022c);
|
||||||
cur7 = nv_rd32(pfb, 0x10023c);
|
cur7 = nv_rd32(pfb, 0x10023c);
|
||||||
cur8 = nv_rd32(pfb, 0x100240);
|
cur8 = nv_rd32(pfb, 0x100240);
|
||||||
|
|
||||||
if (T(CWL) == 0)
|
|
||||||
/* Observed on DDR2 */
|
switch ((!T(CWL)) * ram->base.type) {
|
||||||
|
case NV_MEM_TYPE_DDR2:
|
||||||
T(CWL) = T(CL) - 1;
|
T(CWL) = T(CL) - 1;
|
||||||
|
break;
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
|
T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
prevCL = (cur3 & 0x000000ff) + 1;
|
prevCL = (cur3 & 0x000000ff) + 1;
|
||||||
tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
|
tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
|
||||||
@ -389,10 +402,10 @@ nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
|
|||||||
T(13);
|
T(13);
|
||||||
timing[5] = T(RFC) << 24 |
|
timing[5] = T(RFC) << 24 |
|
||||||
max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
|
max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
|
||||||
(T(CWL) + 6) << 8 |
|
max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
|
||||||
T(RP);
|
T(RP);
|
||||||
timing[6] = (0x5a + T(CL)) << 16 |
|
timing[6] = (0x5a + T(CL)) << 16 |
|
||||||
(6 - T(CL) + T(CWL)) << 8 |
|
max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
|
||||||
(0x50 + T(CL) - T(CWL));
|
(0x50 + T(CL) - T(CWL));
|
||||||
timing[7] = (cur7 & 0xff000000) |
|
timing[7] = (cur7 & 0xff000000) |
|
||||||
((tUNK_base + T(CL)) << 16) |
|
((tUNK_base + T(CL)) << 16) |
|
||||||
@ -401,6 +414,7 @@ nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
|
|||||||
|
|
||||||
switch (ram->base.type) {
|
switch (ram->base.type) {
|
||||||
case NV_MEM_TYPE_DDR2:
|
case NV_MEM_TYPE_DDR2:
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
tUNK_40_0 = prevCL - (cur8 & 0xff);
|
tUNK_40_0 = prevCL - (cur8 & 0xff);
|
||||||
if (tUNK_40_0 > 0)
|
if (tUNK_40_0 > 0)
|
||||||
timing[8] |= T(CL);
|
timing[8] |= T(CL);
|
||||||
@ -439,6 +453,17 @@ nouveau_sddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nouveau_gddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
|
||||||
|
{
|
||||||
|
u32 mr1_old = ram_rd32(fuc, mr[1]);
|
||||||
|
|
||||||
|
if (!(mr1_old & 0x40)) {
|
||||||
|
ram_wr32(fuc, mr[1], mr[1]);
|
||||||
|
ram_nsec(fuc, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
|
nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
|
||||||
{
|
{
|
||||||
@ -449,6 +474,29 @@ nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
|
|||||||
ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
|
ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nva3_ram_fbvref(struct nva3_ramfuc *fuc, u32 val)
|
||||||
|
{
|
||||||
|
struct nouveau_gpio *gpio = nouveau_gpio(fuc->base.pfb);
|
||||||
|
struct dcb_gpio_func func;
|
||||||
|
u32 reg, sh, gpio_val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
|
||||||
|
ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nv50_gpio_location(func.line, ®, &sh);
|
||||||
|
gpio_val = ram_rd32(fuc, gpioFBVREF);
|
||||||
|
if (gpio_val & (8 << sh))
|
||||||
|
val = !val;
|
||||||
|
|
||||||
|
ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
|
||||||
|
ram_nsec(fuc, 20000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
||||||
{
|
{
|
||||||
@ -531,6 +579,9 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
|||||||
case NV_MEM_TYPE_DDR3:
|
case NV_MEM_TYPE_DDR3:
|
||||||
ret = nouveau_sddr3_calc(&ram->base);
|
ret = nouveau_sddr3_calc(&ram->base);
|
||||||
break;
|
break;
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
|
ret = nouveau_gddr3_calc(&ram->base);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
break;
|
break;
|
||||||
@ -582,17 +633,26 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
|||||||
ram_block(fuc);
|
ram_block(fuc);
|
||||||
ram_nsec(fuc, 2000);
|
ram_nsec(fuc, 2000);
|
||||||
|
|
||||||
|
if (!next->bios.ramcfg_10_02_10) {
|
||||||
if (!next->bios.ramcfg_10_02_10)
|
if (ram->base.type == NV_MEM_TYPE_GDDR3)
|
||||||
ram_mask(fuc, 0x111100, 0x04020000, 0x04020000); /*XXX*/
|
ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
|
||||||
|
else
|
||||||
|
ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're disabling the DLL, do it now */
|
/* If we're disabling the DLL, do it now */
|
||||||
switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
|
switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
|
||||||
case NV_MEM_TYPE_DDR3:
|
case NV_MEM_TYPE_DDR3:
|
||||||
nouveau_sddr3_dll_disable(fuc, ram->base.mr);
|
nouveau_sddr3_dll_disable(fuc, ram->base.mr);
|
||||||
break;
|
break;
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
|
nouveau_gddr3_dll_disable(fuc, ram->base.mr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
|
||||||
|
nva3_ram_fbvref(fuc, 0);
|
||||||
|
|
||||||
/* Brace RAM for impact */
|
/* Brace RAM for impact */
|
||||||
ram_wr32(fuc, 0x1002d4, 0x00000001);
|
ram_wr32(fuc, 0x1002d4, 0x00000001);
|
||||||
ram_wr32(fuc, 0x1002d0, 0x00000001);
|
ram_wr32(fuc, 0x1002d0, 0x00000001);
|
||||||
@ -728,6 +788,10 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
|||||||
}
|
}
|
||||||
unk714 |= 0x00000010;
|
unk714 |= 0x00000010;
|
||||||
break;
|
break;
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
|
r111100 |= 0x30000000;
|
||||||
|
unk714 |= 0x00000020;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -753,11 +817,18 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
|||||||
ram_mask(fuc, 0x100718, 0xffffffff, unk718);
|
ram_mask(fuc, 0x100718, 0xffffffff, unk718);
|
||||||
ram_mask(fuc, 0x111100, 0xffffffff, r111100);
|
ram_mask(fuc, 0x111100, 0xffffffff, r111100);
|
||||||
|
|
||||||
|
if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
|
||||||
|
nva3_ram_fbvref(fuc, 1);
|
||||||
|
|
||||||
/* Reset DLL */
|
/* Reset DLL */
|
||||||
if (!next->bios.ramcfg_10_DLLoff)
|
if (!next->bios.ramcfg_10_DLLoff)
|
||||||
nouveau_sddr2_dll_reset(fuc);
|
nouveau_sddr2_dll_reset(fuc);
|
||||||
|
|
||||||
ram_nsec(fuc, 14000);
|
if (ram->base.type == NV_MEM_TYPE_GDDR3) {
|
||||||
|
ram_nsec(fuc, 31000);
|
||||||
|
} else {
|
||||||
|
ram_nsec(fuc, 14000);
|
||||||
|
}
|
||||||
|
|
||||||
if (ram->base.type == NV_MEM_TYPE_DDR3) {
|
if (ram->base.type == NV_MEM_TYPE_DDR3) {
|
||||||
ram_wr32(fuc, 0x100264, 0x1);
|
ram_wr32(fuc, 0x100264, 0x1);
|
||||||
@ -859,8 +930,12 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
|||||||
struct nouveau_oclass *oclass, void *data, u32 datasize,
|
struct nouveau_oclass *oclass, void *data, u32 datasize,
|
||||||
struct nouveau_object **pobject)
|
struct nouveau_object **pobject)
|
||||||
{
|
{
|
||||||
|
struct nouveau_fb *pfb = nouveau_fb(parent);
|
||||||
|
struct nouveau_gpio *gpio = nouveau_gpio(pfb);
|
||||||
|
struct dcb_gpio_func func;
|
||||||
struct nva3_ram *ram;
|
struct nva3_ram *ram;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
u32 reg, shift;
|
||||||
|
|
||||||
ret = nv50_ram_create(parent, engine, oclass, &ram);
|
ret = nv50_ram_create(parent, engine, oclass, &ram);
|
||||||
*pobject = nv_object(ram);
|
*pobject = nv_object(ram);
|
||||||
@ -870,6 +945,7 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
|||||||
switch (ram->base.type) {
|
switch (ram->base.type) {
|
||||||
case NV_MEM_TYPE_DDR2:
|
case NV_MEM_TYPE_DDR2:
|
||||||
case NV_MEM_TYPE_DDR3:
|
case NV_MEM_TYPE_DDR3:
|
||||||
|
case NV_MEM_TYPE_GDDR3:
|
||||||
ram->base.calc = nva3_ram_calc;
|
ram->base.calc = nva3_ram_calc;
|
||||||
ram->base.prog = nva3_ram_prog;
|
ram->base.prog = nva3_ram_prog;
|
||||||
ram->base.tidy = nva3_ram_tidy;
|
ram->base.tidy = nva3_ram_tidy;
|
||||||
@ -928,6 +1004,12 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
|||||||
ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
|
ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
|
||||||
|
if (ret == 0) {
|
||||||
|
nv50_gpio_location(func.line, ®, &shift);
|
||||||
|
ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
nv50_gpio_location(int line, u32 *reg, u32 *shift)
|
nv50_gpio_location(int line, u32 *reg, u32 *shift)
|
||||||
{
|
{
|
||||||
const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
|
const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
|
||||||
|
Loading…
Reference in New Issue
Block a user