/* * Copyright 2013 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs
*/ #define gk104_ram(p) container_of((p), struct gk104_ram, base) #include"ram.h" #include"ramfuc.h"
/*XXX: there does appear to be some kind of condition here, simply * modifying these bits in the vbios from the default pl0 * entries shows no change. however, the data does appear to * be correct and may be required for the transition back
*/
mask = 0x800f07e0;
data = 0x00030000; if (ram_rd32(fuc, 0x10f978) & 0x00800000)
data |= 0x00040000;
if (1) {
data |= 0x800807e0; switch (next->bios.ramcfg_11_03_c0) { case 3: data &= ~0x00000040; break; case 2: data &= ~0x00000100; break; case 1: data &= ~0x80000000; break; case 0: data &= ~0x00000400; break;
}
switch (next->bios.ramcfg_11_03_30) { case 3: data &= ~0x00000020; break; case 2: data &= ~0x00000080; break; case 1: data &= ~0x00080000; break; case 0: data &= ~0x00000200; break;
}
}
if (next->bios.ramcfg_11_02_80)
mask |= 0x03000000; if (next->bios.ramcfg_11_02_40)
mask |= 0x00002000; if (next->bios.ramcfg_11_07_10)
mask |= 0x00004000; if (next->bios.ramcfg_11_07_08)
mask |= 0x00000003; else {
mask |= 0x34000000; if (ram_rd32(fuc, 0x10f978) & 0x00800000)
mask |= 0x40000000;
}
ram_mask(fuc, 0x10f824, mask, data);
if (ram->mode != 2) {
u32 data = 0x01000100 * next->bios.ramcfg_11_04;
ram_nuke(fuc, 0x10f694);
ram_mask(fuc, 0x10f694, 0xff00ff00, data);
}
if (ram->mode == 2 && next->bios.ramcfg_11_08_10)
data = 0x00000080; else
data = 0x00000000;
ram_mask(fuc, 0x10f60c, 0x00000080, data);
mask = 0x00070000;
data = 0x00000000; if (!next->bios.ramcfg_11_02_80)
data |= 0x03000000; if (!next->bios.ramcfg_11_02_40)
data |= 0x00002000; if (!next->bios.ramcfg_11_07_10)
data |= 0x00004000; if (!next->bios.ramcfg_11_07_08)
data |= 0x00000003; else
data |= 0x74000000;
ram_mask(fuc, 0x10f824, mask, data);
if (next->bios.ramcfg_11_01_08)
data = 0x00000000; else
data = 0x00001000;
ram_mask(fuc, 0x10f200, 0x00001000, data);
if (next->bios.ramcfg_11_08_01)
data = 0x00100000; else
data = 0x00000000;
ram_mask(fuc, 0x10f82c, 0x00100000, data);
data = 0x00000000; if (next->bios.ramcfg_11_08_08)
data |= 0x00002000; if (next->bios.ramcfg_11_08_04)
data |= 0x00001000; if (next->bios.ramcfg_11_08_02)
data |= 0x00004000;
ram_mask(fuc, 0x10f830, 0x00007000, data);
data = mask = 0x00000000; if (ram->diff.ramcfg_11_08_20) { if (next->bios.ramcfg_11_08_20)
data |= 0x01000000;
mask |= 0x01000000;
}
ram_mask(fuc, 0x10f200, mask, data);
data = mask = 0x00000000; if (ram->diff.ramcfg_11_02_03) {
data |= next->bios.ramcfg_11_02_03 << 8;
mask |= 0x00000300;
} if (ram->diff.ramcfg_11_01_10) { if (next->bios.ramcfg_11_01_10)
data |= 0x70000000;
mask |= 0x70000000;
}
ram_mask(fuc, 0x10f604, mask, data);
data = mask = 0x00000000; if (ram->diff.timing_20_30_07) {
data |= next->bios.timing_20_30_07 << 28;
mask |= 0x70000000;
} if (ram->diff.ramcfg_11_01_01) { if (next->bios.ramcfg_11_01_01)
data |= 0x00000100;
mask |= 0x00000100;
}
ram_mask(fuc, 0x10f614, mask, data);
data = mask = 0x00000000; if (ram->diff.timing_20_30_07) {
data |= next->bios.timing_20_30_07 << 28;
mask |= 0x70000000;
} if (ram->diff.ramcfg_11_01_02) { if (next->bios.ramcfg_11_01_02)
data |= 0x00000100;
mask |= 0x00000100;
}
ram_mask(fuc, 0x10f610, mask, data);
mask = 0x33f00000;
data = 0x00000000; if (!next->bios.ramcfg_11_01_04)
data |= 0x20200000; if (!next->bios.ramcfg_11_07_80)
data |= 0x12800000; /*XXX: see note above about there probably being some condition * for the 10f824 stuff that uses ramcfg 3...
*/ if (next->bios.ramcfg_11_03_f0) { if (next->bios.rammap_11_08_0c) { if (!next->bios.ramcfg_11_07_80)
mask |= 0x00000020; else
data |= 0x00000020;
mask |= 0x00000004;
}
} else {
mask |= 0x40000020;
data |= 0x00000004;
}
data = mask = 0x00000000; if (ram->diff.ramcfg_11_02_03) {
data |= next->bios.ramcfg_11_02_03;
mask |= 0x00000003;
} if (ram->diff.ramcfg_11_01_10) { if (next->bios.ramcfg_11_01_10)
data |= 0x00000004;
mask |= 0x00000004;
}
data = ram_rd32(fuc, 0x10f978);
data &= ~0x00046144;
data |= 0x0000000b; if (!next->bios.ramcfg_11_07_08) { if (!next->bios.ramcfg_11_07_04)
data |= 0x0000200c; else
data |= 0x00000000;
} else {
data |= 0x00040044;
}
ram_wr32(fuc, 0x10f978, data);
if (ram->mode == 1) {
data = ram_rd32(fuc, 0x10f830) | 0x00000001;
ram_wr32(fuc, 0x10f830, data);
}
if (!next->bios.ramcfg_11_07_08) {
data = 0x88020000; if ( next->bios.ramcfg_11_07_04)
data |= 0x10000000; if (!next->bios.rammap_11_08_10)
data |= 0x00080000;
} else {
data = 0xa40e0000;
}
gk104_ram_train(fuc, 0xbc0f0000, data); if (1) /* XXX: not always? */
ram_nsec(fuc, 1000);
/*XXX: there does appear to be some kind of condition here, simply * modifying these bits in the vbios from the default pl0 * entries shows no change. however, the data does appear to * be correct and may be required for the transition back
*/
mask = 0x00010000;
data = 0x00010000;
if (1) {
mask |= 0x800807e0;
data |= 0x800807e0; switch (next->bios.ramcfg_11_03_c0) { case 3: data &= ~0x00000040; break; case 2: data &= ~0x00000100; break; case 1: data &= ~0x80000000; break; case 0: data &= ~0x00000400; break;
}
switch (next->bios.ramcfg_11_03_30) { case 3: data &= ~0x00000020; break; case 2: data &= ~0x00000080; break; case 1: data &= ~0x00080000; break; case 0: data &= ~0x00000200; break;
}
}
if (next->bios.ramcfg_11_02_80)
mask |= 0x03000000; if (next->bios.ramcfg_11_02_40)
mask |= 0x00002000; if (next->bios.ramcfg_11_07_10)
mask |= 0x00004000; if (next->bios.ramcfg_11_07_08)
mask |= 0x00000003; else
mask |= 0x14000000;
ram_mask(fuc, 0x10f824, mask, data);
mask = 0x00010000;
data = 0x00000000; if (!next->bios.ramcfg_11_02_80)
data |= 0x03000000; if (!next->bios.ramcfg_11_02_40)
data |= 0x00002000; if (!next->bios.ramcfg_11_07_10)
data |= 0x00004000; if (!next->bios.ramcfg_11_07_08)
data |= 0x00000003; else
data |= 0x14000000;
ram_mask(fuc, 0x10f824, mask, data);
ram_nsec(fuc, 1000);
if (next->bios.ramcfg_11_08_01)
data = 0x00100000; else
data = 0x00000000;
ram_mask(fuc, 0x10f82c, 0x00100000, data);
mask = 0x33f00000;
data = 0x00000000; if (!next->bios.ramcfg_11_01_04)
data |= 0x20200000; if (!next->bios.ramcfg_11_07_80)
data |= 0x12800000; /*XXX: see note above about there probably being some condition * for the 10f824 stuff that uses ramcfg 3...
*/ if (next->bios.ramcfg_11_03_f0) { if (next->bios.rammap_11_08_0c) { if (!next->bios.ramcfg_11_07_80)
mask |= 0x00000020; else
data |= 0x00000020;
mask |= 0x08000004;
}
data |= 0x04000000;
} else {
mask |= 0x44000020;
data |= 0x08000004;
}
data = (next->bios.timing[10] & 0x7f000000) >> 24; if (data < next->bios.timing_20_2c_1fc0)
data = next->bios.timing_20_2c_1fc0;
ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
if (ram->base.fb->subdev.device->disp)
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
if (next->bios.rammap_11_08_01)
data = 0x00000800; else
data = 0x00000000;
ram_mask(fuc, 0x10f200, 0x00000800, data); return 0;
}
/******************************************************************************* * main hooks
******************************************************************************/
nvkm_error(subdev, "ramcfg data for %dMHz not found\n", mhz); return -EINVAL;
}
staticint
gk104_calc_pll_output(int fN, int M, int N, int P, int clk)
{ return ((clk * N) + (((u16)(fN + 4096) * clk) >> 13)) / (M * P);
}
staticint
gk104_pll_calc_hiclk(int target_khz, int crystal, int *N1, int *fN1, int *M1, int *P1, int *N2, int *M2, int *P2)
{ int best_err = target_khz, p_ref, n_ref; bool upper = false;
*M1 = 1; /* M has to be 1, otherwise it gets unstable */
*M2 = 1; /* can be 1 or 2, sticking with 1 for simplicity */
*P2 = 1;
for (p_ref = 0x7; p_ref >= 0x5; --p_ref) { for (n_ref = 0x25; n_ref <= 0x2b; ++n_ref) { int cur_N, cur_clk, cur_err;
/* XXX: this is *not* what nvidia do. on fermi nvidia generally * select, based on some unknown condition, one of the two possible * reference frequencies listed in the vbios table for mempll and * program refpll to that frequency. * * so far, i've seen very weird values being chosen by nvidia on * kepler boards, no idea how/why they're chosen.
*/
refclk = next->freq; if (ram->mode == 2) {
ret = gk104_pll_calc_hiclk(next->freq, subdev->device->crystal,
&ram->N1, &ram->fN1, &ram->M1, &ram->P1,
&ram->N2, &ram->M2, &ram->P2);
fuc->mempll.refclk = ret; if (ret <= 0) {
nvkm_error(subdev, "unable to calc plls\n"); return -EINVAL;
}
nvkm_debug(subdev, "successfully calced PLLs for clock %i kHz" " (refclock: %i kHz)\n", next->freq, ret);
} else { /* calculate refpll coefficients */
ret = gt215_pll_calc(subdev, &fuc->refpll, refclk, &ram->N1,
&ram->fN1, &ram->M1, &ram->P1);
fuc->mempll.refclk = ret; if (ret <= 0) {
nvkm_error(subdev, "unable to calc refpll\n"); return -EINVAL;
}
}
for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) { if (ram_have(fuc, mr[i]))
ram->base.mr[i] = ram_rd32(fuc, mr[i]);
}
ram->base.freq = next->freq;
switch (ram->base.type) { case NVKM_RAM_TYPE_DDR3:
ret = nvkm_sddr3_calc(&ram->base); if (ret == 0)
ret = gk104_ram_calc_sddr3(ram, next->freq); break; case NVKM_RAM_TYPE_GDDR5:
ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0); if (ret == 0)
ret = gk104_ram_calc_gddr5(ram, next->freq); break; default:
ret = -ENOSYS; break;
}
/* 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;
/* run a bunch of tables from rammap table. there's actually * individual pointers for each rammap entry too, but, nvidia * seem to just run the last two entries' scripts early on in * their init, and never again.. we'll just run 'em all once * for now. * * i strongly suspect that each script is for a separate mode * (likely selected by 0x10f65c's lower bits?), and the * binary driver skips the one that's already been setup by * the init tables.
*/
data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); if (!data || hdr < 0x15) return -EINVAL;
cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */
data = nvbios_rd32(bios, data + 0x10); /* guess u32... */
save = nvkm_rd32(device, 0x10f65c) & 0x000000f0; for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) {
nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4);
nvbios_init(subdev, nvbios_rd32(bios, data));
}
}
nvkm_mask(device, 0x10f65c, 0x000000f0, save);
nvkm_mask(device, 0x10f584, 0x11000000, 0x00000000);
nvkm_wr32(device, 0x10ecc0, 0xffffffff);
nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010);
if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL))) return -ENOMEM;
p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
n = &cfg->bios;
/* 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); if (ret = 0, i == 0) goto done;
if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) return -ENOMEM;
*pram = &ram->base;
ret = gf100_ram_ctor(func, fb, &ram->base); if (ret) return ret;
INIT_LIST_HEAD(&ram->cfg);
/* calculate a mask of differently configured memory partitions, * because, of course reclocking wasn't complicated enough * already without having to treat some of them differently to * the others....
*/
ram->parts = nvkm_rd32(device, 0x022438);
ram->pmask = nvkm_rd32(device, 0x022554);
ram->pnuts = 0; for (i = 0, tmp = 0; i < ram->parts; i++) { if (!(ram->pmask & (1 << i))) {
u32 cfg1 = nvkm_rd32(device, 0x110204 + (i * 0x1000)); if (tmp && tmp != cfg1) {
ram->pnuts |= (1 << i); continue;
}
tmp = cfg1;
}
}
/* parse bios data for all rammap table entries up-front, and * build information on whether certain fields differ between * any of the entries. * * the binary driver appears to completely ignore some fields * when all entries contain the same value. at first, it was * hoped that these were mere optimisations and the bios init * tables had configured as per the values here, but there is * evidence now to suggest that this isn't the case and we do * need to treat this condition as a "don't touch" indicator.
*/ for (i = 0; !ret; i++) {
ret = gk104_ram_ctor_data(ram, ramcfg, i); if (ret && ret != -ENOENT) {
nvkm_error(subdev, "failed to parse ramcfg data\n"); return ret;
}
}
/* parse bios data for both pll's */
ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); if (ret) {
nvkm_error(subdev, "mclk refpll data not found\n"); return ret;
}
ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll); if (ret) {
nvkm_error(subdev, "mclk pll data not found\n"); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.