Commit d26e7489 authored by Ben Skeggs's avatar Ben Skeggs

drm/gk104-/fb/ram: parse ramcfg data for all frequencies up-front

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 64804a6d
...@@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass; ...@@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass;
#include <subdev/bios/ramcfg.h> #include <subdev/bios/ramcfg.h>
struct nouveau_ram_data { struct nouveau_ram_data {
struct list_head head;
struct nvbios_ramcfg bios; struct nvbios_ramcfg bios;
u32 freq; u32 freq;
}; };
......
...@@ -136,6 +136,7 @@ struct nve0_ram { ...@@ -136,6 +136,7 @@ struct nve0_ram {
struct nouveau_ram base; struct nouveau_ram base;
struct nve0_ramfuc fuc; struct nve0_ramfuc fuc;
struct list_head cfg;
u32 parts; u32 parts;
u32 pmask; u32 pmask;
u32 pnuts; u32 pnuts;
...@@ -934,58 +935,24 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) ...@@ -934,58 +935,24 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
******************************************************************************/ ******************************************************************************/
static int static int
nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
struct nouveau_ram_data *data) struct nouveau_ram_data *data)
{ {
struct nouveau_bios *bios = nouveau_bios(pfb);
struct nve0_ram *ram = (void *)pfb->ram; struct nve0_ram *ram = (void *)pfb->ram;
u8 strap, cnt, len; struct nouveau_ram_data *cfg;
u32 mhz = khz / 1000;
/* lookup memory config data relevant to the target frequency */
ram->base.rammap.data = nvbios_rammapEm(bios, freq / 1000, list_for_each_entry(cfg, &ram->cfg, head) {
&ram->base.rammap.version, if (mhz >= cfg->bios.rammap_min &&
&ram->base.rammap.size, mhz <= cfg->bios.rammap_max) {
&cnt, &len, &data->bios); *data = *cfg;
if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 || data->freq = khz;
ram->base.rammap.size < 0x09) { return 0;
nv_error(pfb, "invalid/missing rammap entry\n");
return -EINVAL;
}
/* locate specific data set for the attached memory */
strap = nvbios_ramcfg_index(nv_subdev(pfb));
ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
ram->base.rammap.version,
ram->base.rammap.size,
cnt, len, strap,
&ram->base.ramcfg.version,
&ram->base.ramcfg.size,
&data->bios);
if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 ||
ram->base.ramcfg.size < 0x08) {
nv_error(pfb, "invalid/missing ramcfg entry\n");
return -EINVAL;
}
/* lookup memory timings, if bios says they're present */
if (data->bios.ramcfg_timing != 0xff) {
ram->base.timing.data =
nvbios_timingEp(bios, data->bios.ramcfg_timing,
&ram->base.timing.version,
&ram->base.timing.size, &cnt, &len,
&data->bios);
if (!ram->base.timing.data ||
ram->base.timing.version != 0x20 ||
ram->base.timing.size < 0x33) {
nv_error(pfb, "invalid/missing timing entry\n");
return -EINVAL;
} }
} else {
ram->base.timing.data = 0;
} }
data->freq = freq; nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
return 0; return -EINVAL;
} }
static int static int
...@@ -1318,6 +1285,66 @@ nve0_ram_init(struct nouveau_object *object) ...@@ -1318,6 +1285,66 @@ nve0_ram_init(struct nouveau_object *object)
return nve0_ram_train_init(pfb); return nve0_ram_train_init(pfb);
} }
static int
nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
{
struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
struct nouveau_bios *bios = nouveau_bios(pfb);
struct nouveau_ram_data *cfg;
u8 ver, hdr, cnt, len;
u32 data;
int ret;
if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
return -ENOMEM;
/* memory config data for a range of target frequencies */
data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
if (ret = -ENOENT, !data)
goto done;
if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
goto done;
/* ... and a portion specific to the attached memory */
data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
&ver, &hdr, &cfg->bios);
if (ret = -EINVAL, !data)
goto done;
if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
goto done;
/* lookup memory timings, if bios says they're present */
if (cfg->bios.ramcfg_timing != 0xff) {
data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
&ver, &hdr, &cnt, &len,
&cfg->bios);
if (ret = -EINVAL, !data)
goto done;
if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
goto done;
}
list_add_tail(&cfg->head, &ram->cfg);
ret = 0;
done:
if (ret)
kfree(cfg);
return ret;
}
static void
nve0_ram_dtor(struct nouveau_object *object)
{
struct nve0_ram *ram = (void *)object;
struct nouveau_ram_data *cfg, *tmp;
list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
kfree(cfg);
}
nouveau_ram_destroy(&ram->base);
}
static int static int
nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -1329,6 +1356,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1329,6 +1356,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct dcb_gpio_func func; struct dcb_gpio_func func;
struct nve0_ram *ram; struct nve0_ram *ram;
int ret, i; int ret, i;
u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
u32 tmp; u32 tmp;
ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
...@@ -1336,6 +1364,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1336,6 +1364,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
INIT_LIST_HEAD(&ram->cfg);
switch (ram->base.type) { switch (ram->base.type) {
case NV_MEM_TYPE_DDR3: case NV_MEM_TYPE_DDR3:
case NV_MEM_TYPE_GDDR5: case NV_MEM_TYPE_GDDR5:
...@@ -1367,7 +1397,16 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1367,7 +1397,16 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
} }
} }
// parse bios data for both pll's /* parse ramcfg data for all possible target frequencies */
for (i = 0; !ret; i++) {
ret = nve0_ram_ctor_data(ram, ramcfg, i);
if (ret && ret != -ENOENT) {
nv_error(pfb, "failed to parse ramcfg data\n");
return ret;
}
}
/* parse bios data for both pll's */
ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
if (ret) { if (ret) {
nv_error(pfb, "mclk refpll data not found\n"); nv_error(pfb, "mclk refpll data not found\n");
...@@ -1380,6 +1419,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1380,6 +1419,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret; return ret;
} }
/* lookup memory voltage gpios */
ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
if (ret == 0) { if (ret == 0) {
ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04)); ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
...@@ -1488,7 +1528,7 @@ nve0_ram_oclass = { ...@@ -1488,7 +1528,7 @@ nve0_ram_oclass = {
.handle = 0, .handle = 0,
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_ram_ctor, .ctor = nve0_ram_ctor,
.dtor = _nouveau_ram_dtor, .dtor = nve0_ram_dtor,
.init = nve0_ram_init, .init = nve0_ram_init,
.fini = _nouveau_ram_fini, .fini = _nouveau_ram_fini,
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment