1639c308eSBen Skeggs /*
2639c308eSBen Skeggs * Copyright 2013 Red Hat Inc.
3639c308eSBen Skeggs *
4639c308eSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5639c308eSBen Skeggs * copy of this software and associated documentation files (the "Software"),
6639c308eSBen Skeggs * to deal in the Software without restriction, including without limitation
7639c308eSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8639c308eSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9639c308eSBen Skeggs * Software is furnished to do so, subject to the following conditions:
10639c308eSBen Skeggs *
11639c308eSBen Skeggs * The above copyright notice and this permission notice shall be included in
12639c308eSBen Skeggs * all copies or substantial portions of the Software.
13639c308eSBen Skeggs *
14639c308eSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15639c308eSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16639c308eSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17639c308eSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18639c308eSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19639c308eSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20639c308eSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21639c308eSBen Skeggs *
22639c308eSBen Skeggs * Authors: Ben Skeggs
23639c308eSBen Skeggs * Roy Spliet <rspliet@eclipso.eu>
24639c308eSBen Skeggs */
25d36a99d2SBen Skeggs #define gt215_ram(p) container_of((p), struct gt215_ram, base)
26d36a99d2SBen Skeggs #include "ram.h"
27639c308eSBen Skeggs #include "ramfuc.h"
28639c308eSBen Skeggs
292bfa0b01SBen Skeggs #include <core/memory.h>
30639c308eSBen Skeggs #include <core/option.h>
31639c308eSBen Skeggs #include <subdev/bios.h>
32639c308eSBen Skeggs #include <subdev/bios/M0205.h>
33639c308eSBen Skeggs #include <subdev/bios/rammap.h>
34639c308eSBen Skeggs #include <subdev/bios/timing.h>
35639c308eSBen Skeggs #include <subdev/clk/gt215.h>
36639c308eSBen Skeggs #include <subdev/gpio.h>
37639c308eSBen Skeggs
38639c308eSBen Skeggs struct gt215_ramfuc {
39639c308eSBen Skeggs struct ramfuc base;
40639c308eSBen Skeggs struct ramfuc_reg r_0x001610;
41639c308eSBen Skeggs struct ramfuc_reg r_0x001700;
42639c308eSBen Skeggs struct ramfuc_reg r_0x002504;
43639c308eSBen Skeggs struct ramfuc_reg r_0x004000;
44639c308eSBen Skeggs struct ramfuc_reg r_0x004004;
45639c308eSBen Skeggs struct ramfuc_reg r_0x004018;
46639c308eSBen Skeggs struct ramfuc_reg r_0x004128;
47639c308eSBen Skeggs struct ramfuc_reg r_0x004168;
48639c308eSBen Skeggs struct ramfuc_reg r_0x100080;
49639c308eSBen Skeggs struct ramfuc_reg r_0x100200;
50639c308eSBen Skeggs struct ramfuc_reg r_0x100210;
51639c308eSBen Skeggs struct ramfuc_reg r_0x100220[9];
52639c308eSBen Skeggs struct ramfuc_reg r_0x100264;
53639c308eSBen Skeggs struct ramfuc_reg r_0x1002d0;
54639c308eSBen Skeggs struct ramfuc_reg r_0x1002d4;
55639c308eSBen Skeggs struct ramfuc_reg r_0x1002dc;
56639c308eSBen Skeggs struct ramfuc_reg r_0x10053c;
57639c308eSBen Skeggs struct ramfuc_reg r_0x1005a0;
58639c308eSBen Skeggs struct ramfuc_reg r_0x1005a4;
59639c308eSBen Skeggs struct ramfuc_reg r_0x100700;
60639c308eSBen Skeggs struct ramfuc_reg r_0x100714;
61639c308eSBen Skeggs struct ramfuc_reg r_0x100718;
62639c308eSBen Skeggs struct ramfuc_reg r_0x10071c;
63639c308eSBen Skeggs struct ramfuc_reg r_0x100720;
64639c308eSBen Skeggs struct ramfuc_reg r_0x100760;
65639c308eSBen Skeggs struct ramfuc_reg r_0x1007a0;
66639c308eSBen Skeggs struct ramfuc_reg r_0x1007e0;
67639c308eSBen Skeggs struct ramfuc_reg r_0x100da0;
68639c308eSBen Skeggs struct ramfuc_reg r_0x10f804;
69639c308eSBen Skeggs struct ramfuc_reg r_0x1110e0;
70639c308eSBen Skeggs struct ramfuc_reg r_0x111100;
71639c308eSBen Skeggs struct ramfuc_reg r_0x111104;
72639c308eSBen Skeggs struct ramfuc_reg r_0x1111e0;
73639c308eSBen Skeggs struct ramfuc_reg r_0x111400;
74639c308eSBen Skeggs struct ramfuc_reg r_0x611200;
75639c308eSBen Skeggs struct ramfuc_reg r_mr[4];
76e0a37f85SRoy Spliet struct ramfuc_reg r_gpio[4];
77639c308eSBen Skeggs };
78639c308eSBen Skeggs
79639c308eSBen Skeggs struct gt215_ltrain {
80639c308eSBen Skeggs enum {
81639c308eSBen Skeggs NVA3_TRAIN_UNKNOWN,
82639c308eSBen Skeggs NVA3_TRAIN_UNSUPPORTED,
83639c308eSBen Skeggs NVA3_TRAIN_ONCE,
84639c308eSBen Skeggs NVA3_TRAIN_EXEC,
85639c308eSBen Skeggs NVA3_TRAIN_DONE
86639c308eSBen Skeggs } state;
87639c308eSBen Skeggs u32 r_100720;
88639c308eSBen Skeggs u32 r_1111e0;
89639c308eSBen Skeggs u32 r_111400;
902bfa0b01SBen Skeggs struct nvkm_memory *memory;
91639c308eSBen Skeggs };
92639c308eSBen Skeggs
93639c308eSBen Skeggs struct gt215_ram {
94639c308eSBen Skeggs struct nvkm_ram base;
95639c308eSBen Skeggs struct gt215_ramfuc fuc;
96639c308eSBen Skeggs struct gt215_ltrain ltrain;
97639c308eSBen Skeggs };
98639c308eSBen Skeggs
99e08a1d97SBaoyou Xie static void
gt215_link_train_calc(u32 * vals,struct gt215_ltrain * train)100639c308eSBen Skeggs gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train)
101639c308eSBen Skeggs {
102639c308eSBen Skeggs int i, lo, hi;
103639c308eSBen Skeggs u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
104639c308eSBen Skeggs
105639c308eSBen Skeggs for (i = 0; i < 8; i++) {
106639c308eSBen Skeggs for (lo = 0; lo < 0x40; lo++) {
107639c308eSBen Skeggs if (!(vals[lo] & 0x80000000))
108639c308eSBen Skeggs continue;
109639c308eSBen Skeggs if (vals[lo] & (0x101 << i))
110639c308eSBen Skeggs break;
111639c308eSBen Skeggs }
112639c308eSBen Skeggs
113639c308eSBen Skeggs if (lo == 0x40)
114639c308eSBen Skeggs return;
115639c308eSBen Skeggs
116639c308eSBen Skeggs for (hi = lo + 1; hi < 0x40; hi++) {
117639c308eSBen Skeggs if (!(vals[lo] & 0x80000000))
118639c308eSBen Skeggs continue;
119639c308eSBen Skeggs if (!(vals[hi] & (0x101 << i))) {
120639c308eSBen Skeggs hi--;
121639c308eSBen Skeggs break;
122639c308eSBen Skeggs }
123639c308eSBen Skeggs }
124639c308eSBen Skeggs
125639c308eSBen Skeggs median[i] = ((hi - lo) >> 1) + lo;
126639c308eSBen Skeggs bins[(median[i] & 0xf0) >> 4]++;
127639c308eSBen Skeggs median[i] += 0x30;
128639c308eSBen Skeggs }
129639c308eSBen Skeggs
130639c308eSBen Skeggs /* Find the best value for 0x1111e0 */
131639c308eSBen Skeggs for (i = 0; i < 4; i++) {
132639c308eSBen Skeggs if (bins[i] > qty) {
133639c308eSBen Skeggs bin = i + 3;
134639c308eSBen Skeggs qty = bins[i];
135639c308eSBen Skeggs }
136639c308eSBen Skeggs }
137639c308eSBen Skeggs
138639c308eSBen Skeggs train->r_100720 = 0;
139639c308eSBen Skeggs for (i = 0; i < 8; i++) {
140639c308eSBen Skeggs median[i] = max(median[i], (u8) (bin << 4));
141639c308eSBen Skeggs median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
142639c308eSBen Skeggs
143639c308eSBen Skeggs train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
144639c308eSBen Skeggs }
145639c308eSBen Skeggs
146639c308eSBen Skeggs train->r_1111e0 = 0x02000000 | (bin * 0x101);
147639c308eSBen Skeggs train->r_111400 = 0x0;
148639c308eSBen Skeggs }
149639c308eSBen Skeggs
150639c308eSBen Skeggs /*
151639c308eSBen Skeggs * Link training for (at least) DDR3
152639c308eSBen Skeggs */
153e08a1d97SBaoyou Xie static int
gt215_link_train(struct gt215_ram * ram)154d36a99d2SBen Skeggs gt215_link_train(struct gt215_ram *ram)
155639c308eSBen Skeggs {
156639c308eSBen Skeggs struct gt215_ltrain *train = &ram->ltrain;
157639c308eSBen Skeggs struct gt215_ramfuc *fuc = &ram->fuc;
158d36a99d2SBen Skeggs struct nvkm_subdev *subdev = &ram->base.fb->subdev;
1593ecd329bSBen Skeggs struct nvkm_device *device = subdev->device;
1603ecd329bSBen Skeggs struct nvkm_bios *bios = device->bios;
1613ecd329bSBen Skeggs struct nvkm_clk *clk = device->clk;
162639c308eSBen Skeggs u32 *result, r1700;
163639c308eSBen Skeggs int ret, i;
164639c308eSBen Skeggs struct nvbios_M0205T M0205T = { 0 };
165639c308eSBen Skeggs u8 ver, hdr, cnt, len, snr, ssz;
166639c308eSBen Skeggs unsigned int clk_current;
167639c308eSBen Skeggs unsigned long flags;
168639c308eSBen Skeggs unsigned long *f = &flags;
169639c308eSBen Skeggs
170639c308eSBen Skeggs if (nvkm_boolopt(device->cfgopt, "NvMemExec", true) != true)
171639c308eSBen Skeggs return -ENOSYS;
172639c308eSBen Skeggs
173639c308eSBen Skeggs /* XXX: Multiple partitions? */
174*6da2ec56SKees Cook result = kmalloc_array(64, sizeof(u32), GFP_KERNEL);
175639c308eSBen Skeggs if (!result)
176639c308eSBen Skeggs return -ENOMEM;
177639c308eSBen Skeggs
178639c308eSBen Skeggs train->state = NVA3_TRAIN_EXEC;
179639c308eSBen Skeggs
180639c308eSBen Skeggs /* Clock speeds for training and back */
181639c308eSBen Skeggs nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
182b1e4553cSBen Skeggs if (M0205T.freq == 0) {
183b1e4553cSBen Skeggs kfree(result);
184639c308eSBen Skeggs return -ENOENT;
185b1e4553cSBen Skeggs }
186639c308eSBen Skeggs
1876625f55cSBen Skeggs clk_current = nvkm_clk_read(clk, nv_clk_src_mem);
188639c308eSBen Skeggs
189639c308eSBen Skeggs ret = gt215_clk_pre(clk, f);
190639c308eSBen Skeggs if (ret)
191639c308eSBen Skeggs goto out;
192639c308eSBen Skeggs
193639c308eSBen Skeggs /* First: clock up/down */
194d36a99d2SBen Skeggs ret = ram->base.func->calc(&ram->base, (u32) M0205T.freq * 1000);
195639c308eSBen Skeggs if (ret)
196639c308eSBen Skeggs goto out;
197639c308eSBen Skeggs
198639c308eSBen Skeggs /* Do this *after* calc, eliminates write in script */
1996758745bSBen Skeggs nvkm_wr32(device, 0x111400, 0x00000000);
200639c308eSBen Skeggs /* XXX: Magic writes that improve train reliability? */
2016758745bSBen Skeggs nvkm_mask(device, 0x100674, 0x0000ffff, 0x00000000);
2026758745bSBen Skeggs nvkm_mask(device, 0x1005e4, 0x0000ffff, 0x00000000);
2036758745bSBen Skeggs nvkm_mask(device, 0x100b0c, 0x000000ff, 0x00000000);
2046758745bSBen Skeggs nvkm_wr32(device, 0x100c04, 0x00000400);
205639c308eSBen Skeggs
206639c308eSBen Skeggs /* Now the training script */
207639c308eSBen Skeggs r1700 = ram_rd32(fuc, 0x001700);
208639c308eSBen Skeggs
209639c308eSBen Skeggs ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
210639c308eSBen Skeggs ram_wr32(fuc, 0x611200, 0x3300);
211639c308eSBen Skeggs ram_wait_vblank(fuc);
212639c308eSBen Skeggs ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
213639c308eSBen Skeggs ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
214639c308eSBen Skeggs ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
215639c308eSBen Skeggs ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
216639c308eSBen Skeggs ram_wr32(fuc, 0x001700, 0x00000000);
217639c308eSBen Skeggs
218639c308eSBen Skeggs ram_train(fuc);
219639c308eSBen Skeggs
220639c308eSBen Skeggs /* Reset */
221639c308eSBen Skeggs ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
222639c308eSBen Skeggs ram_wr32(fuc, 0x10053c, 0x0);
223639c308eSBen Skeggs ram_wr32(fuc, 0x100720, train->r_100720);
224639c308eSBen Skeggs ram_wr32(fuc, 0x1111e0, train->r_1111e0);
225639c308eSBen Skeggs ram_wr32(fuc, 0x111400, train->r_111400);
226639c308eSBen Skeggs ram_nuke(fuc, 0x100080);
227639c308eSBen Skeggs ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
228639c308eSBen Skeggs ram_nsec(fuc, 1000);
229639c308eSBen Skeggs
230639c308eSBen Skeggs ram_wr32(fuc, 0x001700, r1700);
231639c308eSBen Skeggs ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
232639c308eSBen Skeggs ram_wr32(fuc, 0x611200, 0x3330);
233639c308eSBen Skeggs ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
234639c308eSBen Skeggs
235639c308eSBen Skeggs ram_exec(fuc, true);
236639c308eSBen Skeggs
237d36a99d2SBen Skeggs ram->base.func->calc(&ram->base, clk_current);
238639c308eSBen Skeggs ram_exec(fuc, true);
239639c308eSBen Skeggs
240639c308eSBen Skeggs /* Post-processing, avoids flicker */
2416758745bSBen Skeggs nvkm_mask(device, 0x616308, 0x10, 0x10);
2426758745bSBen Skeggs nvkm_mask(device, 0x616b08, 0x10, 0x10);
243639c308eSBen Skeggs
244639c308eSBen Skeggs gt215_clk_post(clk, f);
245639c308eSBen Skeggs
246d36a99d2SBen Skeggs ram_train_result(ram->base.fb, result, 64);
247639c308eSBen Skeggs for (i = 0; i < 64; i++)
2483ecd329bSBen Skeggs nvkm_debug(subdev, "Train: %08x", result[i]);
249639c308eSBen Skeggs gt215_link_train_calc(result, train);
250639c308eSBen Skeggs
2513ecd329bSBen Skeggs nvkm_debug(subdev, "Train: %08x %08x %08x", train->r_100720,
252639c308eSBen Skeggs train->r_1111e0, train->r_111400);
253639c308eSBen Skeggs
254639c308eSBen Skeggs kfree(result);
255639c308eSBen Skeggs
256639c308eSBen Skeggs train->state = NVA3_TRAIN_DONE;
257639c308eSBen Skeggs
258639c308eSBen Skeggs return ret;
259639c308eSBen Skeggs
260639c308eSBen Skeggs out:
261639c308eSBen Skeggs if(ret == -EBUSY)
262639c308eSBen Skeggs f = NULL;
263639c308eSBen Skeggs
264639c308eSBen Skeggs train->state = NVA3_TRAIN_UNSUPPORTED;
265639c308eSBen Skeggs
266639c308eSBen Skeggs gt215_clk_post(clk, f);
267b1e4553cSBen Skeggs kfree(result);
268639c308eSBen Skeggs return ret;
269639c308eSBen Skeggs }
270639c308eSBen Skeggs
271e08a1d97SBaoyou Xie static int
gt215_link_train_init(struct gt215_ram * ram)272d36a99d2SBen Skeggs gt215_link_train_init(struct gt215_ram *ram)
273639c308eSBen Skeggs {
274639c308eSBen Skeggs static const u32 pattern[16] = {
275639c308eSBen Skeggs 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
276639c308eSBen Skeggs 0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
277639c308eSBen Skeggs 0x33333333, 0x55555555, 0x77777777, 0x66666666,
278639c308eSBen Skeggs 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
279639c308eSBen Skeggs };
280639c308eSBen Skeggs struct gt215_ltrain *train = &ram->ltrain;
281d36a99d2SBen Skeggs struct nvkm_device *device = ram->base.fb->subdev.device;
282d36a99d2SBen Skeggs struct nvkm_bios *bios = device->bios;
283639c308eSBen Skeggs struct nvbios_M0205E M0205E;
284639c308eSBen Skeggs u8 ver, hdr, cnt, len;
285639c308eSBen Skeggs u32 r001700;
2862bfa0b01SBen Skeggs u64 addr;
287639c308eSBen Skeggs int ret, i = 0;
288639c308eSBen Skeggs
289639c308eSBen Skeggs train->state = NVA3_TRAIN_UNSUPPORTED;
290639c308eSBen Skeggs
291639c308eSBen Skeggs /* We support type "5"
292639c308eSBen Skeggs * XXX: training pattern table appears to be unused for this routine */
293639c308eSBen Skeggs if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
294639c308eSBen Skeggs return -ENOENT;
295639c308eSBen Skeggs
296639c308eSBen Skeggs if (M0205E.type != 5)
297639c308eSBen Skeggs return 0;
298639c308eSBen Skeggs
299639c308eSBen Skeggs train->state = NVA3_TRAIN_ONCE;
300639c308eSBen Skeggs
3012bfa0b01SBen Skeggs ret = nvkm_ram_get(device, NVKM_RAM_MM_NORMAL, 0x01, 16, 0x8000,
3022bfa0b01SBen Skeggs true, true, &ram->ltrain.memory);
303639c308eSBen Skeggs if (ret)
304639c308eSBen Skeggs return ret;
305639c308eSBen Skeggs
3062bfa0b01SBen Skeggs addr = nvkm_memory_addr(ram->ltrain.memory);
307639c308eSBen Skeggs
3082bfa0b01SBen Skeggs nvkm_wr32(device, 0x100538, 0x10000000 | (addr >> 16));
3096758745bSBen Skeggs nvkm_wr32(device, 0x1005a8, 0x0000ffff);
3106758745bSBen Skeggs nvkm_mask(device, 0x10f800, 0x00000001, 0x00000001);
311639c308eSBen Skeggs
312639c308eSBen Skeggs for (i = 0; i < 0x30; i++) {
3136758745bSBen Skeggs nvkm_wr32(device, 0x10f8c0, (i << 8) | i);
3146758745bSBen Skeggs nvkm_wr32(device, 0x10f900, pattern[i % 16]);
315639c308eSBen Skeggs }
316639c308eSBen Skeggs
317639c308eSBen Skeggs for (i = 0; i < 0x30; i++) {
3186758745bSBen Skeggs nvkm_wr32(device, 0x10f8e0, (i << 8) | i);
3196758745bSBen Skeggs nvkm_wr32(device, 0x10f920, pattern[i % 16]);
320639c308eSBen Skeggs }
321639c308eSBen Skeggs
322639c308eSBen Skeggs /* And upload the pattern */
3236758745bSBen Skeggs r001700 = nvkm_rd32(device, 0x1700);
3242bfa0b01SBen Skeggs nvkm_wr32(device, 0x1700, addr >> 16);
325639c308eSBen Skeggs for (i = 0; i < 16; i++)
3266758745bSBen Skeggs nvkm_wr32(device, 0x700000 + (i << 2), pattern[i]);
327639c308eSBen Skeggs for (i = 0; i < 16; i++)
3286758745bSBen Skeggs nvkm_wr32(device, 0x700100 + (i << 2), pattern[i]);
3296758745bSBen Skeggs nvkm_wr32(device, 0x1700, r001700);
330639c308eSBen Skeggs
3316758745bSBen Skeggs train->r_100720 = nvkm_rd32(device, 0x100720);
3326758745bSBen Skeggs train->r_1111e0 = nvkm_rd32(device, 0x1111e0);
3336758745bSBen Skeggs train->r_111400 = nvkm_rd32(device, 0x111400);
334639c308eSBen Skeggs return 0;
335639c308eSBen Skeggs }
336639c308eSBen Skeggs
337e08a1d97SBaoyou Xie static void
gt215_link_train_fini(struct gt215_ram * ram)338d36a99d2SBen Skeggs gt215_link_train_fini(struct gt215_ram *ram)
339639c308eSBen Skeggs {
3402bfa0b01SBen Skeggs nvkm_memory_unref(&ram->ltrain.memory);
341639c308eSBen Skeggs }
342639c308eSBen Skeggs
343639c308eSBen Skeggs /*
344639c308eSBen Skeggs * RAM reclocking
345639c308eSBen Skeggs */
346639c308eSBen Skeggs #define T(t) cfg->timing_10_##t
347639c308eSBen Skeggs static int
gt215_ram_timing_calc(struct gt215_ram * ram,u32 * timing)348d36a99d2SBen Skeggs gt215_ram_timing_calc(struct gt215_ram *ram, u32 *timing)
349639c308eSBen Skeggs {
350639c308eSBen Skeggs struct nvbios_ramcfg *cfg = &ram->base.target.bios;
351d36a99d2SBen Skeggs struct nvkm_subdev *subdev = &ram->base.fb->subdev;
3523ecd329bSBen Skeggs struct nvkm_device *device = subdev->device;
353639c308eSBen Skeggs int tUNK_base, tUNK_40_0, prevCL;
354639c308eSBen Skeggs u32 cur2, cur3, cur7, cur8;
355639c308eSBen Skeggs
3566758745bSBen Skeggs cur2 = nvkm_rd32(device, 0x100228);
3576758745bSBen Skeggs cur3 = nvkm_rd32(device, 0x10022c);
3586758745bSBen Skeggs cur7 = nvkm_rd32(device, 0x10023c);
3596758745bSBen Skeggs cur8 = nvkm_rd32(device, 0x100240);
360639c308eSBen Skeggs
361639c308eSBen Skeggs
362639c308eSBen Skeggs switch ((!T(CWL)) * ram->base.type) {
363d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR2:
364639c308eSBen Skeggs T(CWL) = T(CL) - 1;
365639c308eSBen Skeggs break;
366d36a99d2SBen Skeggs case NVKM_RAM_TYPE_GDDR3:
367639c308eSBen Skeggs T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
368639c308eSBen Skeggs break;
369639c308eSBen Skeggs }
370639c308eSBen Skeggs
371639c308eSBen Skeggs prevCL = (cur3 & 0x000000ff) + 1;
372639c308eSBen Skeggs tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
373639c308eSBen Skeggs
374639c308eSBen Skeggs timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
375639c308eSBen Skeggs timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
376639c308eSBen Skeggs max_t(u8,T(18), 1) << 16 |
377639c308eSBen Skeggs (T(WTR) + 1 + T(CWL)) << 8 |
378639c308eSBen Skeggs (5 + T(CL) - T(CWL));
379639c308eSBen Skeggs timing[2] = (T(CWL) - 1) << 24 |
380639c308eSBen Skeggs (T(RRD) << 16) |
381639c308eSBen Skeggs (T(RCDWR) << 8) |
382639c308eSBen Skeggs T(RCDRD);
383639c308eSBen Skeggs timing[3] = (cur3 & 0x00ff0000) |
384639c308eSBen Skeggs (0x30 + T(CL)) << 24 |
385639c308eSBen Skeggs (0xb + T(CL)) << 8 |
386639c308eSBen Skeggs (T(CL) - 1);
387639c308eSBen Skeggs timing[4] = T(20) << 24 |
388639c308eSBen Skeggs T(21) << 16 |
389639c308eSBen Skeggs T(13) << 8 |
390639c308eSBen Skeggs T(13);
391639c308eSBen Skeggs timing[5] = T(RFC) << 24 |
392639c308eSBen Skeggs max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
393639c308eSBen Skeggs max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
394639c308eSBen Skeggs T(RP);
395639c308eSBen Skeggs timing[6] = (0x5a + T(CL)) << 16 |
396639c308eSBen Skeggs max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
397639c308eSBen Skeggs (0x50 + T(CL) - T(CWL));
398639c308eSBen Skeggs timing[7] = (cur7 & 0xff000000) |
399639c308eSBen Skeggs ((tUNK_base + T(CL)) << 16) |
400639c308eSBen Skeggs 0x202;
401639c308eSBen Skeggs timing[8] = cur8 & 0xffffff00;
402639c308eSBen Skeggs
403639c308eSBen Skeggs switch (ram->base.type) {
404d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR2:
405d36a99d2SBen Skeggs case NVKM_RAM_TYPE_GDDR3:
406639c308eSBen Skeggs tUNK_40_0 = prevCL - (cur8 & 0xff);
407639c308eSBen Skeggs if (tUNK_40_0 > 0)
408639c308eSBen Skeggs timing[8] |= T(CL);
409639c308eSBen Skeggs break;
410639c308eSBen Skeggs default:
411639c308eSBen Skeggs break;
412639c308eSBen Skeggs }
413639c308eSBen Skeggs
4143ecd329bSBen Skeggs nvkm_debug(subdev, "Entry: 220: %08x %08x %08x %08x\n",
415639c308eSBen Skeggs timing[0], timing[1], timing[2], timing[3]);
4163ecd329bSBen Skeggs nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n",
417639c308eSBen Skeggs timing[4], timing[5], timing[6], timing[7]);
4183ecd329bSBen Skeggs nvkm_debug(subdev, " 240: %08x\n", timing[8]);
419639c308eSBen Skeggs return 0;
420639c308eSBen Skeggs }
421639c308eSBen Skeggs #undef T
422639c308eSBen Skeggs
423639c308eSBen Skeggs static void
nvkm_sddr2_dll_reset(struct gt215_ramfuc * fuc)424639c308eSBen Skeggs nvkm_sddr2_dll_reset(struct gt215_ramfuc *fuc)
425639c308eSBen Skeggs {
426639c308eSBen Skeggs ram_mask(fuc, mr[0], 0x100, 0x100);
427639c308eSBen Skeggs ram_nsec(fuc, 1000);
428639c308eSBen Skeggs ram_mask(fuc, mr[0], 0x100, 0x000);
429639c308eSBen Skeggs ram_nsec(fuc, 1000);
430639c308eSBen Skeggs }
431639c308eSBen Skeggs
432639c308eSBen Skeggs static void
nvkm_sddr3_dll_disable(struct gt215_ramfuc * fuc,u32 * mr)433639c308eSBen Skeggs nvkm_sddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
434639c308eSBen Skeggs {
435639c308eSBen Skeggs u32 mr1_old = ram_rd32(fuc, mr[1]);
436639c308eSBen Skeggs
437639c308eSBen Skeggs if (!(mr1_old & 0x1)) {
438639c308eSBen Skeggs ram_wr32(fuc, 0x1002d4, 0x00000001);
439639c308eSBen Skeggs ram_wr32(fuc, mr[1], mr[1]);
440639c308eSBen Skeggs ram_nsec(fuc, 1000);
441639c308eSBen Skeggs }
442639c308eSBen Skeggs }
443639c308eSBen Skeggs
444639c308eSBen Skeggs static void
nvkm_gddr3_dll_disable(struct gt215_ramfuc * fuc,u32 * mr)445639c308eSBen Skeggs nvkm_gddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
446639c308eSBen Skeggs {
447639c308eSBen Skeggs u32 mr1_old = ram_rd32(fuc, mr[1]);
448639c308eSBen Skeggs
449639c308eSBen Skeggs if (!(mr1_old & 0x40)) {
450639c308eSBen Skeggs ram_wr32(fuc, mr[1], mr[1]);
451639c308eSBen Skeggs ram_nsec(fuc, 1000);
452639c308eSBen Skeggs }
453639c308eSBen Skeggs }
454639c308eSBen Skeggs
455639c308eSBen Skeggs static void
gt215_ram_lock_pll(struct gt215_ramfuc * fuc,struct gt215_clk_info * mclk)456639c308eSBen Skeggs gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk)
457639c308eSBen Skeggs {
458639c308eSBen Skeggs ram_wr32(fuc, 0x004004, mclk->pll);
459639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
460639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
461639c308eSBen Skeggs ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
462639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
463639c308eSBen Skeggs }
464639c308eSBen Skeggs
465639c308eSBen Skeggs static void
gt215_ram_gpio(struct gt215_ramfuc * fuc,u8 tag,u32 val)466e0a37f85SRoy Spliet gt215_ram_gpio(struct gt215_ramfuc *fuc, u8 tag, u32 val)
467639c308eSBen Skeggs {
4682ea7249fSBen Skeggs struct nvkm_gpio *gpio = fuc->base.fb->subdev.device->gpio;
469639c308eSBen Skeggs struct dcb_gpio_func func;
470639c308eSBen Skeggs u32 reg, sh, gpio_val;
471639c308eSBen Skeggs int ret;
472639c308eSBen Skeggs
473e0a37f85SRoy Spliet if (nvkm_gpio_get(gpio, 0, tag, DCB_GPIO_UNUSED) != val) {
474e0a37f85SRoy Spliet ret = nvkm_gpio_find(gpio, 0, tag, DCB_GPIO_UNUSED, &func);
475639c308eSBen Skeggs if (ret)
476639c308eSBen Skeggs return;
477639c308eSBen Skeggs
478e0a37f85SRoy Spliet reg = func.line >> 3;
479e0a37f85SRoy Spliet sh = (func.line & 0x7) << 2;
480e0a37f85SRoy Spliet gpio_val = ram_rd32(fuc, gpio[reg]);
481639c308eSBen Skeggs if (gpio_val & (8 << sh))
482639c308eSBen Skeggs val = !val;
483e0a37f85SRoy Spliet if (!(func.log[1] & 1))
484e0a37f85SRoy Spliet val = !val;
485639c308eSBen Skeggs
486e0a37f85SRoy Spliet ram_mask(fuc, gpio[reg], (0x3 << sh), ((val | 0x2) << sh));
487639c308eSBen Skeggs ram_nsec(fuc, 20000);
488639c308eSBen Skeggs }
489639c308eSBen Skeggs }
490639c308eSBen Skeggs
491639c308eSBen Skeggs static int
gt215_ram_calc(struct nvkm_ram * base,u32 freq)492d36a99d2SBen Skeggs gt215_ram_calc(struct nvkm_ram *base, u32 freq)
493639c308eSBen Skeggs {
494d36a99d2SBen Skeggs struct gt215_ram *ram = gt215_ram(base);
495639c308eSBen Skeggs struct gt215_ramfuc *fuc = &ram->fuc;
496639c308eSBen Skeggs struct gt215_ltrain *train = &ram->ltrain;
497d36a99d2SBen Skeggs struct nvkm_subdev *subdev = &ram->base.fb->subdev;
4983ecd329bSBen Skeggs struct nvkm_device *device = subdev->device;
4993ecd329bSBen Skeggs struct nvkm_bios *bios = device->bios;
500639c308eSBen Skeggs struct gt215_clk_info mclk;
501ef6e8f4cSRoy Spliet struct nvkm_gpio *gpio = device->gpio;
502639c308eSBen Skeggs struct nvkm_ram_data *next;
503639c308eSBen Skeggs u8 ver, hdr, cnt, len, strap;
504639c308eSBen Skeggs u32 data;
505639c308eSBen Skeggs u32 r004018, r100760, r100da0, r111100, ctrl;
506639c308eSBen Skeggs u32 unk714, unk718, unk71c;
507639c308eSBen Skeggs int ret, i;
508639c308eSBen Skeggs u32 timing[9];
509639c308eSBen Skeggs bool pll2pll;
510639c308eSBen Skeggs
511639c308eSBen Skeggs next = &ram->base.target;
512639c308eSBen Skeggs next->freq = freq;
513639c308eSBen Skeggs ram->base.next = next;
514639c308eSBen Skeggs
515639c308eSBen Skeggs if (ram->ltrain.state == NVA3_TRAIN_ONCE)
516d36a99d2SBen Skeggs gt215_link_train(ram);
517639c308eSBen Skeggs
518639c308eSBen Skeggs /* lookup memory config data relevant to the target frequency */
519639c308eSBen Skeggs data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
520639c308eSBen Skeggs &next->bios);
521639c308eSBen Skeggs if (!data || ver != 0x10 || hdr < 0x05) {
5223ecd329bSBen Skeggs nvkm_error(subdev, "invalid/missing rammap entry\n");
523639c308eSBen Skeggs return -EINVAL;
524639c308eSBen Skeggs }
525639c308eSBen Skeggs
526639c308eSBen Skeggs /* locate specific data set for the attached memory */
527d36a99d2SBen Skeggs strap = nvbios_ramcfg_index(subdev);
528639c308eSBen Skeggs if (strap >= cnt) {
5293ecd329bSBen Skeggs nvkm_error(subdev, "invalid ramcfg strap\n");
530639c308eSBen Skeggs return -EINVAL;
531639c308eSBen Skeggs }
532639c308eSBen Skeggs
533639c308eSBen Skeggs data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
534639c308eSBen Skeggs &ver, &hdr, &next->bios);
535639c308eSBen Skeggs if (!data || ver != 0x10 || hdr < 0x09) {
5363ecd329bSBen Skeggs nvkm_error(subdev, "invalid/missing ramcfg entry\n");
537639c308eSBen Skeggs return -EINVAL;
538639c308eSBen Skeggs }
539639c308eSBen Skeggs
540639c308eSBen Skeggs /* lookup memory timings, if bios says they're present */
541639c308eSBen Skeggs if (next->bios.ramcfg_timing != 0xff) {
542639c308eSBen Skeggs data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
543639c308eSBen Skeggs &ver, &hdr, &cnt, &len,
544639c308eSBen Skeggs &next->bios);
545639c308eSBen Skeggs if (!data || ver != 0x10 || hdr < 0x17) {
5463ecd329bSBen Skeggs nvkm_error(subdev, "invalid/missing timing entry\n");
547639c308eSBen Skeggs return -EINVAL;
548639c308eSBen Skeggs }
549639c308eSBen Skeggs }
550639c308eSBen Skeggs
551d36a99d2SBen Skeggs ret = gt215_pll_info(device->clk, 0x12, 0x4000, freq, &mclk);
552639c308eSBen Skeggs if (ret < 0) {
5533ecd329bSBen Skeggs nvkm_error(subdev, "failed mclk calculation\n");
554639c308eSBen Skeggs return ret;
555639c308eSBen Skeggs }
556639c308eSBen Skeggs
557d36a99d2SBen Skeggs gt215_ram_timing_calc(ram, timing);
558639c308eSBen Skeggs
559d36a99d2SBen Skeggs ret = ram_init(fuc, ram->base.fb);
560639c308eSBen Skeggs if (ret)
561639c308eSBen Skeggs return ret;
562639c308eSBen Skeggs
563639c308eSBen Skeggs /* Determine ram-specific MR values */
564639c308eSBen Skeggs ram->base.mr[0] = ram_rd32(fuc, mr[0]);
565639c308eSBen Skeggs ram->base.mr[1] = ram_rd32(fuc, mr[1]);
566639c308eSBen Skeggs ram->base.mr[2] = ram_rd32(fuc, mr[2]);
567639c308eSBen Skeggs
568639c308eSBen Skeggs switch (ram->base.type) {
569d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR2:
570639c308eSBen Skeggs ret = nvkm_sddr2_calc(&ram->base);
571639c308eSBen Skeggs break;
572d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR3:
573639c308eSBen Skeggs ret = nvkm_sddr3_calc(&ram->base);
574639c308eSBen Skeggs break;
575d36a99d2SBen Skeggs case NVKM_RAM_TYPE_GDDR3:
576639c308eSBen Skeggs ret = nvkm_gddr3_calc(&ram->base);
577639c308eSBen Skeggs break;
578639c308eSBen Skeggs default:
579639c308eSBen Skeggs ret = -ENOSYS;
580639c308eSBen Skeggs break;
581639c308eSBen Skeggs }
582639c308eSBen Skeggs
583639c308eSBen Skeggs if (ret)
584639c308eSBen Skeggs return ret;
585639c308eSBen Skeggs
5863b582bedSRoy Spliet /* XXX: 750MHz seems rather arbitrary */
587639c308eSBen Skeggs if (freq <= 750000) {
588639c308eSBen Skeggs r004018 = 0x10000000;
589639c308eSBen Skeggs r100760 = 0x22222222;
590639c308eSBen Skeggs r100da0 = 0x00000010;
591639c308eSBen Skeggs } else {
592639c308eSBen Skeggs r004018 = 0x00000000;
593639c308eSBen Skeggs r100760 = 0x00000000;
594639c308eSBen Skeggs r100da0 = 0x00000000;
595639c308eSBen Skeggs }
596639c308eSBen Skeggs
5977164f4c5SRoy Spliet if (!next->bios.ramcfg_DLLoff)
598639c308eSBen Skeggs r004018 |= 0x00004000;
599639c308eSBen Skeggs
600639c308eSBen Skeggs /* pll2pll requires to switch to a safe clock first */
601639c308eSBen Skeggs ctrl = ram_rd32(fuc, 0x004000);
602639c308eSBen Skeggs pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
603639c308eSBen Skeggs
604639c308eSBen Skeggs /* Pre, NVIDIA does this outside the script */
605639c308eSBen Skeggs if (next->bios.ramcfg_10_02_10) {
606639c308eSBen Skeggs ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
607639c308eSBen Skeggs } else {
608639c308eSBen Skeggs ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
609639c308eSBen Skeggs ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
610639c308eSBen Skeggs }
611639c308eSBen Skeggs /* Always disable this bit during reclock */
612639c308eSBen Skeggs ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
613639c308eSBen Skeggs
614639c308eSBen Skeggs /* If switching from non-pll to pll, lock before disabling FB */
615639c308eSBen Skeggs if (mclk.pll && !pll2pll) {
616639c308eSBen Skeggs ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
617639c308eSBen Skeggs gt215_ram_lock_pll(fuc, &mclk);
618639c308eSBen Skeggs }
619639c308eSBen Skeggs
620639c308eSBen Skeggs /* Start with disabling some CRTCs and PFIFO? */
621639c308eSBen Skeggs ram_wait_vblank(fuc);
622639c308eSBen Skeggs ram_wr32(fuc, 0x611200, 0x3300);
623639c308eSBen Skeggs ram_mask(fuc, 0x002504, 0x1, 0x1);
624639c308eSBen Skeggs ram_nsec(fuc, 10000);
625639c308eSBen Skeggs ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
626639c308eSBen Skeggs ram_block(fuc);
627639c308eSBen Skeggs ram_nsec(fuc, 2000);
628639c308eSBen Skeggs
629639c308eSBen Skeggs if (!next->bios.ramcfg_10_02_10) {
630d36a99d2SBen Skeggs if (ram->base.type == NVKM_RAM_TYPE_GDDR3)
631639c308eSBen Skeggs ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
632639c308eSBen Skeggs else
633639c308eSBen Skeggs ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
634639c308eSBen Skeggs }
635639c308eSBen Skeggs
636639c308eSBen Skeggs /* If we're disabling the DLL, do it now */
6377164f4c5SRoy Spliet switch (next->bios.ramcfg_DLLoff * ram->base.type) {
638d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR3:
639639c308eSBen Skeggs nvkm_sddr3_dll_disable(fuc, ram->base.mr);
640639c308eSBen Skeggs break;
641d36a99d2SBen Skeggs case NVKM_RAM_TYPE_GDDR3:
642639c308eSBen Skeggs nvkm_gddr3_dll_disable(fuc, ram->base.mr);
643639c308eSBen Skeggs break;
644639c308eSBen Skeggs }
645639c308eSBen Skeggs
646e0a37f85SRoy Spliet if (next->bios.timing_10_ODT)
647e0a37f85SRoy Spliet gt215_ram_gpio(fuc, 0x2e, 1);
648639c308eSBen Skeggs
649639c308eSBen Skeggs /* Brace RAM for impact */
650639c308eSBen Skeggs ram_wr32(fuc, 0x1002d4, 0x00000001);
651639c308eSBen Skeggs ram_wr32(fuc, 0x1002d0, 0x00000001);
652639c308eSBen Skeggs ram_wr32(fuc, 0x1002d0, 0x00000001);
653639c308eSBen Skeggs ram_wr32(fuc, 0x100210, 0x00000000);
654639c308eSBen Skeggs ram_wr32(fuc, 0x1002dc, 0x00000001);
655639c308eSBen Skeggs ram_nsec(fuc, 2000);
656639c308eSBen Skeggs
657d36a99d2SBen Skeggs if (device->chipset == 0xa3 && freq <= 500000)
658639c308eSBen Skeggs ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
659639c308eSBen Skeggs
660ef6e8f4cSRoy Spliet /* Alter FBVDD/Q, apparently must be done with PLL disabled, thus
661ef6e8f4cSRoy Spliet * set it to bypass */
662ef6e8f4cSRoy Spliet if (nvkm_gpio_get(gpio, 0, 0x18, DCB_GPIO_UNUSED) ==
663ef6e8f4cSRoy Spliet next->bios.ramcfg_FBVDDQ) {
664ef6e8f4cSRoy Spliet data = ram_rd32(fuc, 0x004000) & 0x9;
665ef6e8f4cSRoy Spliet
666ef6e8f4cSRoy Spliet if (data == 0x1)
667ef6e8f4cSRoy Spliet ram_mask(fuc, 0x004000, 0x8, 0x8);
668ef6e8f4cSRoy Spliet if (data & 0x1)
669ef6e8f4cSRoy Spliet ram_mask(fuc, 0x004000, 0x1, 0x0);
670ef6e8f4cSRoy Spliet
671ef6e8f4cSRoy Spliet gt215_ram_gpio(fuc, 0x18, !next->bios.ramcfg_FBVDDQ);
672ef6e8f4cSRoy Spliet
673ef6e8f4cSRoy Spliet if (data & 0x1)
674ef6e8f4cSRoy Spliet ram_mask(fuc, 0x004000, 0x1, 0x1);
675ef6e8f4cSRoy Spliet }
676ef6e8f4cSRoy Spliet
677639c308eSBen Skeggs /* Fiddle with clocks */
678639c308eSBen Skeggs /* There's 4 scenario's
679639c308eSBen Skeggs * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
680639c308eSBen Skeggs * clk->pll: Set up new PLL, switch
681639c308eSBen Skeggs * pll->clk: Set up clock, switch
682639c308eSBen Skeggs * clk->clk: Overwrite ctrl and other bits, switch */
683639c308eSBen Skeggs
684639c308eSBen Skeggs /* Switch to regular clock - 324MHz */
685639c308eSBen Skeggs if (pll2pll) {
686639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
687639c308eSBen Skeggs ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
688639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
689639c308eSBen Skeggs ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
690639c308eSBen Skeggs ram_wr32(fuc, 0x004018, 0x00001000);
691639c308eSBen Skeggs gt215_ram_lock_pll(fuc, &mclk);
692639c308eSBen Skeggs }
693639c308eSBen Skeggs
694639c308eSBen Skeggs if (mclk.pll) {
695639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
696639c308eSBen Skeggs ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
697639c308eSBen Skeggs ram_wr32(fuc, 0x100da0, r100da0);
698639c308eSBen Skeggs } else {
699639c308eSBen Skeggs ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
700639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
701639c308eSBen Skeggs ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
702639c308eSBen Skeggs ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
703639c308eSBen Skeggs ram_wr32(fuc, 0x100da0, r100da0);
704639c308eSBen Skeggs }
705639c308eSBen Skeggs ram_nsec(fuc, 20000);
706639c308eSBen Skeggs
707639c308eSBen Skeggs if (next->bios.rammap_10_04_08) {
708639c308eSBen Skeggs ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
709639c308eSBen Skeggs next->bios.ramcfg_10_05 << 8 |
710639c308eSBen Skeggs next->bios.ramcfg_10_05);
711639c308eSBen Skeggs ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
712639c308eSBen Skeggs next->bios.ramcfg_10_07);
713639c308eSBen Skeggs ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
714639c308eSBen Skeggs next->bios.ramcfg_10_03_0f << 16 |
715639c308eSBen Skeggs next->bios.ramcfg_10_09_0f |
716639c308eSBen Skeggs 0x80000000);
717639c308eSBen Skeggs ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
718639c308eSBen Skeggs } else {
719639c308eSBen Skeggs if (train->state == NVA3_TRAIN_DONE) {
720639c308eSBen Skeggs ram_wr32(fuc, 0x100080, 0x1020);
721639c308eSBen Skeggs ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
722639c308eSBen Skeggs ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
723639c308eSBen Skeggs ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
724639c308eSBen Skeggs }
725639c308eSBen Skeggs ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
726639c308eSBen Skeggs ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
727639c308eSBen Skeggs ram_mask(fuc, 0x100760, 0x22222222, r100760);
728639c308eSBen Skeggs ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
729639c308eSBen Skeggs ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
730639c308eSBen Skeggs }
731639c308eSBen Skeggs
732d36a99d2SBen Skeggs if (device->chipset == 0xa3 && freq > 500000) {
733639c308eSBen Skeggs ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
734639c308eSBen Skeggs }
735639c308eSBen Skeggs
736639c308eSBen Skeggs /* Final switch */
737639c308eSBen Skeggs if (mclk.pll) {
738639c308eSBen Skeggs ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
739639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
740639c308eSBen Skeggs }
741639c308eSBen Skeggs
742639c308eSBen Skeggs ram_wr32(fuc, 0x1002dc, 0x00000000);
743639c308eSBen Skeggs ram_wr32(fuc, 0x1002d4, 0x00000001);
744639c308eSBen Skeggs ram_wr32(fuc, 0x100210, 0x80000000);
745639c308eSBen Skeggs ram_nsec(fuc, 2000);
746639c308eSBen Skeggs
747639c308eSBen Skeggs /* Set RAM MR parameters and timings */
748639c308eSBen Skeggs for (i = 2; i >= 0; i--) {
749639c308eSBen Skeggs if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
750639c308eSBen Skeggs ram_wr32(fuc, mr[i], ram->base.mr[i]);
751639c308eSBen Skeggs ram_nsec(fuc, 1000);
752639c308eSBen Skeggs }
753639c308eSBen Skeggs }
754639c308eSBen Skeggs
755639c308eSBen Skeggs ram_wr32(fuc, 0x100220[3], timing[3]);
756639c308eSBen Skeggs ram_wr32(fuc, 0x100220[1], timing[1]);
757639c308eSBen Skeggs ram_wr32(fuc, 0x100220[6], timing[6]);
758639c308eSBen Skeggs ram_wr32(fuc, 0x100220[7], timing[7]);
759639c308eSBen Skeggs ram_wr32(fuc, 0x100220[2], timing[2]);
760639c308eSBen Skeggs ram_wr32(fuc, 0x100220[4], timing[4]);
761639c308eSBen Skeggs ram_wr32(fuc, 0x100220[5], timing[5]);
762639c308eSBen Skeggs ram_wr32(fuc, 0x100220[0], timing[0]);
763639c308eSBen Skeggs ram_wr32(fuc, 0x100220[8], timing[8]);
764639c308eSBen Skeggs
765639c308eSBen Skeggs /* Misc */
766639c308eSBen Skeggs ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
767639c308eSBen Skeggs
768639c308eSBen Skeggs /* XXX: A lot of "chipset"/"ram type" specific stuff...? */
769639c308eSBen Skeggs unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000130;
770639c308eSBen Skeggs unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
771639c308eSBen Skeggs unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
772639c308eSBen Skeggs r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
773639c308eSBen Skeggs
7740b0b78cdSRoy Spliet /* NVA8 seems to skip various bits related to ramcfg_10_02_04 */
7750b0b78cdSRoy Spliet if (device->chipset == 0xa8) {
7760b0b78cdSRoy Spliet r111100 |= 0x08000000;
7770b0b78cdSRoy Spliet if (!next->bios.ramcfg_10_02_04)
7780b0b78cdSRoy Spliet unk714 |= 0x00000010;
7790b0b78cdSRoy Spliet } else {
780639c308eSBen Skeggs if (next->bios.ramcfg_10_02_04) {
781639c308eSBen Skeggs switch (ram->base.type) {
782d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR2:
7830b0b78cdSRoy Spliet case NVKM_RAM_TYPE_DDR3:
7840b0b78cdSRoy Spliet r111100 &= ~0x00000020;
7850b0b78cdSRoy Spliet if (next->bios.ramcfg_10_02_10)
7860b0b78cdSRoy Spliet r111100 |= 0x08000004;
7870b0b78cdSRoy Spliet else
7880b0b78cdSRoy Spliet r111100 |= 0x00000024;
789639c308eSBen Skeggs break;
790639c308eSBen Skeggs default:
791639c308eSBen Skeggs break;
792639c308eSBen Skeggs }
793639c308eSBen Skeggs } else {
794639c308eSBen Skeggs switch (ram->base.type) {
795d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR2:
796d36a99d2SBen Skeggs case NVKM_RAM_TYPE_DDR3:
7970b0b78cdSRoy Spliet r111100 &= ~0x00000024;
798639c308eSBen Skeggs r111100 |= 0x12800000;
7990b0b78cdSRoy Spliet
8000b0b78cdSRoy Spliet if (next->bios.ramcfg_10_02_10)
8010b0b78cdSRoy Spliet r111100 |= 0x08000000;
802639c308eSBen Skeggs unk714 |= 0x00000010;
803639c308eSBen Skeggs break;
804d36a99d2SBen Skeggs case NVKM_RAM_TYPE_GDDR3:
805639c308eSBen Skeggs r111100 |= 0x30000000;
806639c308eSBen Skeggs unk714 |= 0x00000020;
807639c308eSBen Skeggs break;
808639c308eSBen Skeggs default:
809639c308eSBen Skeggs break;
810639c308eSBen Skeggs }
811639c308eSBen Skeggs }
8120b0b78cdSRoy Spliet }
813639c308eSBen Skeggs
814639c308eSBen Skeggs unk714 |= (next->bios.ramcfg_10_04_01) << 8;
815639c308eSBen Skeggs
816639c308eSBen Skeggs if (next->bios.ramcfg_10_02_20)
817639c308eSBen Skeggs unk714 |= 0xf0000000;
818639c308eSBen Skeggs if (next->bios.ramcfg_10_02_02)
819639c308eSBen Skeggs unk718 |= 0x00000100;
820639c308eSBen Skeggs if (next->bios.ramcfg_10_02_01)
821639c308eSBen Skeggs unk71c |= 0x00000100;
822639c308eSBen Skeggs if (next->bios.timing_10_24 != 0xff) {
823639c308eSBen Skeggs unk718 &= ~0xf0000000;
824639c308eSBen Skeggs unk718 |= next->bios.timing_10_24 << 28;
825639c308eSBen Skeggs }
826639c308eSBen Skeggs if (next->bios.ramcfg_10_02_10)
827639c308eSBen Skeggs r111100 &= ~0x04020000;
828639c308eSBen Skeggs
829639c308eSBen Skeggs ram_mask(fuc, 0x100714, 0xffffffff, unk714);
830639c308eSBen Skeggs ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
831639c308eSBen Skeggs ram_mask(fuc, 0x100718, 0xffffffff, unk718);
832639c308eSBen Skeggs ram_mask(fuc, 0x111100, 0xffffffff, r111100);
833639c308eSBen Skeggs
834e0a37f85SRoy Spliet if (!next->bios.timing_10_ODT)
835e0a37f85SRoy Spliet gt215_ram_gpio(fuc, 0x2e, 0);
836639c308eSBen Skeggs
837639c308eSBen Skeggs /* Reset DLL */
8387164f4c5SRoy Spliet if (!next->bios.ramcfg_DLLoff)
839639c308eSBen Skeggs nvkm_sddr2_dll_reset(fuc);
840639c308eSBen Skeggs
841d36a99d2SBen Skeggs if (ram->base.type == NVKM_RAM_TYPE_GDDR3) {
842639c308eSBen Skeggs ram_nsec(fuc, 31000);
843639c308eSBen Skeggs } else {
844639c308eSBen Skeggs ram_nsec(fuc, 14000);
845639c308eSBen Skeggs }
846639c308eSBen Skeggs
847d36a99d2SBen Skeggs if (ram->base.type == NVKM_RAM_TYPE_DDR3) {
848639c308eSBen Skeggs ram_wr32(fuc, 0x100264, 0x1);
849639c308eSBen Skeggs ram_nsec(fuc, 2000);
850639c308eSBen Skeggs }
851639c308eSBen Skeggs
852639c308eSBen Skeggs ram_nuke(fuc, 0x100700);
853639c308eSBen Skeggs ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
854639c308eSBen Skeggs ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
855639c308eSBen Skeggs
856639c308eSBen Skeggs /* Re-enable FB */
857639c308eSBen Skeggs ram_unblock(fuc);
858639c308eSBen Skeggs ram_wr32(fuc, 0x611200, 0x3330);
859639c308eSBen Skeggs
860639c308eSBen Skeggs /* Post fiddlings */
861639c308eSBen Skeggs if (next->bios.rammap_10_04_02)
862639c308eSBen Skeggs ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
863639c308eSBen Skeggs if (next->bios.ramcfg_10_02_10) {
864639c308eSBen Skeggs ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
865639c308eSBen Skeggs ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
866639c308eSBen Skeggs } else {
867639c308eSBen Skeggs ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
868639c308eSBen Skeggs }
869639c308eSBen Skeggs
870639c308eSBen Skeggs if (mclk.pll) {
871639c308eSBen Skeggs ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
872639c308eSBen Skeggs ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
873639c308eSBen Skeggs } else {
874639c308eSBen Skeggs ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
875639c308eSBen Skeggs ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
876639c308eSBen Skeggs ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
877639c308eSBen Skeggs }
878639c308eSBen Skeggs
879639c308eSBen Skeggs return 0;
880639c308eSBen Skeggs }
881639c308eSBen Skeggs
882639c308eSBen Skeggs static int
gt215_ram_prog(struct nvkm_ram * base)883d36a99d2SBen Skeggs gt215_ram_prog(struct nvkm_ram *base)
884639c308eSBen Skeggs {
885d36a99d2SBen Skeggs struct gt215_ram *ram = gt215_ram(base);
886639c308eSBen Skeggs struct gt215_ramfuc *fuc = &ram->fuc;
887d36a99d2SBen Skeggs struct nvkm_device *device = ram->base.fb->subdev.device;
888639c308eSBen Skeggs bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true);
889639c308eSBen Skeggs
890639c308eSBen Skeggs if (exec) {
8916758745bSBen Skeggs nvkm_mask(device, 0x001534, 0x2, 0x2);
892639c308eSBen Skeggs
893639c308eSBen Skeggs ram_exec(fuc, true);
894639c308eSBen Skeggs
895639c308eSBen Skeggs /* Post-processing, avoids flicker */
8966758745bSBen Skeggs nvkm_mask(device, 0x002504, 0x1, 0x0);
8976758745bSBen Skeggs nvkm_mask(device, 0x001534, 0x2, 0x0);
898639c308eSBen Skeggs
8996758745bSBen Skeggs nvkm_mask(device, 0x616308, 0x10, 0x10);
9006758745bSBen Skeggs nvkm_mask(device, 0x616b08, 0x10, 0x10);
901639c308eSBen Skeggs } else {
902639c308eSBen Skeggs ram_exec(fuc, false);
903639c308eSBen Skeggs }
904639c308eSBen Skeggs return 0;
905639c308eSBen Skeggs }
906639c308eSBen Skeggs
907639c308eSBen Skeggs static void
gt215_ram_tidy(struct nvkm_ram * base)908d36a99d2SBen Skeggs gt215_ram_tidy(struct nvkm_ram *base)
909639c308eSBen Skeggs {
910d36a99d2SBen Skeggs struct gt215_ram *ram = gt215_ram(base);
911d36a99d2SBen Skeggs ram_exec(&ram->fuc, false);
912639c308eSBen Skeggs }
913639c308eSBen Skeggs
914639c308eSBen Skeggs static int
gt215_ram_init(struct nvkm_ram * base)915d36a99d2SBen Skeggs gt215_ram_init(struct nvkm_ram *base)
916639c308eSBen Skeggs {
917d36a99d2SBen Skeggs struct gt215_ram *ram = gt215_ram(base);
918d36a99d2SBen Skeggs gt215_link_train_init(ram);
919639c308eSBen Skeggs return 0;
920639c308eSBen Skeggs }
921639c308eSBen Skeggs
922d36a99d2SBen Skeggs static void *
gt215_ram_dtor(struct nvkm_ram * base)923d36a99d2SBen Skeggs gt215_ram_dtor(struct nvkm_ram *base)
924639c308eSBen Skeggs {
925d36a99d2SBen Skeggs struct gt215_ram *ram = gt215_ram(base);
926d36a99d2SBen Skeggs gt215_link_train_fini(ram);
927d36a99d2SBen Skeggs return ram;
928639c308eSBen Skeggs }
929639c308eSBen Skeggs
930d36a99d2SBen Skeggs static const struct nvkm_ram_func
931d36a99d2SBen Skeggs gt215_ram_func = {
932d36a99d2SBen Skeggs .dtor = gt215_ram_dtor,
933d36a99d2SBen Skeggs .init = gt215_ram_init,
934d36a99d2SBen Skeggs .calc = gt215_ram_calc,
935d36a99d2SBen Skeggs .prog = gt215_ram_prog,
936d36a99d2SBen Skeggs .tidy = gt215_ram_tidy,
937d36a99d2SBen Skeggs };
938d36a99d2SBen Skeggs
939d36a99d2SBen Skeggs int
gt215_ram_new(struct nvkm_fb * fb,struct nvkm_ram ** pram)940d36a99d2SBen Skeggs gt215_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
941639c308eSBen Skeggs {
942639c308eSBen Skeggs struct gt215_ram *ram;
943d36a99d2SBen Skeggs int ret, i;
944639c308eSBen Skeggs
945d36a99d2SBen Skeggs if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL)))
946d36a99d2SBen Skeggs return -ENOMEM;
947d36a99d2SBen Skeggs *pram = &ram->base;
948d36a99d2SBen Skeggs
949d36a99d2SBen Skeggs ret = nv50_ram_ctor(>215_ram_func, fb, &ram->base);
950639c308eSBen Skeggs if (ret)
951639c308eSBen Skeggs return ret;
952639c308eSBen Skeggs
953639c308eSBen Skeggs ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
954639c308eSBen Skeggs ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
955639c308eSBen Skeggs ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
956639c308eSBen Skeggs ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
957639c308eSBen Skeggs ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
958639c308eSBen Skeggs ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
959639c308eSBen Skeggs ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
960639c308eSBen Skeggs ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
961639c308eSBen Skeggs ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
962639c308eSBen Skeggs ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
963639c308eSBen Skeggs ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
964639c308eSBen Skeggs for (i = 0; i < 9; i++)
965639c308eSBen Skeggs ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
966639c308eSBen Skeggs ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
967639c308eSBen Skeggs ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
968639c308eSBen Skeggs ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
969639c308eSBen Skeggs ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
970639c308eSBen Skeggs ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
971639c308eSBen Skeggs ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
972639c308eSBen Skeggs ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
973639c308eSBen Skeggs ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
974639c308eSBen Skeggs ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
975639c308eSBen Skeggs ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
976639c308eSBen Skeggs ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
977639c308eSBen Skeggs ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
978639c308eSBen Skeggs ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
979639c308eSBen Skeggs ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
980639c308eSBen Skeggs ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
981639c308eSBen Skeggs ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
982639c308eSBen Skeggs ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
983639c308eSBen Skeggs ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
984639c308eSBen Skeggs ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
985639c308eSBen Skeggs ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
986639c308eSBen Skeggs ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
987639c308eSBen Skeggs ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
988639c308eSBen Skeggs ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
989639c308eSBen Skeggs
990639c308eSBen Skeggs if (ram->base.ranks > 1) {
991639c308eSBen Skeggs ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
992639c308eSBen Skeggs ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
993639c308eSBen Skeggs ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
994639c308eSBen Skeggs ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
995639c308eSBen Skeggs } else {
996639c308eSBen Skeggs ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
997639c308eSBen Skeggs ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
998639c308eSBen Skeggs ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
999639c308eSBen Skeggs ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
1000639c308eSBen Skeggs }
1001e0a37f85SRoy Spliet ram->fuc.r_gpio[0] = ramfuc_reg(0x00e104);
1002e0a37f85SRoy Spliet ram->fuc.r_gpio[1] = ramfuc_reg(0x00e108);
1003e0a37f85SRoy Spliet ram->fuc.r_gpio[2] = ramfuc_reg(0x00e120);
1004e0a37f85SRoy Spliet ram->fuc.r_gpio[3] = ramfuc_reg(0x00e124);
1005639c308eSBen Skeggs
1006639c308eSBen Skeggs return 0;
1007639c308eSBen Skeggs }
1008