]>
Commit | Line | Data |
---|---|---|
75faef78 BS |
1 | /* |
2 | * Copyright 2013 Red Hat Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: Ben Skeggs | |
7f4b9616 | 23 | * Roy Spliet <rspliet@eclipso.eu> |
75faef78 | 24 | */ |
d36a99d2 BS |
25 | #define gt215_ram(p) container_of((p), struct gt215_ram, base) |
26 | #include "ram.h" | |
639c308e | 27 | #include "ramfuc.h" |
639c308e BS |
28 | |
29 | #include <core/option.h> | |
aae95ca7 | 30 | #include <subdev/bios.h> |
7f4b9616 | 31 | #include <subdev/bios/M0205.h> |
639c308e | 32 | #include <subdev/bios/rammap.h> |
aae95ca7 | 33 | #include <subdev/bios/timing.h> |
7632b30e | 34 | #include <subdev/clk/gt215.h> |
598a39e7 RS |
35 | #include <subdev/gpio.h> |
36 | ||
598a39e7 RS |
37 | /* XXX: Remove when memx gains GPIO support */ |
38 | extern int nv50_gpio_location(int line, u32 *reg, u32 *shift); | |
39 | ||
639c308e | 40 | struct gt215_ramfuc { |
aae95ca7 | 41 | struct ramfuc base; |
7f4b9616 RS |
42 | struct ramfuc_reg r_0x001610; |
43 | struct ramfuc_reg r_0x001700; | |
b6a7907f | 44 | struct ramfuc_reg r_0x002504; |
aae95ca7 BS |
45 | struct ramfuc_reg r_0x004000; |
46 | struct ramfuc_reg r_0x004004; | |
47 | struct ramfuc_reg r_0x004018; | |
48 | struct ramfuc_reg r_0x004128; | |
49 | struct ramfuc_reg r_0x004168; | |
7f4b9616 | 50 | struct ramfuc_reg r_0x100080; |
aae95ca7 BS |
51 | struct ramfuc_reg r_0x100200; |
52 | struct ramfuc_reg r_0x100210; | |
53 | struct ramfuc_reg r_0x100220[9]; | |
b6a7907f | 54 | struct ramfuc_reg r_0x100264; |
aae95ca7 BS |
55 | struct ramfuc_reg r_0x1002d0; |
56 | struct ramfuc_reg r_0x1002d4; | |
57 | struct ramfuc_reg r_0x1002dc; | |
58 | struct ramfuc_reg r_0x10053c; | |
59 | struct ramfuc_reg r_0x1005a0; | |
60 | struct ramfuc_reg r_0x1005a4; | |
b6a7907f | 61 | struct ramfuc_reg r_0x100700; |
aae95ca7 BS |
62 | struct ramfuc_reg r_0x100714; |
63 | struct ramfuc_reg r_0x100718; | |
64 | struct ramfuc_reg r_0x10071c; | |
7f4b9616 | 65 | struct ramfuc_reg r_0x100720; |
aae95ca7 BS |
66 | struct ramfuc_reg r_0x100760; |
67 | struct ramfuc_reg r_0x1007a0; | |
68 | struct ramfuc_reg r_0x1007e0; | |
b6a7907f | 69 | struct ramfuc_reg r_0x100da0; |
aae95ca7 BS |
70 | struct ramfuc_reg r_0x10f804; |
71 | struct ramfuc_reg r_0x1110e0; | |
72 | struct ramfuc_reg r_0x111100; | |
73 | struct ramfuc_reg r_0x111104; | |
7f4b9616 RS |
74 | struct ramfuc_reg r_0x1111e0; |
75 | struct ramfuc_reg r_0x111400; | |
aae95ca7 BS |
76 | struct ramfuc_reg r_0x611200; |
77 | struct ramfuc_reg r_mr[4]; | |
598a39e7 | 78 | struct ramfuc_reg r_gpioFBVREF; |
aae95ca7 BS |
79 | }; |
80 | ||
639c308e | 81 | struct gt215_ltrain { |
7f4b9616 RS |
82 | enum { |
83 | NVA3_TRAIN_UNKNOWN, | |
84 | NVA3_TRAIN_UNSUPPORTED, | |
85 | NVA3_TRAIN_ONCE, | |
86 | NVA3_TRAIN_EXEC, | |
87 | NVA3_TRAIN_DONE | |
88 | } state; | |
89 | u32 r_100720; | |
90 | u32 r_1111e0; | |
91 | u32 r_111400; | |
639c308e | 92 | struct nvkm_mem *mem; |
7f4b9616 RS |
93 | }; |
94 | ||
639c308e BS |
95 | struct gt215_ram { |
96 | struct nvkm_ram base; | |
97 | struct gt215_ramfuc fuc; | |
98 | struct gt215_ltrain ltrain; | |
75faef78 BS |
99 | }; |
100 | ||
7f4b9616 | 101 | void |
639c308e | 102 | gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) |
7f4b9616 RS |
103 | { |
104 | int i, lo, hi; | |
105 | u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0; | |
106 | ||
107 | for (i = 0; i < 8; i++) { | |
108 | for (lo = 0; lo < 0x40; lo++) { | |
109 | if (!(vals[lo] & 0x80000000)) | |
110 | continue; | |
111 | if (vals[lo] & (0x101 << i)) | |
112 | break; | |
113 | } | |
114 | ||
115 | if (lo == 0x40) | |
116 | return; | |
117 | ||
118 | for (hi = lo + 1; hi < 0x40; hi++) { | |
119 | if (!(vals[lo] & 0x80000000)) | |
120 | continue; | |
121 | if (!(vals[hi] & (0x101 << i))) { | |
122 | hi--; | |
123 | break; | |
124 | } | |
125 | } | |
126 | ||
127 | median[i] = ((hi - lo) >> 1) + lo; | |
128 | bins[(median[i] & 0xf0) >> 4]++; | |
129 | median[i] += 0x30; | |
130 | } | |
131 | ||
132 | /* Find the best value for 0x1111e0 */ | |
133 | for (i = 0; i < 4; i++) { | |
134 | if (bins[i] > qty) { | |
135 | bin = i + 3; | |
136 | qty = bins[i]; | |
137 | } | |
138 | } | |
139 | ||
140 | train->r_100720 = 0; | |
141 | for (i = 0; i < 8; i++) { | |
142 | median[i] = max(median[i], (u8) (bin << 4)); | |
143 | median[i] = min(median[i], (u8) ((bin << 4) | 0xf)); | |
144 | ||
145 | train->r_100720 |= ((median[i] & 0x0f) << (i << 2)); | |
146 | } | |
147 | ||
148 | train->r_1111e0 = 0x02000000 | (bin * 0x101); | |
149 | train->r_111400 = 0x0; | |
150 | } | |
151 | ||
152 | /* | |
153 | * Link training for (at least) DDR3 | |
154 | */ | |
155 | int | |
d36a99d2 | 156 | gt215_link_train(struct gt215_ram *ram) |
7f4b9616 | 157 | { |
639c308e | 158 | struct gt215_ltrain *train = &ram->ltrain; |
639c308e | 159 | struct gt215_ramfuc *fuc = &ram->fuc; |
d36a99d2 | 160 | struct nvkm_subdev *subdev = &ram->base.fb->subdev; |
3ecd329b BS |
161 | struct nvkm_device *device = subdev->device; |
162 | struct nvkm_bios *bios = device->bios; | |
163 | struct nvkm_clk *clk = device->clk; | |
7f4b9616 RS |
164 | u32 *result, r1700; |
165 | int ret, i; | |
166 | struct nvbios_M0205T M0205T = { 0 }; | |
167 | u8 ver, hdr, cnt, len, snr, ssz; | |
168 | unsigned int clk_current; | |
169 | unsigned long flags; | |
170 | unsigned long *f = &flags; | |
171 | ||
639c308e | 172 | if (nvkm_boolopt(device->cfgopt, "NvMemExec", true) != true) |
7f4b9616 RS |
173 | return -ENOSYS; |
174 | ||
175 | /* XXX: Multiple partitions? */ | |
176 | result = kmalloc(64 * sizeof(u32), GFP_KERNEL); | |
177 | if (!result) | |
178 | return -ENOMEM; | |
179 | ||
180 | train->state = NVA3_TRAIN_EXEC; | |
181 | ||
182 | /* Clock speeds for training and back */ | |
183 | nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T); | |
b1e4553c BS |
184 | if (M0205T.freq == 0) { |
185 | kfree(result); | |
7f4b9616 | 186 | return -ENOENT; |
b1e4553c | 187 | } |
7f4b9616 | 188 | |
6625f55c | 189 | clk_current = nvkm_clk_read(clk, nv_clk_src_mem); |
7f4b9616 | 190 | |
639c308e | 191 | ret = gt215_clk_pre(clk, f); |
7f4b9616 RS |
192 | if (ret) |
193 | goto out; | |
194 | ||
195 | /* First: clock up/down */ | |
d36a99d2 | 196 | ret = ram->base.func->calc(&ram->base, (u32) M0205T.freq * 1000); |
7f4b9616 RS |
197 | if (ret) |
198 | goto out; | |
199 | ||
200 | /* Do this *after* calc, eliminates write in script */ | |
6758745b | 201 | nvkm_wr32(device, 0x111400, 0x00000000); |
7f4b9616 | 202 | /* XXX: Magic writes that improve train reliability? */ |
6758745b BS |
203 | nvkm_mask(device, 0x100674, 0x0000ffff, 0x00000000); |
204 | nvkm_mask(device, 0x1005e4, 0x0000ffff, 0x00000000); | |
205 | nvkm_mask(device, 0x100b0c, 0x000000ff, 0x00000000); | |
206 | nvkm_wr32(device, 0x100c04, 0x00000400); | |
7f4b9616 RS |
207 | |
208 | /* Now the training script */ | |
209 | r1700 = ram_rd32(fuc, 0x001700); | |
210 | ||
211 | ram_mask(fuc, 0x100200, 0x00000800, 0x00000000); | |
212 | ram_wr32(fuc, 0x611200, 0x3300); | |
213 | ram_wait_vblank(fuc); | |
214 | ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000); | |
215 | ram_mask(fuc, 0x001610, 0x00000083, 0x00000003); | |
216 | ram_mask(fuc, 0x100080, 0x00000020, 0x00000000); | |
217 | ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000); | |
218 | ram_wr32(fuc, 0x001700, 0x00000000); | |
219 | ||
220 | ram_train(fuc); | |
221 | ||
222 | /* Reset */ | |
223 | ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000); | |
224 | ram_wr32(fuc, 0x10053c, 0x0); | |
225 | ram_wr32(fuc, 0x100720, train->r_100720); | |
226 | ram_wr32(fuc, 0x1111e0, train->r_1111e0); | |
227 | ram_wr32(fuc, 0x111400, train->r_111400); | |
228 | ram_nuke(fuc, 0x100080); | |
229 | ram_mask(fuc, 0x100080, 0x00000020, 0x00000020); | |
230 | ram_nsec(fuc, 1000); | |
231 | ||
232 | ram_wr32(fuc, 0x001700, r1700); | |
233 | ram_mask(fuc, 0x001610, 0x00000083, 0x00000080); | |
234 | ram_wr32(fuc, 0x611200, 0x3330); | |
235 | ram_mask(fuc, 0x100200, 0x00000800, 0x00000800); | |
236 | ||
237 | ram_exec(fuc, true); | |
238 | ||
d36a99d2 | 239 | ram->base.func->calc(&ram->base, clk_current); |
7f4b9616 RS |
240 | ram_exec(fuc, true); |
241 | ||
242 | /* Post-processing, avoids flicker */ | |
6758745b BS |
243 | nvkm_mask(device, 0x616308, 0x10, 0x10); |
244 | nvkm_mask(device, 0x616b08, 0x10, 0x10); | |
7f4b9616 | 245 | |
639c308e | 246 | gt215_clk_post(clk, f); |
7f4b9616 | 247 | |
d36a99d2 | 248 | ram_train_result(ram->base.fb, result, 64); |
7f4b9616 | 249 | for (i = 0; i < 64; i++) |
3ecd329b | 250 | nvkm_debug(subdev, "Train: %08x", result[i]); |
639c308e | 251 | gt215_link_train_calc(result, train); |
7f4b9616 | 252 | |
3ecd329b BS |
253 | nvkm_debug(subdev, "Train: %08x %08x %08x", train->r_100720, |
254 | train->r_1111e0, train->r_111400); | |
7f4b9616 RS |
255 | |
256 | kfree(result); | |
257 | ||
258 | train->state = NVA3_TRAIN_DONE; | |
259 | ||
260 | return ret; | |
261 | ||
262 | out: | |
263 | if(ret == -EBUSY) | |
264 | f = NULL; | |
265 | ||
266 | train->state = NVA3_TRAIN_UNSUPPORTED; | |
267 | ||
639c308e | 268 | gt215_clk_post(clk, f); |
b1e4553c | 269 | kfree(result); |
7f4b9616 RS |
270 | return ret; |
271 | } | |
272 | ||
273 | int | |
d36a99d2 | 274 | gt215_link_train_init(struct gt215_ram *ram) |
7f4b9616 RS |
275 | { |
276 | static const u32 pattern[16] = { | |
277 | 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, | |
278 | 0x00000000, 0x11111111, 0x44444444, 0xdddddddd, | |
279 | 0x33333333, 0x55555555, 0x77777777, 0x66666666, | |
280 | 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, | |
281 | }; | |
639c308e | 282 | struct gt215_ltrain *train = &ram->ltrain; |
d36a99d2 BS |
283 | struct nvkm_device *device = ram->base.fb->subdev.device; |
284 | struct nvkm_bios *bios = device->bios; | |
639c308e | 285 | struct nvkm_mem *mem; |
7f4b9616 RS |
286 | struct nvbios_M0205E M0205E; |
287 | u8 ver, hdr, cnt, len; | |
288 | u32 r001700; | |
289 | int ret, i = 0; | |
290 | ||
291 | train->state = NVA3_TRAIN_UNSUPPORTED; | |
292 | ||
293 | /* We support type "5" | |
294 | * XXX: training pattern table appears to be unused for this routine */ | |
295 | if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)) | |
296 | return -ENOENT; | |
297 | ||
298 | if (M0205E.type != 5) | |
299 | return 0; | |
300 | ||
301 | train->state = NVA3_TRAIN_ONCE; | |
302 | ||
d36a99d2 BS |
303 | ret = ram->base.func->get(&ram->base, 0x8000, 0x10000, 0, 0x800, |
304 | &ram->ltrain.mem); | |
7f4b9616 RS |
305 | if (ret) |
306 | return ret; | |
307 | ||
308 | mem = ram->ltrain.mem; | |
309 | ||
6758745b BS |
310 | nvkm_wr32(device, 0x100538, 0x10000000 | (mem->offset >> 16)); |
311 | nvkm_wr32(device, 0x1005a8, 0x0000ffff); | |
312 | nvkm_mask(device, 0x10f800, 0x00000001, 0x00000001); | |
7f4b9616 RS |
313 | |
314 | for (i = 0; i < 0x30; i++) { | |
6758745b BS |
315 | nvkm_wr32(device, 0x10f8c0, (i << 8) | i); |
316 | nvkm_wr32(device, 0x10f900, pattern[i % 16]); | |
7f4b9616 RS |
317 | } |
318 | ||
319 | for (i = 0; i < 0x30; i++) { | |
6758745b BS |
320 | nvkm_wr32(device, 0x10f8e0, (i << 8) | i); |
321 | nvkm_wr32(device, 0x10f920, pattern[i % 16]); | |
7f4b9616 RS |
322 | } |
323 | ||
324 | /* And upload the pattern */ | |
6758745b BS |
325 | r001700 = nvkm_rd32(device, 0x1700); |
326 | nvkm_wr32(device, 0x1700, mem->offset >> 16); | |
7f4b9616 | 327 | for (i = 0; i < 16; i++) |
6758745b | 328 | nvkm_wr32(device, 0x700000 + (i << 2), pattern[i]); |
7f4b9616 | 329 | for (i = 0; i < 16; i++) |
6758745b BS |
330 | nvkm_wr32(device, 0x700100 + (i << 2), pattern[i]); |
331 | nvkm_wr32(device, 0x1700, r001700); | |
7f4b9616 | 332 | |
6758745b BS |
333 | train->r_100720 = nvkm_rd32(device, 0x100720); |
334 | train->r_1111e0 = nvkm_rd32(device, 0x1111e0); | |
335 | train->r_111400 = nvkm_rd32(device, 0x111400); | |
7f4b9616 RS |
336 | return 0; |
337 | } | |
338 | ||
339 | void | |
d36a99d2 | 340 | gt215_link_train_fini(struct gt215_ram *ram) |
7f4b9616 | 341 | { |
7f4b9616 | 342 | if (ram->ltrain.mem) |
d36a99d2 | 343 | ram->base.func->put(&ram->base, &ram->ltrain.mem); |
7f4b9616 RS |
344 | } |
345 | ||
bf504b3f RS |
346 | /* |
347 | * RAM reclocking | |
348 | */ | |
349 | #define T(t) cfg->timing_10_##t | |
350 | static int | |
d36a99d2 | 351 | gt215_ram_timing_calc(struct gt215_ram *ram, u32 *timing) |
bf504b3f | 352 | { |
bf504b3f | 353 | struct nvbios_ramcfg *cfg = &ram->base.target.bios; |
d36a99d2 | 354 | struct nvkm_subdev *subdev = &ram->base.fb->subdev; |
3ecd329b | 355 | struct nvkm_device *device = subdev->device; |
b0c7336b | 356 | int tUNK_base, tUNK_40_0, prevCL; |
598a39e7 | 357 | u32 cur2, cur3, cur7, cur8; |
bf504b3f | 358 | |
6758745b BS |
359 | cur2 = nvkm_rd32(device, 0x100228); |
360 | cur3 = nvkm_rd32(device, 0x10022c); | |
361 | cur7 = nvkm_rd32(device, 0x10023c); | |
362 | cur8 = nvkm_rd32(device, 0x100240); | |
bf504b3f | 363 | |
598a39e7 RS |
364 | |
365 | switch ((!T(CWL)) * ram->base.type) { | |
d36a99d2 | 366 | case NVKM_RAM_TYPE_DDR2: |
b0c7336b | 367 | T(CWL) = T(CL) - 1; |
598a39e7 | 368 | break; |
d36a99d2 | 369 | case NVKM_RAM_TYPE_GDDR3: |
598a39e7 RS |
370 | T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; |
371 | break; | |
372 | } | |
bf504b3f | 373 | |
b0c7336b RS |
374 | prevCL = (cur3 & 0x000000ff) + 1; |
375 | tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL; | |
bf504b3f RS |
376 | |
377 | timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC)); | |
378 | timing[1] = (T(WR) + 1 + T(CWL)) << 24 | | |
379 | max_t(u8,T(18), 1) << 16 | | |
380 | (T(WTR) + 1 + T(CWL)) << 8 | | |
381 | (5 + T(CL) - T(CWL)); | |
382 | timing[2] = (T(CWL) - 1) << 24 | | |
383 | (T(RRD) << 16) | | |
384 | (T(RCDWR) << 8) | | |
385 | T(RCDRD); | |
386 | timing[3] = (cur3 & 0x00ff0000) | | |
387 | (0x30 + T(CL)) << 24 | | |
388 | (0xb + T(CL)) << 8 | | |
389 | (T(CL) - 1); | |
390 | timing[4] = T(20) << 24 | | |
391 | T(21) << 16 | | |
392 | T(13) << 8 | | |
393 | T(13); | |
394 | timing[5] = T(RFC) << 24 | | |
395 | max_t(u8,T(RCDRD), T(RCDWR)) << 16 | | |
598a39e7 | 396 | max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 | |
bf504b3f RS |
397 | T(RP); |
398 | timing[6] = (0x5a + T(CL)) << 16 | | |
598a39e7 | 399 | max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 | |
bf504b3f RS |
400 | (0x50 + T(CL) - T(CWL)); |
401 | timing[7] = (cur7 & 0xff000000) | | |
402 | ((tUNK_base + T(CL)) << 16) | | |
403 | 0x202; | |
404 | timing[8] = cur8 & 0xffffff00; | |
405 | ||
b0c7336b | 406 | switch (ram->base.type) { |
d36a99d2 BS |
407 | case NVKM_RAM_TYPE_DDR2: |
408 | case NVKM_RAM_TYPE_GDDR3: | |
b0c7336b RS |
409 | tUNK_40_0 = prevCL - (cur8 & 0xff); |
410 | if (tUNK_40_0 > 0) | |
411 | timing[8] |= T(CL); | |
412 | break; | |
413 | default: | |
414 | break; | |
415 | } | |
416 | ||
3ecd329b BS |
417 | nvkm_debug(subdev, "Entry: 220: %08x %08x %08x %08x\n", |
418 | timing[0], timing[1], timing[2], timing[3]); | |
419 | nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n", | |
420 | timing[4], timing[5], timing[6], timing[7]); | |
421 | nvkm_debug(subdev, " 240: %08x\n", timing[8]); | |
bf504b3f RS |
422 | return 0; |
423 | } | |
424 | #undef T | |
425 | ||
b6a7907f | 426 | static void |
639c308e | 427 | nvkm_sddr2_dll_reset(struct gt215_ramfuc *fuc) |
b6a7907f RS |
428 | { |
429 | ram_mask(fuc, mr[0], 0x100, 0x100); | |
430 | ram_nsec(fuc, 1000); | |
431 | ram_mask(fuc, mr[0], 0x100, 0x000); | |
432 | ram_nsec(fuc, 1000); | |
433 | } | |
434 | ||
435 | static void | |
639c308e | 436 | nvkm_sddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr) |
b6a7907f RS |
437 | { |
438 | u32 mr1_old = ram_rd32(fuc, mr[1]); | |
439 | ||
440 | if (!(mr1_old & 0x1)) { | |
441 | ram_wr32(fuc, 0x1002d4, 0x00000001); | |
442 | ram_wr32(fuc, mr[1], mr[1]); | |
443 | ram_nsec(fuc, 1000); | |
444 | } | |
445 | } | |
446 | ||
598a39e7 | 447 | static void |
639c308e | 448 | nvkm_gddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr) |
598a39e7 RS |
449 | { |
450 | u32 mr1_old = ram_rd32(fuc, mr[1]); | |
451 | ||
452 | if (!(mr1_old & 0x40)) { | |
453 | ram_wr32(fuc, mr[1], mr[1]); | |
454 | ram_nsec(fuc, 1000); | |
455 | } | |
456 | } | |
457 | ||
b6a7907f | 458 | static void |
639c308e | 459 | gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk) |
b6a7907f RS |
460 | { |
461 | ram_wr32(fuc, 0x004004, mclk->pll); | |
462 | ram_mask(fuc, 0x004000, 0x00000001, 0x00000001); | |
463 | ram_mask(fuc, 0x004000, 0x00000010, 0x00000000); | |
464 | ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000); | |
465 | ram_mask(fuc, 0x004000, 0x00000010, 0x00000010); | |
466 | } | |
467 | ||
598a39e7 | 468 | static void |
639c308e | 469 | gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) |
598a39e7 | 470 | { |
2ea7249f | 471 | struct nvkm_gpio *gpio = fuc->base.fb->subdev.device->gpio; |
598a39e7 RS |
472 | struct dcb_gpio_func func; |
473 | u32 reg, sh, gpio_val; | |
474 | int ret; | |
475 | ||
2ea7249f BS |
476 | if (nvkm_gpio_get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) { |
477 | ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); | |
598a39e7 RS |
478 | if (ret) |
479 | return; | |
480 | ||
481 | nv50_gpio_location(func.line, ®, &sh); | |
482 | gpio_val = ram_rd32(fuc, gpioFBVREF); | |
483 | if (gpio_val & (8 << sh)) | |
484 | val = !val; | |
485 | ||
486 | ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh)); | |
487 | ram_nsec(fuc, 20000); | |
488 | } | |
489 | } | |
490 | ||
aae95ca7 | 491 | static int |
d36a99d2 | 492 | gt215_ram_calc(struct nvkm_ram *base, u32 freq) |
aae95ca7 | 493 | { |
d36a99d2 | 494 | struct gt215_ram *ram = gt215_ram(base); |
639c308e BS |
495 | struct gt215_ramfuc *fuc = &ram->fuc; |
496 | struct gt215_ltrain *train = &ram->ltrain; | |
d36a99d2 | 497 | struct nvkm_subdev *subdev = &ram->base.fb->subdev; |
3ecd329b BS |
498 | struct nvkm_device *device = subdev->device; |
499 | struct nvkm_bios *bios = device->bios; | |
639c308e BS |
500 | struct gt215_clk_info mclk; |
501 | struct nvkm_ram_data *next; | |
c378eb74 | 502 | u8 ver, hdr, cnt, len, strap; |
aae95ca7 | 503 | u32 data; |
b6a7907f | 504 | u32 r004018, r100760, r100da0, r111100, ctrl; |
aae95ca7 | 505 | u32 unk714, unk718, unk71c; |
c378eb74 | 506 | int ret, i; |
bf504b3f | 507 | u32 timing[9]; |
b6a7907f | 508 | bool pll2pll; |
c378eb74 BS |
509 | |
510 | next = &ram->base.target; | |
511 | next->freq = freq; | |
512 | ram->base.next = next; | |
aae95ca7 | 513 | |
7f4b9616 | 514 | if (ram->ltrain.state == NVA3_TRAIN_ONCE) |
d36a99d2 | 515 | gt215_link_train(ram); |
7f4b9616 | 516 | |
aae95ca7 | 517 | /* lookup memory config data relevant to the target frequency */ |
b6a7907f | 518 | data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len, |
639c308e | 519 | &next->bios); |
b6a7907f | 520 | if (!data || ver != 0x10 || hdr < 0x05) { |
3ecd329b | 521 | nvkm_error(subdev, "invalid/missing rammap entry\n"); |
aae95ca7 BS |
522 | return -EINVAL; |
523 | } | |
524 | ||
525 | /* locate specific data set for the attached memory */ | |
d36a99d2 | 526 | strap = nvbios_ramcfg_index(subdev); |
aae95ca7 | 527 | if (strap >= cnt) { |
3ecd329b | 528 | nvkm_error(subdev, "invalid ramcfg strap\n"); |
aae95ca7 BS |
529 | return -EINVAL; |
530 | } | |
531 | ||
c378eb74 BS |
532 | data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, |
533 | &ver, &hdr, &next->bios); | |
b6a7907f | 534 | if (!data || ver != 0x10 || hdr < 0x09) { |
3ecd329b | 535 | nvkm_error(subdev, "invalid/missing ramcfg entry\n"); |
aae95ca7 BS |
536 | return -EINVAL; |
537 | } | |
538 | ||
539 | /* lookup memory timings, if bios says they're present */ | |
c378eb74 BS |
540 | if (next->bios.ramcfg_timing != 0xff) { |
541 | data = nvbios_timingEp(bios, next->bios.ramcfg_timing, | |
542 | &ver, &hdr, &cnt, &len, | |
543 | &next->bios); | |
b6a7907f | 544 | if (!data || ver != 0x10 || hdr < 0x17) { |
3ecd329b | 545 | nvkm_error(subdev, "invalid/missing timing entry\n"); |
aae95ca7 BS |
546 | return -EINVAL; |
547 | } | |
aae95ca7 BS |
548 | } |
549 | ||
d36a99d2 | 550 | ret = gt215_pll_info(device->clk, 0x12, 0x4000, freq, &mclk); |
aae95ca7 | 551 | if (ret < 0) { |
3ecd329b | 552 | nvkm_error(subdev, "failed mclk calculation\n"); |
aae95ca7 BS |
553 | return ret; |
554 | } | |
555 | ||
d36a99d2 | 556 | gt215_ram_timing_calc(ram, timing); |
bf504b3f | 557 | |
d36a99d2 | 558 | ret = ram_init(fuc, ram->base.fb); |
b6a7907f RS |
559 | if (ret) |
560 | return ret; | |
561 | ||
562 | /* Determine ram-specific MR values */ | |
563 | ram->base.mr[0] = ram_rd32(fuc, mr[0]); | |
564 | ram->base.mr[1] = ram_rd32(fuc, mr[1]); | |
565 | ram->base.mr[2] = ram_rd32(fuc, mr[2]); | |
566 | ||
567 | switch (ram->base.type) { | |
d36a99d2 | 568 | case NVKM_RAM_TYPE_DDR2: |
639c308e | 569 | ret = nvkm_sddr2_calc(&ram->base); |
b0c7336b | 570 | break; |
d36a99d2 | 571 | case NVKM_RAM_TYPE_DDR3: |
639c308e | 572 | ret = nvkm_sddr3_calc(&ram->base); |
b6a7907f | 573 | break; |
d36a99d2 | 574 | case NVKM_RAM_TYPE_GDDR3: |
639c308e | 575 | ret = nvkm_gddr3_calc(&ram->base); |
598a39e7 | 576 | break; |
b6a7907f RS |
577 | default: |
578 | ret = -ENOSYS; | |
579 | break; | |
580 | } | |
581 | ||
aae95ca7 BS |
582 | if (ret) |
583 | return ret; | |
584 | ||
3b582bed | 585 | /* XXX: 750MHz seems rather arbitrary */ |
aae95ca7 BS |
586 | if (freq <= 750000) { |
587 | r004018 = 0x10000000; | |
588 | r100760 = 0x22222222; | |
b6a7907f | 589 | r100da0 = 0x00000010; |
aae95ca7 BS |
590 | } else { |
591 | r004018 = 0x00000000; | |
592 | r100760 = 0x00000000; | |
b6a7907f | 593 | r100da0 = 0x00000000; |
aae95ca7 BS |
594 | } |
595 | ||
7164f4c5 | 596 | if (!next->bios.ramcfg_DLLoff) |
b6a7907f RS |
597 | r004018 |= 0x00004000; |
598 | ||
599 | /* pll2pll requires to switch to a safe clock first */ | |
aae95ca7 | 600 | ctrl = ram_rd32(fuc, 0x004000); |
b6a7907f | 601 | pll2pll = (!(ctrl & 0x00000008)) && mclk.pll; |
aae95ca7 | 602 | |
b6a7907f | 603 | /* Pre, NVIDIA does this outside the script */ |
c378eb74 | 604 | if (next->bios.ramcfg_10_02_10) { |
aae95ca7 BS |
605 | ram_mask(fuc, 0x111104, 0x00000600, 0x00000000); |
606 | } else { | |
607 | ram_mask(fuc, 0x111100, 0x40000000, 0x40000000); | |
608 | ram_mask(fuc, 0x111104, 0x00000180, 0x00000000); | |
609 | } | |
b6a7907f RS |
610 | /* Always disable this bit during reclock */ |
611 | ram_mask(fuc, 0x100200, 0x00000800, 0x00000000); | |
612 | ||
613 | /* If switching from non-pll to pll, lock before disabling FB */ | |
614 | if (mclk.pll && !pll2pll) { | |
615 | ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101); | |
639c308e | 616 | gt215_ram_lock_pll(fuc, &mclk); |
b6a7907f RS |
617 | } |
618 | ||
619 | /* Start with disabling some CRTCs and PFIFO? */ | |
620 | ram_wait_vblank(fuc); | |
621 | ram_wr32(fuc, 0x611200, 0x3300); | |
622 | ram_mask(fuc, 0x002504, 0x1, 0x1); | |
623 | ram_nsec(fuc, 10000); | |
624 | ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */ | |
625 | ram_block(fuc); | |
626 | ram_nsec(fuc, 2000); | |
627 | ||
598a39e7 | 628 | if (!next->bios.ramcfg_10_02_10) { |
d36a99d2 | 629 | if (ram->base.type == NVKM_RAM_TYPE_GDDR3) |
598a39e7 RS |
630 | ram_mask(fuc, 0x111100, 0x04020000, 0x00020000); |
631 | else | |
632 | ram_mask(fuc, 0x111100, 0x04020000, 0x04020000); | |
633 | } | |
aae95ca7 | 634 | |
b6a7907f | 635 | /* If we're disabling the DLL, do it now */ |
7164f4c5 | 636 | switch (next->bios.ramcfg_DLLoff * ram->base.type) { |
d36a99d2 | 637 | case NVKM_RAM_TYPE_DDR3: |
639c308e | 638 | nvkm_sddr3_dll_disable(fuc, ram->base.mr); |
b0c7336b | 639 | break; |
d36a99d2 | 640 | case NVKM_RAM_TYPE_GDDR3: |
639c308e | 641 | nvkm_gddr3_dll_disable(fuc, ram->base.mr); |
598a39e7 | 642 | break; |
b0c7336b | 643 | } |
b6a7907f | 644 | |
598a39e7 | 645 | if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT) |
639c308e | 646 | gt215_ram_fbvref(fuc, 0); |
598a39e7 | 647 | |
b6a7907f | 648 | /* Brace RAM for impact */ |
aae95ca7 BS |
649 | ram_wr32(fuc, 0x1002d4, 0x00000001); |
650 | ram_wr32(fuc, 0x1002d0, 0x00000001); | |
651 | ram_wr32(fuc, 0x1002d0, 0x00000001); | |
652 | ram_wr32(fuc, 0x100210, 0x00000000); | |
653 | ram_wr32(fuc, 0x1002dc, 0x00000001); | |
654 | ram_nsec(fuc, 2000); | |
655 | ||
d36a99d2 | 656 | if (device->chipset == 0xa3 && freq <= 500000) |
b6a7907f RS |
657 | ram_mask(fuc, 0x100700, 0x00000006, 0x00000006); |
658 | ||
659 | /* Fiddle with clocks */ | |
660 | /* There's 4 scenario's | |
661 | * pll->pll: first switch to a 324MHz clock, set up new PLL, switch | |
662 | * clk->pll: Set up new PLL, switch | |
663 | * pll->clk: Set up clock, switch | |
664 | * clk->clk: Overwrite ctrl and other bits, switch */ | |
665 | ||
666 | /* Switch to regular clock - 324MHz */ | |
667 | if (pll2pll) { | |
668 | ram_mask(fuc, 0x004000, 0x00000004, 0x00000004); | |
669 | ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101); | |
670 | ram_mask(fuc, 0x004000, 0x00000008, 0x00000008); | |
aae95ca7 BS |
671 | ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); |
672 | ram_wr32(fuc, 0x004018, 0x00001000); | |
639c308e | 673 | gt215_ram_lock_pll(fuc, &mclk); |
b6a7907f RS |
674 | } |
675 | ||
676 | if (mclk.pll) { | |
677 | ram_mask(fuc, 0x004000, 0x00000105, 0x00000105); | |
678 | ram_wr32(fuc, 0x004018, 0x00001000 | r004018); | |
679 | ram_wr32(fuc, 0x100da0, r100da0); | |
680 | } else { | |
681 | ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101); | |
682 | ram_mask(fuc, 0x004000, 0x00000108, 0x00000008); | |
aae95ca7 | 683 | ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); |
b6a7907f RS |
684 | ram_wr32(fuc, 0x004018, 0x00009000 | r004018); |
685 | ram_wr32(fuc, 0x100da0, r100da0); | |
aae95ca7 | 686 | } |
b6a7907f | 687 | ram_nsec(fuc, 20000); |
aae95ca7 | 688 | |
c378eb74 BS |
689 | if (next->bios.rammap_10_04_08) { |
690 | ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 | | |
691 | next->bios.ramcfg_10_05 << 8 | | |
692 | next->bios.ramcfg_10_05); | |
693 | ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 | | |
694 | next->bios.ramcfg_10_07); | |
695 | ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 | | |
696 | next->bios.ramcfg_10_03_0f << 16 | | |
697 | next->bios.ramcfg_10_09_0f | | |
698 | 0x80000000); | |
aae95ca7 BS |
699 | ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000); |
700 | } else { | |
b6a7907f RS |
701 | if (train->state == NVA3_TRAIN_DONE) { |
702 | ram_wr32(fuc, 0x100080, 0x1020); | |
703 | ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400); | |
704 | ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0); | |
705 | ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720); | |
706 | } | |
aae95ca7 BS |
707 | ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000); |
708 | ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000); | |
709 | ram_mask(fuc, 0x100760, 0x22222222, r100760); | |
710 | ram_mask(fuc, 0x1007a0, 0x22222222, r100760); | |
711 | ram_mask(fuc, 0x1007e0, 0x22222222, r100760); | |
712 | } | |
713 | ||
d36a99d2 | 714 | if (device->chipset == 0xa3 && freq > 500000) { |
b6a7907f RS |
715 | ram_mask(fuc, 0x100700, 0x00000006, 0x00000000); |
716 | } | |
717 | ||
718 | /* Final switch */ | |
aae95ca7 BS |
719 | if (mclk.pll) { |
720 | ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000); | |
b6a7907f | 721 | ram_mask(fuc, 0x004000, 0x00000008, 0x00000000); |
aae95ca7 BS |
722 | } |
723 | ||
aae95ca7 BS |
724 | ram_wr32(fuc, 0x1002dc, 0x00000000); |
725 | ram_wr32(fuc, 0x1002d4, 0x00000001); | |
726 | ram_wr32(fuc, 0x100210, 0x80000000); | |
b6a7907f | 727 | ram_nsec(fuc, 2000); |
aae95ca7 | 728 | |
b6a7907f | 729 | /* Set RAM MR parameters and timings */ |
b0c7336b RS |
730 | for (i = 2; i >= 0; i--) { |
731 | if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) { | |
732 | ram_wr32(fuc, mr[i], ram->base.mr[i]); | |
733 | ram_nsec(fuc, 1000); | |
734 | } | |
735 | } | |
aae95ca7 | 736 | |
bf504b3f RS |
737 | ram_wr32(fuc, 0x100220[3], timing[3]); |
738 | ram_wr32(fuc, 0x100220[1], timing[1]); | |
739 | ram_wr32(fuc, 0x100220[6], timing[6]); | |
740 | ram_wr32(fuc, 0x100220[7], timing[7]); | |
741 | ram_wr32(fuc, 0x100220[2], timing[2]); | |
742 | ram_wr32(fuc, 0x100220[4], timing[4]); | |
743 | ram_wr32(fuc, 0x100220[5], timing[5]); | |
744 | ram_wr32(fuc, 0x100220[0], timing[0]); | |
745 | ram_wr32(fuc, 0x100220[8], timing[8]); | |
746 | ||
747 | /* Misc */ | |
c378eb74 | 748 | ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12); |
aae95ca7 | 749 | |
b6a7907f RS |
750 | /* XXX: A lot of "chipset"/"ram type" specific stuff...? */ |
751 | unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000130; | |
752 | unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100; | |
753 | unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100; | |
754 | r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000; | |
755 | ||
756 | if (next->bios.ramcfg_10_02_04) { | |
757 | switch (ram->base.type) { | |
d36a99d2 BS |
758 | case NVKM_RAM_TYPE_DDR3: |
759 | if (device->chipset != 0xa8) | |
b6a7907f RS |
760 | r111100 |= 0x00000004; |
761 | /* no break */ | |
d36a99d2 | 762 | case NVKM_RAM_TYPE_DDR2: |
b0c7336b RS |
763 | r111100 |= 0x08000000; |
764 | break; | |
b6a7907f RS |
765 | default: |
766 | break; | |
767 | } | |
768 | } else { | |
769 | switch (ram->base.type) { | |
d36a99d2 | 770 | case NVKM_RAM_TYPE_DDR2: |
b0c7336b RS |
771 | r111100 |= 0x1a800000; |
772 | unk714 |= 0x00000010; | |
773 | break; | |
d36a99d2 BS |
774 | case NVKM_RAM_TYPE_DDR3: |
775 | if (device->chipset == 0xa8) { | |
b6a7907f RS |
776 | r111100 |= 0x08000000; |
777 | } else { | |
778 | r111100 &= ~0x00000004; | |
779 | r111100 |= 0x12800000; | |
780 | } | |
781 | unk714 |= 0x00000010; | |
782 | break; | |
d36a99d2 | 783 | case NVKM_RAM_TYPE_GDDR3: |
598a39e7 RS |
784 | r111100 |= 0x30000000; |
785 | unk714 |= 0x00000020; | |
786 | break; | |
b6a7907f RS |
787 | default: |
788 | break; | |
789 | } | |
790 | } | |
791 | ||
792 | unk714 |= (next->bios.ramcfg_10_04_01) << 8; | |
793 | ||
c378eb74 | 794 | if (next->bios.ramcfg_10_02_20) |
aae95ca7 | 795 | unk714 |= 0xf0000000; |
b6a7907f RS |
796 | if (next->bios.ramcfg_10_02_02) |
797 | unk718 |= 0x00000100; | |
c378eb74 | 798 | if (next->bios.ramcfg_10_02_01) |
aae95ca7 | 799 | unk71c |= 0x00000100; |
b6a7907f RS |
800 | if (next->bios.timing_10_24 != 0xff) { |
801 | unk718 &= ~0xf0000000; | |
802 | unk718 |= next->bios.timing_10_24 << 28; | |
803 | } | |
804 | if (next->bios.ramcfg_10_02_10) | |
805 | r111100 &= ~0x04020000; | |
aae95ca7 | 806 | |
b6a7907f RS |
807 | ram_mask(fuc, 0x100714, 0xffffffff, unk714); |
808 | ram_mask(fuc, 0x10071c, 0xffffffff, unk71c); | |
809 | ram_mask(fuc, 0x100718, 0xffffffff, unk718); | |
810 | ram_mask(fuc, 0x111100, 0xffffffff, r111100); | |
aae95ca7 | 811 | |
598a39e7 | 812 | if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT) |
639c308e | 813 | gt215_ram_fbvref(fuc, 1); |
598a39e7 | 814 | |
b6a7907f | 815 | /* Reset DLL */ |
7164f4c5 | 816 | if (!next->bios.ramcfg_DLLoff) |
639c308e | 817 | nvkm_sddr2_dll_reset(fuc); |
aae95ca7 | 818 | |
d36a99d2 | 819 | if (ram->base.type == NVKM_RAM_TYPE_GDDR3) { |
598a39e7 RS |
820 | ram_nsec(fuc, 31000); |
821 | } else { | |
822 | ram_nsec(fuc, 14000); | |
823 | } | |
aae95ca7 | 824 | |
d36a99d2 | 825 | if (ram->base.type == NVKM_RAM_TYPE_DDR3) { |
b0c7336b RS |
826 | ram_wr32(fuc, 0x100264, 0x1); |
827 | ram_nsec(fuc, 2000); | |
828 | } | |
aae95ca7 | 829 | |
b6a7907f RS |
830 | ram_nuke(fuc, 0x100700); |
831 | ram_mask(fuc, 0x100700, 0x01000000, 0x01000000); | |
832 | ram_mask(fuc, 0x100700, 0x01000000, 0x00000000); | |
833 | ||
834 | /* Re-enable FB */ | |
835 | ram_unblock(fuc); | |
836 | ram_wr32(fuc, 0x611200, 0x3330); | |
837 | ||
838 | /* Post fiddlings */ | |
c378eb74 | 839 | if (next->bios.rammap_10_04_02) |
aae95ca7 | 840 | ram_mask(fuc, 0x100200, 0x00000800, 0x00000800); |
c378eb74 | 841 | if (next->bios.ramcfg_10_02_10) { |
aae95ca7 BS |
842 | ram_mask(fuc, 0x111104, 0x00000180, 0x00000180); |
843 | ram_mask(fuc, 0x111100, 0x40000000, 0x00000000); | |
844 | } else { | |
845 | ram_mask(fuc, 0x111104, 0x00000600, 0x00000600); | |
846 | } | |
847 | ||
848 | if (mclk.pll) { | |
849 | ram_mask(fuc, 0x004168, 0x00000001, 0x00000000); | |
850 | ram_mask(fuc, 0x004168, 0x00000100, 0x00000000); | |
851 | } else { | |
852 | ram_mask(fuc, 0x004000, 0x00000001, 0x00000000); | |
853 | ram_mask(fuc, 0x004128, 0x00000001, 0x00000000); | |
854 | ram_mask(fuc, 0x004128, 0x00000100, 0x00000000); | |
855 | } | |
856 | ||
857 | return 0; | |
858 | } | |
859 | ||
860 | static int | |
d36a99d2 | 861 | gt215_ram_prog(struct nvkm_ram *base) |
aae95ca7 | 862 | { |
d36a99d2 | 863 | struct gt215_ram *ram = gt215_ram(base); |
639c308e | 864 | struct gt215_ramfuc *fuc = &ram->fuc; |
d36a99d2 | 865 | struct nvkm_device *device = ram->base.fb->subdev.device; |
639c308e | 866 | bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true); |
b6a7907f RS |
867 | |
868 | if (exec) { | |
6758745b | 869 | nvkm_mask(device, 0x001534, 0x2, 0x2); |
b6a7907f RS |
870 | |
871 | ram_exec(fuc, true); | |
872 | ||
873 | /* Post-processing, avoids flicker */ | |
6758745b BS |
874 | nvkm_mask(device, 0x002504, 0x1, 0x0); |
875 | nvkm_mask(device, 0x001534, 0x2, 0x0); | |
b6a7907f | 876 | |
6758745b BS |
877 | nvkm_mask(device, 0x616308, 0x10, 0x10); |
878 | nvkm_mask(device, 0x616b08, 0x10, 0x10); | |
b6a7907f RS |
879 | } else { |
880 | ram_exec(fuc, false); | |
881 | } | |
aae95ca7 BS |
882 | return 0; |
883 | } | |
884 | ||
885 | static void | |
d36a99d2 | 886 | gt215_ram_tidy(struct nvkm_ram *base) |
aae95ca7 | 887 | { |
d36a99d2 BS |
888 | struct gt215_ram *ram = gt215_ram(base); |
889 | ram_exec(&ram->fuc, false); | |
aae95ca7 BS |
890 | } |
891 | ||
892 | static int | |
d36a99d2 | 893 | gt215_ram_init(struct nvkm_ram *base) |
aae95ca7 | 894 | { |
d36a99d2 BS |
895 | struct gt215_ram *ram = gt215_ram(base); |
896 | gt215_link_train_init(ram); | |
7f4b9616 RS |
897 | return 0; |
898 | } | |
899 | ||
d36a99d2 BS |
900 | static void * |
901 | gt215_ram_dtor(struct nvkm_ram *base) | |
7f4b9616 | 902 | { |
d36a99d2 BS |
903 | struct gt215_ram *ram = gt215_ram(base); |
904 | gt215_link_train_fini(ram); | |
905 | return ram; | |
aae95ca7 BS |
906 | } |
907 | ||
d36a99d2 BS |
908 | static const struct nvkm_ram_func |
909 | gt215_ram_func = { | |
910 | .dtor = gt215_ram_dtor, | |
911 | .init = gt215_ram_init, | |
912 | .get = nv50_ram_get, | |
913 | .put = nv50_ram_put, | |
914 | .calc = gt215_ram_calc, | |
915 | .prog = gt215_ram_prog, | |
916 | .tidy = gt215_ram_tidy, | |
917 | }; | |
918 | ||
919 | int | |
920 | gt215_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) | |
75faef78 | 921 | { |
d36a99d2 | 922 | struct nvkm_gpio *gpio = fb->subdev.device->gpio; |
598a39e7 | 923 | struct dcb_gpio_func func; |
639c308e | 924 | struct gt215_ram *ram; |
598a39e7 | 925 | u32 reg, shift; |
d36a99d2 BS |
926 | int ret, i; |
927 | ||
928 | if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) | |
929 | return -ENOMEM; | |
930 | *pram = &ram->base; | |
75faef78 | 931 | |
d36a99d2 | 932 | ret = nv50_ram_ctor(>215_ram_func, fb, &ram->base); |
75faef78 BS |
933 | if (ret) |
934 | return ret; | |
935 | ||
7f4b9616 RS |
936 | ram->fuc.r_0x001610 = ramfuc_reg(0x001610); |
937 | ram->fuc.r_0x001700 = ramfuc_reg(0x001700); | |
b6a7907f | 938 | ram->fuc.r_0x002504 = ramfuc_reg(0x002504); |
aae95ca7 BS |
939 | ram->fuc.r_0x004000 = ramfuc_reg(0x004000); |
940 | ram->fuc.r_0x004004 = ramfuc_reg(0x004004); | |
941 | ram->fuc.r_0x004018 = ramfuc_reg(0x004018); | |
942 | ram->fuc.r_0x004128 = ramfuc_reg(0x004128); | |
943 | ram->fuc.r_0x004168 = ramfuc_reg(0x004168); | |
7f4b9616 | 944 | ram->fuc.r_0x100080 = ramfuc_reg(0x100080); |
aae95ca7 BS |
945 | ram->fuc.r_0x100200 = ramfuc_reg(0x100200); |
946 | ram->fuc.r_0x100210 = ramfuc_reg(0x100210); | |
947 | for (i = 0; i < 9; i++) | |
948 | ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4)); | |
b6a7907f | 949 | ram->fuc.r_0x100264 = ramfuc_reg(0x100264); |
aae95ca7 BS |
950 | ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0); |
951 | ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4); | |
952 | ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc); | |
953 | ram->fuc.r_0x10053c = ramfuc_reg(0x10053c); | |
954 | ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0); | |
955 | ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4); | |
b6a7907f | 956 | ram->fuc.r_0x100700 = ramfuc_reg(0x100700); |
aae95ca7 BS |
957 | ram->fuc.r_0x100714 = ramfuc_reg(0x100714); |
958 | ram->fuc.r_0x100718 = ramfuc_reg(0x100718); | |
959 | ram->fuc.r_0x10071c = ramfuc_reg(0x10071c); | |
7f4b9616 | 960 | ram->fuc.r_0x100720 = ramfuc_reg(0x100720); |
a4073189 RS |
961 | ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask); |
962 | ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask); | |
963 | ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask); | |
b6a7907f | 964 | ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask); |
aae95ca7 | 965 | ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804); |
a4073189 | 966 | ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask); |
aae95ca7 BS |
967 | ram->fuc.r_0x111100 = ramfuc_reg(0x111100); |
968 | ram->fuc.r_0x111104 = ramfuc_reg(0x111104); | |
7f4b9616 RS |
969 | ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0); |
970 | ram->fuc.r_0x111400 = ramfuc_reg(0x111400); | |
aae95ca7 BS |
971 | ram->fuc.r_0x611200 = ramfuc_reg(0x611200); |
972 | ||
973 | if (ram->base.ranks > 1) { | |
974 | ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8); | |
975 | ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc); | |
976 | ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8); | |
977 | ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec); | |
978 | } else { | |
979 | ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0); | |
980 | ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4); | |
981 | ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0); | |
982 | ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4); | |
983 | } | |
984 | ||
2ea7249f | 985 | ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); |
598a39e7 RS |
986 | if (ret == 0) { |
987 | nv50_gpio_location(func.line, ®, &shift); | |
988 | ram->fuc.r_gpioFBVREF = ramfuc_reg(reg); | |
989 | } | |
990 | ||
75faef78 BS |
991 | return 0; |
992 | } |