No, no, these will not implement Fermi reclocking. This set of patches contains some of the preparatory work that I deem stable enough to move upstream. Notable changes - Training pattern upload routines from GK104+ now shared with GT215+ - Timing calculation for Fermi - GDDR5 MR calculation from VBIOS timing table v1.0. Also useful for that pesky GT 240. - A routine to translate a VBIOS init script to a set of memx writes. Used by both "that GT 240" and Fermi. - Misc clean-up Testers should expect no changes in behaviour before/after. Keen eyes can double-check on their Tesla and Fermi GDDR5 graphics cards that training patterns are uploaded on boot.
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 01/11] nvkm/ramgf100: Get rid of (size, data) pairs for rammap, ramcfg, timing
In correspondence with the other ram_calc implementations. Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 093223d..fffd01a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -133,21 +133,22 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) struct nvkm_device *device = subdev->device; struct nvkm_clk *clk = device->clk; struct nvkm_bios *bios = device->bios; - struct nvbios_ramcfg cfg; - u8 ver, cnt, len, strap; - struct { - u32 data; - u8 size; - } rammap, ramcfg, timing; + struct nvkm_ram_data *next; + u8 ver, hdr, cnt, len, strap; + u32 data; int ref, div, out; int from, mode; int N1, M1, P; int ret; + next = &ram->base.target; + next->freq = freq; + ram->base.next = next; + /* lookup memory config data relevant to the target frequency */ - rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, - &cnt, &ramcfg.size, &cfg); - if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { + data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, + &cnt, &len, &next->bios); + if (!data || ver != 0x10 || len < 0x0e) { nvkm_error(subdev, "invalid/missing rammap entry\n"); return -EINVAL; } @@ -159,23 +160,23 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) return -EINVAL; } - ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); - if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { + data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, + &ver, &hdr, &next->bios); + if (!data || ver != 0x10 || hdr < 0x0e) { nvkm_error(subdev, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ - strap = nvbios_rd08(bios, ramcfg.data + 0x01); - if (strap != 0xff) { - timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, - &cnt, &len); - if (!timing.data || ver != 0x10 || timing.size < 0x19) { + strap = nvbios_rd08(bios, data + 0x01); + if (next->bios.ramcfg_timing != 0xff) { + data = nvbios_timingEp(bios, next->bios.ramcfg_timing, + &ver, &hdr, &cnt, &len, + &next->bios); + if (!data || ver != 0x10 || hdr < 0x17) { nvkm_error(subdev, "invalid/missing timing entry\n"); return -EINVAL; } - } else { - timing.data = 0; } ret = ram_init(fuc, ram->base.fb); -- 2.9.3
Todo: - Determine source of R[10f298] & 0x11 Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 115 ++++++++++++++-------- 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index fffd01a..6ebdc4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -48,11 +48,7 @@ struct gf100_ramfuc { struct ramfuc_reg r_0x137390; - struct ramfuc_reg r_0x10f290; - struct ramfuc_reg r_0x10f294; - struct ramfuc_reg r_0x10f298; - struct ramfuc_reg r_0x10f29c; - struct ramfuc_reg r_0x10f2a0; + struct ramfuc_reg r_0x10f290[5]; struct ramfuc_reg r_0x10f300; struct ramfuc_reg r_0x10f338; @@ -104,6 +100,50 @@ struct gf100_ram { struct nvbios_pll mempll; }; +#define T(t) cfg->timing_10_##t +static int +gf100_ram_timing_calc(struct gf100_ram *ram, u32 *timing) +{ + struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + u32 cur1, cur2, cur4; + + cur1 = nvkm_rd32(device, 0x10f294); + cur2 = nvkm_rd32(device, 0x10f298); + cur4 = nvkm_rd32(device, 0x10f2a0); + + /* XXX: (G)DDR3? */ + switch ((!T(CWL)) * ram->base.type) { + case NVKM_RAM_TYPE_GDDR5: + T(CWL) = (cur1 & 0x00000380) >> 7; + break; + } + + timing[0] = (T(RP) << 24 | T(RAS) << 17 | T(RFC) << 8 | T(RC)); + timing[1] = (cur1 & ~0x03ffc07f) | + (T(RCDWR) << 20) | + (T(RCDRD) << 14) | + (T(CWL) << 7) | + (T(CL)); + /* XXX: lower 8 bytes are two bits indicating "feature(s) X" */ + timing[2] = (cur2 & ~0x00ffffff) | + (T(WR) << 16) | + (T(WTR) << 8); + timing[3] = (T(FAW)) << 9 | + (T(CKE)) << 5 | + (T(XPDLL)); + timing[4] = (cur4 & ~0x001f8000) | + (T(RRD) << 15); + + nvkm_debug(subdev, "Entry: 290: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nvkm_debug(subdev, " 2a0: %08x\n", + timing[4]); + return 0; +} +#undef T + static void gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) { @@ -136,10 +176,11 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) struct nvkm_ram_data *next; u8 ver, hdr, cnt, len, strap; u32 data; + u32 timing[5]; int ref, div, out; int from, mode; int N1, M1, P; - int ret; + int i, ret; next = &ram->base.target; next->freq = freq; @@ -179,6 +220,8 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) } } + gf100_ram_timing_calc(ram, timing); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -314,28 +357,6 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) ram_wr32(fuc, 0x10f338, 0x00300220); ram_wr32(fuc, 0x10f300, 0x0000011d); ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f290, 0x02060505); - ram_wr32(fuc, 0x10f294, 0x34208288); - ram_wr32(fuc, 0x10f298, 0x44050411); - ram_wr32(fuc, 0x10f29c, 0x0000114c); - ram_wr32(fuc, 0x10f2a0, 0x42e10069); - ram_wr32(fuc, 0x10f614, 0x40044f77); - ram_wr32(fuc, 0x10f610, 0x40044f77); - ram_wr32(fuc, 0x10f344, 0x00600009); - ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f348, 0x00700008); - ram_wr32(fuc, 0x61c140, 0x19240000); - ram_wr32(fuc, 0x10f830, 0x00300017); - gf100_ram_train(fuc, 0x80021001); - gf100_ram_train(fuc, 0x80081001); - ram_wr32(fuc, 0x10f340, 0x00500004); - ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f830, 0x01300017); - ram_wr32(fuc, 0x10f830, 0x00300017); -// 0x00030020 // 0x00000000 // 0x00000000 -// 0x00020034 // 0x0000000b - ram_wr32(fuc, 0x100b0c, 0x00080028); - ram_wr32(fuc, 0x611200, 0x00003330); } else { ram_wr32(fuc, 0x10f800, 0x00001800); ram_wr32(fuc, 0x13d8f4, 0x00000000); @@ -364,11 +385,30 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) ram_wr32(fuc, 0x10f338, 0x00300200); ram_wr32(fuc, 0x10f300, 0x0000084d); ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f290, 0x0b343825); - ram_wr32(fuc, 0x10f294, 0x3483028e); - ram_wr32(fuc, 0x10f298, 0x440c0600); - ram_wr32(fuc, 0x10f29c, 0x0000214c); - ram_wr32(fuc, 0x10f2a0, 0x42e20069); + } + + for (i = 0; i < 5; i++) + ram_wr32(fuc, 0x10f290[i], timing[i]); + + if (mode == 0) { + ram_wr32(fuc, 0x10f614, 0x40044f77); + ram_wr32(fuc, 0x10f610, 0x40044f77); + ram_wr32(fuc, 0x10f344, 0x00600009); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f348, 0x00700008); + ram_wr32(fuc, 0x61c140, 0x19240000); + ram_wr32(fuc, 0x10f830, 0x00300017); + gf100_ram_train(fuc, 0x80021001); + gf100_ram_train(fuc, 0x80081001); + ram_wr32(fuc, 0x10f340, 0x00500004); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f830, 0x01300017); + ram_wr32(fuc, 0x10f830, 0x00300017); +// 0x00030020 // 0x00000000 // 0x00000000 +// 0x00020034 // 0x0000000b + ram_wr32(fuc, 0x100b0c, 0x00080028); + ram_wr32(fuc, 0x611200, 0x00003330); + } else { ram_wr32(fuc, 0x10f200, 0x00ce0000); ram_wr32(fuc, 0x10f614, 0x60044e77); ram_wr32(fuc, 0x10f610, 0x60044e77); @@ -630,7 +670,7 @@ gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) struct nvkm_subdev *subdev = &fb->subdev; struct nvkm_bios *bios = subdev->device->bios; struct gf100_ram *ram; - int ret; + int i, ret; if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) return -ENOMEM; @@ -663,11 +703,8 @@ gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) ram->fuc.r_0x137390 = ramfuc_reg(0x137390); - ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290); - ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294); - ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298); - ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c); - ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0); + for (i = 0; i < 5; i++) + ram->fuc.r_0x10f290[i] = ramfuc_reg(0x10f290 + (i * 4)); ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300); ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338); -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 03/11] nvkm/gddr5: MR calculation for timing table v1.0
Merges in skeggsb's: "fb/ram/gf10x: timing_10_0e_30" Todo: - find l3, rq - triple-check Signed-off-by: Roy Spliet <nouveau at spliet.org> --- .../drm/nouveau/include/nvkm/subdev/bios/ramcfg.h | 12 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 22 ++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c | 2 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c | 21 ++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 49 ++++++++++++---------- 5 files changed, 71 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h index 4560a52..44e4ca2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h @@ -40,6 +40,10 @@ struct nvbios_ramcfg { unsigned ramcfg_DLLoff; unsigned ramcfg_RON; unsigned ramcfg_FBVDDQ; + unsigned ramcfg_LowFreq; + unsigned ramcfg_WCKPin; + unsigned ramcfg_Hf_VREF; + unsigned ramcfg_VREFD_off; union { struct { unsigned ramcfg_00_03_01:1; @@ -82,12 +86,9 @@ struct nvbios_ramcfg { unsigned ramcfg_11_01_04:1; unsigned ramcfg_11_01_08:1; unsigned ramcfg_11_01_10:1; - unsigned ramcfg_11_01_40:1; - unsigned ramcfg_11_01_80:1; unsigned ramcfg_11_02_03:2; unsigned ramcfg_11_02_04:1; unsigned ramcfg_11_02_08:1; - unsigned ramcfg_11_02_10:1; unsigned ramcfg_11_02_40:1; unsigned ramcfg_11_02_80:1; unsigned ramcfg_11_03_0f:4; @@ -95,7 +96,6 @@ struct nvbios_ramcfg { unsigned ramcfg_11_03_c0:2; unsigned ramcfg_11_03_f0:4; unsigned ramcfg_11_04:8; - unsigned ramcfg_11_06:8; unsigned ramcfg_11_07_02:1; unsigned ramcfg_11_07_04:1; unsigned ramcfg_11_07_08:1; @@ -132,6 +132,7 @@ struct nvbios_ramcfg { unsigned timing_10_RRD:8; unsigned timing_10_XPDLL:8; unsigned timing_10_ODT:3; + unsigned timing_10_DS:2; /* empty: 15 */ unsigned timing_10_10:8; /* empty: 17 */ @@ -139,7 +140,8 @@ struct nvbios_ramcfg { unsigned timing_10_CWL:8; unsigned timing_10_FAW:8; unsigned timing_10_CKE:8; - /* empty: 22, 23 */ + unsigned timing_10_ADRCMD_T:8; /* XXX: [3:2]? */ + /* empty: 23 */ unsigned timing_10_18:8; }; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index 131d967..0d517a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -205,8 +205,11 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_10_02_20 = (nvbios_rd08(bios, data + 0x02) & 0x20) >> 5; p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_10_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_LowFreq = (nvbios_rd08(bios, data + 0x03) & 0x20) >> 5; + p->ramcfg_WCKPin = (nvbios_rd08(bios, data + 0x03) & 0x40) >> 6; p->ramcfg_10_04_01 = (nvbios_rd08(bios, data + 0x04) & 0x01) >> 0; p->ramcfg_FBVDDQ = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; + p->ramcfg_Hf_VREF = (nvbios_rd08(bios, data + 0x04) & 0x20) >> 5; p->ramcfg_10_05_0f = (nvbios_rd08(bios, data + 0x05) & 0x0f) >> 0; p->ramcfg_10_05_f0 = (nvbios_rd08(bios, data + 0x05) & 0xf0) >> 4; p->ramcfg_10_06_0f = (nvbios_rd08(bios, data + 0x06) & 0x0f) >> 0; @@ -216,6 +219,17 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_10_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; p->ramcfg_10_09_0f = (nvbios_rd08(bios, data + 0x09) & 0x0f) >> 0; p->ramcfg_10_09_f0 = (nvbios_rd08(bios, data + 0x09) & 0xf0) >> 4; + + switch (elen) { + case 0xe: + case 0xd: + p->ramcfg_VREFD_off = nvbios_rd08(bios, data + 0x0c); + case 0xc: + case 0xb: + default: + break; + } + break; case 0x11: p->ramcfg_timing = nvbios_rd08(bios, data + 0x00); @@ -225,12 +239,12 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_11_01_08 = (nvbios_rd08(bios, data + 0x01) & 0x08) >> 3; p->ramcfg_11_01_10 = (nvbios_rd08(bios, data + 0x01) & 0x10) >> 4; p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x01) & 0x20) >> 5; - p->ramcfg_11_01_40 = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6; - p->ramcfg_11_01_80 = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7; + p->ramcfg_LowFreq = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6; + p->ramcfg_WCKPin = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7; p->ramcfg_11_02_03 = (nvbios_rd08(bios, data + 0x02) & 0x03) >> 0; p->ramcfg_11_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; p->ramcfg_11_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; - p->ramcfg_11_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_Hf_VREF = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; p->ramcfg_11_02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_11_02_80 = (nvbios_rd08(bios, data + 0x02) & 0x80) >> 7; p->ramcfg_11_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; @@ -238,7 +252,7 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_11_03_c0 = (nvbios_rd08(bios, data + 0x03) & 0xc0) >> 6; p->ramcfg_11_03_f0 = (nvbios_rd08(bios, data + 0x03) & 0xf0) >> 4; p->ramcfg_11_04 = (nvbios_rd08(bios, data + 0x04) & 0xff) >> 0; - p->ramcfg_11_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_VREFD_off = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; p->ramcfg_11_07_02 = (nvbios_rd08(bios, data + 0x07) & 0x02) >> 1; p->ramcfg_11_07_04 = (nvbios_rd08(bios, data + 0x07) & 0x04) >> 2; p->ramcfg_11_07_08 = (nvbios_rd08(bios, data + 0x07) & 0x08) >> 3; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c index c36be13..f1999e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c @@ -104,6 +104,7 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, p->timing_10_ODT = nvbios_rd08(bios, data + 0x0e) & 0x07; if (p->ramcfg_ver >= 0x10) p->ramcfg_RON = nvbios_rd08(bios, data + 0x0e) & 0x07; + p->timing_10_DS = nvbios_rd08(bios, data + 0xe) & 0x30 >> 4; p->timing_10_18 = 0xff; p->timing_10_CKE = 0; @@ -117,6 +118,7 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, p->timing_10_18 = nvbios_rd08(bios, data + 0x18); case 0x18: case 0x17: + p->timing_10_ADRCMD_T = nvbios_rd08(bios, data + 0x16); case 0x16: p->timing_10_CKE = nvbios_rd08(bios, data + 0x15); case 0x15: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c index 2cc074d..22e1e0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c @@ -39,14 +39,18 @@ nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts) int rq = ram->freq < 1000000; /* XXX */ xd = !ram->next->bios.ramcfg_DLLoff; + lf = ram->next->bios.ramcfg_LowFreq; + pd = ram->next->bios.ramcfg_WCKPin; + vh = ram->next->bios.ramcfg_Hf_VREF; + vo = ram->next->bios.ramcfg_VREFD_off; switch (ram->next->bios.ramcfg_ver) { + case 0x10: + vr = 0; + l3 = (ram->mr[5] & 0x4) >> 2; + break; case 0x11: - pd = ram->next->bios.ramcfg_11_01_80; - lf = ram->next->bios.ramcfg_11_01_40; - vh = ram->next->bios.ramcfg_11_02_10; vr = ram->next->bios.ramcfg_11_02_04; - vo = ram->next->bios.ramcfg_11_06; l3 = !ram->next->bios.ramcfg_11_07_02; break; default: @@ -54,6 +58,15 @@ nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts) } switch (ram->next->bios.timing_ver) { + case 0x10: + WL = ram->next->bios.timing_10_CWL; + CL = ram->next->bios.timing_10_CL; + WR = ram->next->bios.timing_10_WR; + at[0] = ram->next->bios.timing_10_ADRCMD_T & 0x3; + at[1] = 0; + dt = ram->next->bios.timing_10_ODT; + ds = ram->next->bios.timing_10_DS; + break; case 0x20: WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; CL = (ram->next->bios.timing[1] & 0x0000001f); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 6ebdc4c..b4fe3bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -50,11 +50,7 @@ struct gf100_ramfuc { struct ramfuc_reg r_0x10f290[5]; - struct ramfuc_reg r_0x10f300; - struct ramfuc_reg r_0x10f338; - struct ramfuc_reg r_0x10f340; - struct ramfuc_reg r_0x10f344; - struct ramfuc_reg r_0x10f348; + struct ramfuc_reg r_mr[9]; struct ramfuc_reg r_0x10f910; struct ramfuc_reg r_0x10f914; @@ -226,6 +222,19 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) if (ret) return ret; + /* Determine ram-specific MR values */ + for (i = 0; i < 9; i++) + ram->base.mr[i] = ram_rd32(fuc, mr[i]); + + switch (ram->base.type) { + case NVKM_RAM_TYPE_GDDR5: + ret = nvkm_gddr5_calc(&ram->base, false); + break; + default: + ret = -ENOSYS; + break; + } + /* determine current mclk configuration */ from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */ @@ -354,9 +363,6 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) ram_nsec(fuc, 2000); ram_wr32(fuc, 0x10f314, 0x00000001); ram_wr32(fuc, 0x10f210, 0x80000000); - ram_wr32(fuc, 0x10f338, 0x00300220); - ram_wr32(fuc, 0x10f300, 0x0000011d); - ram_nsec(fuc, 1000); } else { ram_wr32(fuc, 0x10f800, 0x00001800); ram_wr32(fuc, 0x13d8f4, 0x00000000); @@ -382,25 +388,26 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) ram_nsec(fuc, 2000); ram_wr32(fuc, 0x10f314, 0x00000001); ram_wr32(fuc, 0x10f210, 0x80000000); - ram_wr32(fuc, 0x10f338, 0x00300200); - ram_wr32(fuc, 0x10f300, 0x0000084d); - ram_nsec(fuc, 1000); } + ram_wr32(fuc, mr[3], ram->base.mr[3]); + ram_wr32(fuc, mr[0], ram->base.mr[0]); + ram_nsec(fuc, 1000); + for (i = 0; i < 5; i++) ram_wr32(fuc, 0x10f290[i], timing[i]); if (mode == 0) { ram_wr32(fuc, 0x10f614, 0x40044f77); ram_wr32(fuc, 0x10f610, 0x40044f77); - ram_wr32(fuc, 0x10f344, 0x00600009); + ram_wr32(fuc, mr[6], 0x00600009); ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f348, 0x00700008); + ram_wr32(fuc, mr[7], 0x00700008); ram_wr32(fuc, 0x61c140, 0x19240000); ram_wr32(fuc, 0x10f830, 0x00300017); gf100_ram_train(fuc, 0x80021001); gf100_ram_train(fuc, 0x80081001); - ram_wr32(fuc, 0x10f340, 0x00500004); + ram_wr32(fuc, mr[5], 0x00500004); ram_nsec(fuc, 1000); ram_wr32(fuc, 0x10f830, 0x01300017); ram_wr32(fuc, 0x10f830, 0x00300017); @@ -412,11 +419,11 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) ram_wr32(fuc, 0x10f200, 0x00ce0000); ram_wr32(fuc, 0x10f614, 0x60044e77); ram_wr32(fuc, 0x10f610, 0x60044e77); - ram_wr32(fuc, 0x10f340, 0x00500000); + ram_wr32(fuc, mr[5], 0x00500000); ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f344, 0x00600228); + ram_wr32(fuc, mr[6], 0x00600228); ram_nsec(fuc, 1000); - ram_wr32(fuc, 0x10f348, 0x00700000); + ram_wr32(fuc, mr[7], 0x00700000); ram_wr32(fuc, 0x13d8f4, 0x00000000); ram_wr32(fuc, 0x61c140, 0x09a40000); @@ -706,11 +713,9 @@ gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) for (i = 0; i < 5; i++) ram->fuc.r_0x10f290[i] = ramfuc_reg(0x10f290 + (i * 4)); - ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300); - ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338); - ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340); - ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344); - ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348); + ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); + for (i = 1; i < 9; i++) + ram->fuc.r_mr[i] = ramfuc_reg(0x10f330 + ((i - 1) * 4)); ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910); ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 04/11] nvkm/ramgt215: Move ram training up the chain
Parts are re-used even on NVA3, others from GF100 on Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h | 17 +++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 92 +++++++++----- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 140 +--------------------- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 61 ++++++++++ 4 files changed, 140 insertions(+), 170 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h index b60068b..ce8a98e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h @@ -1,6 +1,7 @@ #ifndef __NVKM_FB_RAM_PRIV_H__ #define __NVKM_FB_RAM_PRIV_H__ #include "priv.h" +#include <subdev/bios/M0209.h> int nvkm_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, enum nvkm_ram_type, u64 size, u32 tags, @@ -24,6 +25,22 @@ int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); +/* Training */ +struct gt215_ram_train { + u16 mask; + struct nvbios_M0209S remap; + struct nvbios_M0209S type00; + struct nvbios_M0209S type01; + struct nvbios_M0209S type04; + struct nvbios_M0209S type06; + struct nvbios_M0209S type07; + struct nvbios_M0209S type08; + struct nvbios_M0209S type09; +}; +int gt215_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, + struct gt215_ram_train *train); +int gf100_ram_train_init(struct nvkm_ram *ram); + int gk104_ram_ctor(struct nvkm_fb *, struct nvkm_ram **, u32); int gk104_ram_init(struct nvkm_ram *ram); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index b4fe3bb..38a7e2b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -28,6 +28,7 @@ #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> +#include <subdev/bios/M0205.h> #include <subdev/bios/rammap.h> #include <subdev/bios/timing.h> #include <subdev/clk.h> @@ -549,45 +550,74 @@ gf100_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, } static int -gf100_ram_init(struct nvkm_ram *base) +gf100_ram_train_init_0(struct nvkm_ram *ram, struct gt215_ram_train *train) { - static const u8 train0[] = { - 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - }; - static const u32 train1[] = { - 0x00000000, 0xffffffff, - 0x55555555, 0xaaaaaaaa, - 0x33333333, 0xcccccccc, - 0xf0f0f0f0, 0x0f0f0f0f, - 0x00ff00ff, 0xff00ff00, - 0x0000ffff, 0xffff0000, - }; - struct gf100_ram *ram = gf100_ram(base); - struct nvkm_device *device = ram->base.fb->subdev.device; - int i; + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; + int i, j; - switch (ram->base.type) { + if ((train->mask & 0x03d3) != 0x03d3) { + nvkm_warn(subdev, "missing link training data\n"); + return -EINVAL; + } + + for (i = 0; i < 0x30; i++) { + for (j = 0; j < 8; j += 4) { + nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920 + j, 0x00000000 | + train->type08.data[i] << 4 | + train->type06.data[i]); + nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]); + nvkm_wr32(device, 0x10f920 + j, 0x00000100 | + train->type09.data[i] << 4 | + train->type07.data[i]); + nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]); + } + } + + for (j = 0; j < 8; j += 4) { + for (i = 0; i < 0x100; i++) { + nvkm_wr32(device, 0x10f968 + j, i); + nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]); + } + } + + return 0; +} + +int +gf100_ram_train_init(struct nvkm_ram *ram) +{ + u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev); + struct gt215_ram_train *train; + int ret, i; + + if (!(train = kzalloc(sizeof(*train), GFP_KERNEL))) + return -ENOMEM; + + for (i = 0; i < 0x100; i++) { + ret = gt215_ram_train_type(ram, i, ramcfg, train); + if (ret && ret != -ENOENT) + break; + } + + switch (ram->type) { case NVKM_RAM_TYPE_GDDR5: + ret = gf100_ram_train_init_0(ram, train); break; default: - return 0; + ret = 0; + break; } - /* prepare for ddr link training, and load training patterns */ - for (i = 0; i < 0x30; i++) { - nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]); - nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]); - nvkm_wr32(device, 0x10f918, train1[i % 12]); - nvkm_wr32(device, 0x10f91c, train1[i % 12]); - nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]); - nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]); - nvkm_wr32(device, 0x10f918, train1[i % 12]); - nvkm_wr32(device, 0x10f91c, train1[i % 12]); - } + kfree(train); + return ret; +} +static int +gf100_ram_init(struct nvkm_ram *base) +{ + /* XXX: Don't hook up yet for bisectability */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 7904fa4..8bf4638 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1257,144 +1257,6 @@ gk104_ram_tidy(struct nvkm_ram *base) ram_exec(&ram->fuc, false); } -struct gk104_ram_train { - u16 mask; - struct nvbios_M0209S remap; - struct nvbios_M0209S type00; - struct nvbios_M0209S type01; - struct nvbios_M0209S type04; - struct nvbios_M0209S type06; - struct nvbios_M0209S type07; - struct nvbios_M0209S type08; - struct nvbios_M0209S type09; -}; - -static int -gk104_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, - struct gk104_ram_train *train) -{ - struct nvkm_bios *bios = ram->fb->subdev.device->bios; - struct nvbios_M0205E M0205E; - struct nvbios_M0205S M0205S; - struct nvbios_M0209E M0209E; - struct nvbios_M0209S *remap = &train->remap; - struct nvbios_M0209S *value; - u8 ver, hdr, cnt, len; - u32 data; - - /* determine type of data for this index */ - if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))) - return -ENOENT; - - switch (M0205E.type) { - case 0x00: value = &train->type00; break; - case 0x01: value = &train->type01; break; - case 0x04: value = &train->type04; break; - case 0x06: value = &train->type06; break; - case 0x07: value = &train->type07; break; - case 0x08: value = &train->type08; break; - case 0x09: value = &train->type09; break; - default: - return 0; - } - - /* training data index determined by ramcfg strap */ - if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S))) - return -EINVAL; - i = M0205S.data; - - /* training data format information */ - if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E))) - return -EINVAL; - - /* ... and the raw data */ - if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value))) - return -EINVAL; - - if (M0209E.v02_07 == 2) { - /* of course! why wouldn't we have a pointer to another entry - * in the same table, and use the first one as an array of - * remap indices... - */ - if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr, - remap))) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(value->data); i++) - value->data[i] = remap->data[value->data[i]]; - } else - if (M0209E.v02_07 != 1) - return -EINVAL; - - train->mask |= 1 << M0205E.type; - return 0; -} - -static int -gk104_ram_train_init_0(struct nvkm_ram *ram, struct gk104_ram_train *train) -{ - struct nvkm_subdev *subdev = &ram->fb->subdev; - struct nvkm_device *device = subdev->device; - int i, j; - - if ((train->mask & 0x03d3) != 0x03d3) { - nvkm_warn(subdev, "missing link training data\n"); - return -EINVAL; - } - - for (i = 0; i < 0x30; i++) { - for (j = 0; j < 8; j += 4) { - nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f920 + j, 0x00000000 | - train->type08.data[i] << 4 | - train->type06.data[i]); - nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]); - nvkm_wr32(device, 0x10f920 + j, 0x00000100 | - train->type09.data[i] << 4 | - train->type07.data[i]); - nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]); - } - } - - for (j = 0; j < 8; j += 4) { - for (i = 0; i < 0x100; i++) { - nvkm_wr32(device, 0x10f968 + j, i); - nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]); - } - } - - return 0; -} - -static int -gk104_ram_train_init(struct nvkm_ram *ram) -{ - u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev); - struct gk104_ram_train *train; - int ret, i; - - if (!(train = kzalloc(sizeof(*train), GFP_KERNEL))) - return -ENOMEM; - - for (i = 0; i < 0x100; i++) { - ret = gk104_ram_train_type(ram, i, ramcfg, train); - if (ret && ret != -ENOENT) - break; - } - - switch (ram->type) { - case NVKM_RAM_TYPE_GDDR5: - ret = gk104_ram_train_init_0(ram, train); - break; - default: - ret = 0; - break; - } - - kfree(train); - return ret; -} - int gk104_ram_init(struct nvkm_ram *ram) { @@ -1439,7 +1301,7 @@ gk104_ram_init(struct nvkm_ram *ram) nvkm_wr32(device, 0x10ecc0, 0xffffffff); nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010); - return gk104_ram_train_init(ram); + return gf100_ram_train_init(ram); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 8454899..6abd0e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -267,6 +267,67 @@ gt215_link_train(struct gt215_ram *ram) return ret; } +int +gt215_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, + struct gt215_ram_train *train) +{ + struct nvkm_bios *bios = ram->fb->subdev.device->bios; + struct nvbios_M0205E M0205E; + struct nvbios_M0205S M0205S; + struct nvbios_M0209E M0209E; + struct nvbios_M0209S *remap = &train->remap; + struct nvbios_M0209S *value; + u8 ver, hdr, cnt, len; + u32 data; + + /* determine type of data for this index */ + if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))) + return -ENOENT; + + switch (M0205E.type) { + case 0x00: value = &train->type00; break; + case 0x01: value = &train->type01; break; + case 0x04: value = &train->type04; break; + case 0x06: value = &train->type06; break; + case 0x07: value = &train->type07; break; + case 0x08: value = &train->type08; break; + case 0x09: value = &train->type09; break; + default: + return 0; + } + + /* training data index determined by ramcfg strap */ + if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S))) + return -EINVAL; + i = M0205S.data; + + /* training data format information */ + if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E))) + return -EINVAL; + + /* ... and the raw data */ + if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value))) + return -EINVAL; + + if (M0209E.v02_07 == 2) { + /* of course! why wouldn't we have a pointer to another entry + * in the same table, and use the first one as an array of + * remap indices... + */ + if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr, + remap))) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(value->data); i++) + value->data[i] = remap->data[value->data[i]]; + } else + if (M0209E.v02_07 != 1) + return -EINVAL; + + train->mask |= 1 << M0205E.type; + return 0; +} + static int gt215_link_train_init(struct gt215_ram *ram) { -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 05/11] nvkm/ramgf100: Don't mandate training pattern 4
It's not found on Fermi. Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 38a7e2b..eef09bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -556,7 +556,7 @@ gf100_ram_train_init_0(struct nvkm_ram *ram, struct gt215_ram_train *train) struct nvkm_device *device = subdev->device; int i, j; - if ((train->mask & 0x03d3) != 0x03d3) { + if ((train->mask & 0x03c3) != 0x03c3) { nvkm_warn(subdev, "missing link training data\n"); return -EINVAL; } @@ -575,10 +575,13 @@ gf100_ram_train_init_0(struct nvkm_ram *ram, struct gt215_ram_train *train) } } - for (j = 0; j < 8; j += 4) { - for (i = 0; i < 0x100; i++) { - nvkm_wr32(device, 0x10f968 + j, i); - nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]); + if (train->mask & 0x10) { + for (j = 0; j < 8; j += 4) { + for (i = 0; i < 0x100; i++) { + nvkm_wr32(device, 0x10f968 + j, i); + nvkm_wr32(device, 0x10f900 + j, + train->type04.data[i]); + } } } -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 06/11] nvkm/ramgf100: Unset bit before uploading train values
Just because the blob does it too... Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index eef09bf..62359c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -620,6 +620,12 @@ gf100_ram_train_init(struct nvkm_ram *ram) static int gf100_ram_init(struct nvkm_ram *base) { + struct nvkm_subdev *subdev = &base->fb->subdev; + struct nvkm_device *device = subdev->device; + + /* XXX Why does the blob do this? */ + nvkm_mask(device, 0x137360, 0x00000002, 0x00000000); + /* XXX: Don't hook up yet for bisectability */ return 0; } -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 07/11] nvkm/ramgf100: Reinstate default ram train pattern
Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 59 +++++++++++++++++------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 62359c2..a469719 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -556,22 +556,49 @@ gf100_ram_train_init_0(struct nvkm_ram *ram, struct gt215_ram_train *train) struct nvkm_device *device = subdev->device; int i, j; - if ((train->mask & 0x03c3) != 0x03c3) { - nvkm_warn(subdev, "missing link training data\n"); - return -EINVAL; - } - - for (i = 0; i < 0x30; i++) { - for (j = 0; j < 8; j += 4) { - nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f920 + j, 0x00000000 | - train->type08.data[i] << 4 | - train->type06.data[i]); - nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]); - nvkm_wr32(device, 0x10f920 + j, 0x00000100 | - train->type09.data[i] << 4 | - train->type07.data[i]); - nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]); + static const u8 train0[] = { + 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, + 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + }; + + static const u32 train1[] = { + 0x00000000, 0xffffffff, + 0x55555555, 0xaaaaaaaa, + 0x33333333, 0xcccccccc, + 0xf0f0f0f0, 0x0f0f0f0f, + 0x00ff00ff, 0xff00ff00, + 0x0000ffff, 0xffff0000, + }; + + if ((train->mask & 0x03c3) == 0x03c3) { + for (i = 0; i < 0x30; i++) { + for (j = 0; j < 8; j += 4) { + nvkm_wr32(device, 0x10f968 + j, (i << 8)); + nvkm_wr32(device, 0x10f920 + j, 0x00000000 | + train->type08.data[i] << 4 | + train->type06.data[i]); + nvkm_wr32(device, 0x10f918 + j, + train->type00.data[i]); + nvkm_wr32(device, 0x10f920 + j, 0x00000100 | + train->type09.data[i] << 4 | + train->type07.data[i]); + nvkm_wr32(device, 0x10f918 + j, + train->type01.data[i]); + } + } + } else { + nvkm_info(subdev, "missing link training data, using defaults\n"); + + for (i = 0; i < 0x30; i++) { + for (j = 0; j < 8; j += 4) { + nvkm_wr32(device, 0x10f968 + j, (i << 8)); + nvkm_wr32(device, 0x10f920 + j, 0x00000100 | + train0[i % 12]); + nvkm_wr32(device, 0x10f918 + j, train1[i % 12]); + nvkm_wr32(device, 0x10f920 + j, 0x00000000 | + train0[i % 12]); + nvkm_wr32(device, 0x10f918 + j, train1[i % 12]); + } } } -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 08/11] nvkm/ramgt215: Add train ptrn upload for GDDR5
Signed-off-by: Roy Spliet <nouveau at spliet.org> Tested-by: Ilia Mirkin <imirkin at alum.mit.edu> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 128 +++++++++++++++++----- 2 files changed, 99 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h index ce8a98e..ef9edc5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h @@ -32,6 +32,7 @@ struct gt215_ram_train { struct nvbios_M0209S type00; struct nvbios_M0209S type01; struct nvbios_M0209S type04; + struct nvbios_M0209S type05; struct nvbios_M0209S type06; struct nvbios_M0209S type07; struct nvbios_M0209S type08; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 6abd0e3..fa85942 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -75,7 +75,7 @@ struct gt215_ramfuc { struct ramfuc_reg r_gpio[4]; }; -struct gt215_ltrain { +struct gt215_ram_train_ddr3 { enum { NVA3_TRAIN_UNKNOWN, NVA3_TRAIN_UNSUPPORTED, @@ -92,11 +92,11 @@ struct gt215_ltrain { struct gt215_ram { struct nvkm_ram base; struct gt215_ramfuc fuc; - struct gt215_ltrain ltrain; + struct gt215_ram_train_ddr3 ltrain; }; static void -gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) +gt215_link_train_calc(u32 *vals, struct gt215_ram_train_ddr3 *train) { int i, lo, hi; u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0; @@ -152,7 +152,7 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) static int gt215_link_train(struct gt215_ram *ram) { - struct gt215_ltrain *train = &ram->ltrain; + struct gt215_ram_train_ddr3 *train = &ram->ltrain; struct gt215_ramfuc *fuc = &ram->fuc; struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; @@ -288,6 +288,7 @@ gt215_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, case 0x00: value = &train->type00; break; case 0x01: value = &train->type01; break; case 0x04: value = &train->type04; break; + case 0x05: value = &train->type05; break; case 0x06: value = &train->type06; break; case 0x07: value = &train->type07; break; case 0x08: value = &train->type08; break; @@ -321,7 +322,7 @@ gt215_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, for (i = 0; i < ARRAY_SIZE(value->data); i++) value->data[i] = remap->data[value->data[i]]; } else - if (M0209E.v02_07 != 1) + if (M0209E.v02_07 > 2) return -EINVAL; train->mask |= 1 << M0205E.type; @@ -329,7 +330,47 @@ gt215_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, } static int -gt215_link_train_init(struct gt215_ram *ram) +gt215_ram_train_upload_gddr5(struct nvkm_ram *ram, + struct gt215_ram_train *train) +{ + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; + int i, j; + + static const u32 off[] = {0x00, 0x20, 0x04, 0x24}; + + if ((train->mask & 0x03c3) != 0x03c3) { + nvkm_info(subdev, + "missing link training data, not uploading patterns\n"); + return 0; + } + + for (j = 0; j < 4; j++) { + for (i = 0; i < 0x80; i++) { + nvkm_wr32(device, 0x10f8c0 + off[j], (i << 8) | i); + if (i < 0x30) { + nvkm_wr32(device, 0x10f940 + off[j], 0x00000000 | + train->type08.data[i] << 4 | + train->type06.data[i]); + nvkm_wr32(device, 0x10f900 + off[j], + train->type00.data[i]); + nvkm_wr32(device, 0x10f940 + off[j], 0x00000100 | + train->type09.data[i] << 4 | + train->type07.data[i]); + nvkm_wr32(device, 0x10f900 + off[j], + train->type01.data[i]); + } + nvkm_wr32(device, 0x10f840 + off[j], 0x00000000 | i); + nvkm_wr32(device, 0x10f840 + off[j], 0x01000000 | i); + } + } + + return 0; +} + +static int +gt215_ram_train_upload_ddr3(struct nvkm_ram *ram, + struct gt215_ram_train *train) { static const u32 pattern[16] = { 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, @@ -337,33 +378,28 @@ gt215_link_train_init(struct gt215_ram *ram) 0x33333333, 0x55555555, 0x77777777, 0x66666666, 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, }; - struct gt215_ltrain *train = &ram->ltrain; - struct nvkm_device *device = ram->base.fb->subdev.device; - struct nvkm_bios *bios = device->bios; + struct gt215_ram *gt215 = gt215_ram(ram); + struct gt215_ram_train_ddr3 *train_ddr3 = >215->ltrain; + struct nvkm_device *device = ram->fb->subdev.device; struct nvkm_mem *mem; - struct nvbios_M0205E M0205E; - u8 ver, hdr, cnt, len; u32 r001700; int ret, i = 0; - train->state = NVA3_TRAIN_UNSUPPORTED; + train_ddr3->state = NVA3_TRAIN_UNSUPPORTED; /* We support type "5" * XXX: training pattern table appears to be unused for this routine */ - if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)) - return -ENOENT; - - if (M0205E.type != 5) + if ((train->mask & 0x0020) != 0x0020) return 0; - train->state = NVA3_TRAIN_ONCE; + train_ddr3->state = NVA3_TRAIN_ONCE; - ret = ram->base.func->get(&ram->base, 0x8000, 0x10000, 0, 0x800, - &ram->ltrain.mem); + ret = ram->func->get(ram, 0x8000, 0x10000, 0, 0x800, + &train_ddr3->mem); if (ret) return ret; - mem = ram->ltrain.mem; + mem = train_ddr3->mem; nvkm_wr32(device, 0x100538, 0x10000000 | (mem->offset >> 16)); nvkm_wr32(device, 0x1005a8, 0x0000ffff); @@ -388,17 +424,50 @@ gt215_link_train_init(struct gt215_ram *ram) nvkm_wr32(device, 0x700100 + (i << 2), pattern[i]); nvkm_wr32(device, 0x1700, r001700); - train->r_100720 = nvkm_rd32(device, 0x100720); - train->r_1111e0 = nvkm_rd32(device, 0x1111e0); - train->r_111400 = nvkm_rd32(device, 0x111400); + train_ddr3->r_100720 = nvkm_rd32(device, 0x100720); + train_ddr3->r_1111e0 = nvkm_rd32(device, 0x1111e0); + train_ddr3->r_111400 = nvkm_rd32(device, 0x111400); return 0; } +int +gt215_ram_train_init(struct nvkm_ram *ram) +{ + u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev); + struct gt215_ram_train *train; + int ret, i; + + if (!(train = kzalloc(sizeof(*train), GFP_KERNEL))) + return -ENOMEM; + + for (i = 0; i < 0x100; i++) { + ret = gt215_ram_train_type(ram, i, ramcfg, train); + if (ret && ret != -ENOENT) + break; + } + + switch (ram->type) { + case NVKM_RAM_TYPE_GDDR5: + ret = gt215_ram_train_upload_gddr5(ram, train); + break; + case NVKM_RAM_TYPE_DDR3: + ret = gt215_ram_train_upload_ddr3(ram, train); + break; + default: + ret = 0; + break; + } + + kfree(train); + return ret; +} + static void -gt215_link_train_fini(struct gt215_ram *ram) +gt215_ram_train_fini(struct nvkm_ram *ram) { - if (ram->ltrain.mem) - ram->base.func->put(&ram->base, &ram->ltrain.mem); + struct gt215_ram *gt215 = gt215_ram(ram); + if (gt215->ltrain.mem) + ram->func->put(ram, >215->ltrain.mem); } /* @@ -554,7 +623,7 @@ gt215_ram_calc(struct nvkm_ram *base, u32 freq) { struct gt215_ram *ram = gt215_ram(base); struct gt215_ramfuc *fuc = &ram->fuc; - struct gt215_ltrain *train = &ram->ltrain; + struct gt215_ram_train_ddr3 *train = &ram->ltrain; struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; @@ -979,8 +1048,7 @@ gt215_ram_tidy(struct nvkm_ram *base) static int gt215_ram_init(struct nvkm_ram *base) { - struct gt215_ram *ram = gt215_ram(base); - gt215_link_train_init(ram); + gt215_ram_train_init(base); return 0; } @@ -988,7 +1056,7 @@ static void * gt215_ram_dtor(struct nvkm_ram *base) { struct gt215_ram *ram = gt215_ram(base); - gt215_link_train_fini(ram); + gt215_ram_train_fini(base); return ram; } -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 09/11] nvkm/ramgf100: Hook up ram training pattern init for NVC0+
Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index a469719..eebd20b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -653,8 +653,7 @@ gf100_ram_init(struct nvkm_ram *base) /* XXX Why does the blob do this? */ nvkm_mask(device, 0x137360, 0x00000002, 0x00000000); - /* XXX: Don't hook up yet for bisectability */ - return 0; + return gf100_ram_train_init(base); } static const struct nvkm_ram_func -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 10/11] nvkm/pmu/memx: init script -> memx translation
Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h | 2 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h | 8 +++ drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 66 +++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h index f37538eb..b9c46ef 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h @@ -50,4 +50,6 @@ void nvkm_memx_train(struct nvkm_memx *); int nvkm_memx_train_result(struct nvkm_pmu *, u32 *, int); void nvkm_memx_block(struct nvkm_memx *); void nvkm_memx_unblock(struct nvkm_memx *); +void nvkm_memx_init_run(struct nvkm_memx *memx, struct nvkm_bios *bios, + u16 offset, u8 ramcfg); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h index 9ef9d6a..614e716 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h @@ -160,6 +160,13 @@ ramfuc_unblock(struct ramfuc *ram) nvkm_memx_unblock(ram->memx); } +static inline void +ramfuc_init_run(struct ramfuc *ram, struct nvkm_bios *bios, u16 offset, + u8 ramcfg) +{ + nvkm_memx_init_run(ram->memx, bios, offset, ramcfg); +} + #define ram_init(s,p) ramfuc_init(&(s)->base, (p)) #define ram_exec(s,e) ramfuc_exec(&(s)->base, (e)) #define ram_have(s,r) ((s)->r_##r.addr != 0x000000) @@ -174,4 +181,5 @@ ramfuc_unblock(struct ramfuc *ram) #define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l)) #define ram_block(s) ramfuc_block(&(s)->base) #define ram_unblock(s) ramfuc_unblock(&(s)->base) +#define ram_init_run(s,b,o,r) ramfuc_init_run(&(s)->base, (b), (o), (r)) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index e6f7416..c58a51d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -1,6 +1,9 @@ #ifndef __NVKM_PMU_MEMX_H__ #define __NVKM_PMU_MEMX_H__ #include "priv.h" +#include <subdev/bios.h> +#include <subdev/bios/init.h> +#include <subdev/bios/ramcfg.h> struct nvkm_memx { struct nvkm_pmu *pmu; @@ -200,4 +203,67 @@ nvkm_memx_unblock(struct nvkm_memx *memx) nvkm_debug(&memx->pmu->subdev, " HOST UNBLOCKED\n"); memx_cmd(memx, MEMX_LEAVE, 0, NULL); } + +/****************************************************************************** + * Turn VBIOS init script into memx command stream. Not-quite as feature rich + * as subdev/bios/init.c + *****************************************************************************/ + +static void +nvkm_memx_init_ram_restrict(struct nvkm_memx *memx, struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + struct nvkm_subdev *subdev = &memx->pmu->subdev; + struct nvkm_device *device = subdev->device; + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 incr = nvbios_rd08(bios, init->offset + 5); + u8 num = nvbios_rd08(bios, init->offset + 6); + u8 count = nvbios_ramcfg_count(init->bios); + u8 index = init->ramcfg; + u8 i; + u32 oldval, newval; + + init->offset += 7; + + for (i = 0; i < num; i++) { + oldval = nvkm_rd32(device, addr); + newval = nvbios_rd32(bios, init->offset + (4 * index)); + + if (oldval != newval) { + nvkm_memx_wr32(memx, addr, newval); + } + init->offset += 4 * count; + addr += incr; + } +} + +void +nvkm_memx_init_run(struct nvkm_memx *memx, struct nvkm_bios *bios, u16 offset, + u8 ramcfg) +{ + struct nvbios_init init = { + .subdev = &bios->subdev, + .bios = bios, + .offset = offset, + .outp = NULL, + .execute = 1, + .ramcfg = ramcfg, + }; + u8 op; + + while (init.offset) + { + op = nvbios_rd08(bios, init.offset); + switch (op) + { + case 0x8f: + nvkm_memx_init_ram_restrict(memx, &init); + break; + case 0x71: + default: + return; + } + } +} + #endif -- 2.9.3
Roy Spliet
2017-Apr-10 19:37 UTC
[Nouveau] [PATCH 11/11] nvkm/bios/perf: Retreive pointer to unk1c script
Signed-off-by: Roy Spliet <nouveau at spliet.org> --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c | 14 ++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h index 478b1c0..28555d6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h @@ -40,4 +40,5 @@ struct nvbios_perf_fan { }; int nvbios_perf_fan_parse(struct nvkm_bios *, struct nvbios_perf_fan *); +u16 nvbios_perf_script_unk1c(struct nvkm_bios *bios); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c index c306835..55c1f36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c @@ -213,3 +213,17 @@ nvbios_perf_fan_parse(struct nvkm_bios *bios, return 0; } + +u16 +nvbios_perf_script_unk1c(struct nvkm_bios *bios) +{ + struct bit_entry bit_P; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) { + return nvbios_rd16(bios, bit_P.offset + 0x1c); + } + } + + return 0x0000; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index eebd20b..def119c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -31,6 +31,7 @@ #include <subdev/bios/M0205.h> #include <subdev/bios/rammap.h> #include <subdev/bios/timing.h> +#include <subdev/bios/perf.h> #include <subdev/clk.h> #include <subdev/clk/pll.h> #include <subdev/ltc.h> -- 2.9.3
Possibly Parallel Threads
- [PATCH 04/11] nvkm/ramgt215: Move ram training up the chain
- [PATCH 07/11] nvkm/ramgf100: Reinstate default ram train pattern
- [PATCH 08/11] nvkm/ramgt215: Add train ptrn upload for GDDR5
- Preparations for Fermi DRAM clock changes
- RESEND Preparations for Fermi DRAM clock changes