]>
Commit | Line | Data |
---|---|---|
dceef5d8 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 | |
23 | */ | |
639c308e BS |
24 | #include "nv50.h" |
25 | #include "ramseq.h" | |
dceef5d8 | 26 | |
639c308e | 27 | #include <core/option.h> |
dceef5d8 | 28 | #include <subdev/bios.h> |
aae95ca7 | 29 | #include <subdev/bios/perf.h> |
639c308e | 30 | #include <subdev/bios/pll.h> |
35fe024a | 31 | #include <subdev/bios/rammap.h> |
aae95ca7 | 32 | #include <subdev/bios/timing.h> |
f3867f43 | 33 | #include <subdev/clk/pll.h> |
dceef5d8 | 34 | |
aae95ca7 BS |
35 | struct nv50_ramseq { |
36 | struct hwsq base; | |
37 | struct hwsq_reg r_0x002504; | |
38 | struct hwsq_reg r_0x004008; | |
39 | struct hwsq_reg r_0x00400c; | |
40 | struct hwsq_reg r_0x00c040; | |
82a74fd2 | 41 | struct hwsq_reg r_0x100200; |
aae95ca7 | 42 | struct hwsq_reg r_0x100210; |
82a74fd2 | 43 | struct hwsq_reg r_0x10021c; |
aae95ca7 BS |
44 | struct hwsq_reg r_0x1002d0; |
45 | struct hwsq_reg r_0x1002d4; | |
46 | struct hwsq_reg r_0x1002dc; | |
82a74fd2 RS |
47 | struct hwsq_reg r_0x10053c; |
48 | struct hwsq_reg r_0x1005a0; | |
49 | struct hwsq_reg r_0x1005a4; | |
50 | struct hwsq_reg r_0x100710; | |
51 | struct hwsq_reg r_0x100714; | |
52 | struct hwsq_reg r_0x100718; | |
53 | struct hwsq_reg r_0x10071c; | |
d4cc5f0c | 54 | struct hwsq_reg r_0x100da0; |
aae95ca7 BS |
55 | struct hwsq_reg r_0x100e20; |
56 | struct hwsq_reg r_0x100e24; | |
57 | struct hwsq_reg r_0x611200; | |
58 | struct hwsq_reg r_timing[9]; | |
59 | struct hwsq_reg r_mr[4]; | |
60 | }; | |
61 | ||
75faef78 | 62 | struct nv50_ram { |
639c308e | 63 | struct nvkm_ram base; |
aae95ca7 | 64 | struct nv50_ramseq hwsq; |
75faef78 BS |
65 | }; |
66 | ||
35fe024a RS |
67 | #define T(t) cfg->timing_10_##t |
68 | static int | |
b1e4553c | 69 | nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) |
35fe024a | 70 | { |
b1e4553c | 71 | struct nv50_ram *ram = (void *)fb->ram; |
35fe024a | 72 | struct nvbios_ramcfg *cfg = &ram->base.target.bios; |
b1e4553c | 73 | u32 cur2, cur4, cur7, cur8; |
35fe024a RS |
74 | u8 unkt3b; |
75 | ||
b1e4553c BS |
76 | cur2 = nv_rd32(fb, 0x100228); |
77 | cur4 = nv_rd32(fb, 0x100230); | |
78 | cur7 = nv_rd32(fb, 0x10023c); | |
79 | cur8 = nv_rd32(fb, 0x100240); | |
35fe024a RS |
80 | |
81 | switch ((!T(CWL)) * ram->base.type) { | |
82 | case NV_MEM_TYPE_DDR2: | |
83 | T(CWL) = T(CL) - 1; | |
84 | break; | |
85 | case NV_MEM_TYPE_GDDR3: | |
86 | T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; | |
87 | break; | |
88 | } | |
89 | ||
90 | /* XXX: N=1 is not proper statistics */ | |
b1e4553c | 91 | if (nv_device(fb)->chipset == 0xa0) { |
35fe024a RS |
92 | unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40; |
93 | timing[6] = (0x2d + T(CL) - T(CWL) + | |
94 | ram->base.next->bios.rammap_00_16_40) << 16 | | |
95 | T(CWL) << 8 | | |
96 | (0x2f + T(CL) - T(CWL)); | |
97 | } else { | |
98 | unkt3b = 0x16; | |
99 | timing[6] = (0x2b + T(CL) - T(CWL)) << 16 | | |
100 | max_t(s8, T(CWL) - 2, 1) << 8 | | |
101 | (0x2e + T(CL) - T(CWL)); | |
102 | } | |
103 | ||
104 | timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC)); | |
105 | timing[1] = (T(WR) + 1 + T(CWL)) << 24 | | |
106 | max_t(u8, T(18), 1) << 16 | | |
107 | (T(WTR) + 1 + T(CWL)) << 8 | | |
108 | (3 + T(CL) - T(CWL)); | |
109 | timing[2] = (T(CWL) - 1) << 24 | | |
110 | (T(RRD) << 16) | | |
111 | (T(RCDWR) << 8) | | |
112 | T(RCDRD); | |
113 | timing[3] = (unkt3b - 2 + T(CL)) << 24 | | |
114 | unkt3b << 16 | | |
115 | (T(CL) - 1) << 8 | | |
116 | (T(CL) - 1); | |
117 | timing[4] = (cur4 & 0xffff0000) | | |
118 | T(13) << 8 | | |
119 | T(13); | |
120 | timing[5] = T(RFC) << 24 | | |
121 | max_t(u8, T(RCDRD), T(RCDWR)) << 16 | | |
122 | T(RP); | |
123 | /* Timing 6 is already done above */ | |
124 | timing[7] = (cur7 & 0xff00ffff) | (T(CL) - 1) << 16; | |
125 | timing[8] = (cur8 & 0xffffff00); | |
126 | ||
127 | /* XXX: P.version == 1 only has DDR2 and GDDR3? */ | |
b1e4553c | 128 | if (fb->ram->type == NV_MEM_TYPE_DDR2) { |
35fe024a RS |
129 | timing[5] |= (T(CL) + 3) << 8; |
130 | timing[8] |= (T(CL) - 4); | |
b1e4553c | 131 | } else if (fb->ram->type == NV_MEM_TYPE_GDDR3) { |
35fe024a RS |
132 | timing[5] |= (T(CL) + 2) << 8; |
133 | timing[8] |= (T(CL) - 2); | |
134 | } | |
135 | ||
b1e4553c | 136 | nv_debug(fb, " 220: %08x %08x %08x %08x\n", |
35fe024a | 137 | timing[0], timing[1], timing[2], timing[3]); |
b1e4553c | 138 | nv_debug(fb, " 230: %08x %08x %08x %08x\n", |
35fe024a | 139 | timing[4], timing[5], timing[6], timing[7]); |
b1e4553c | 140 | nv_debug(fb, " 240: %08x\n", timing[8]); |
35fe024a RS |
141 | return 0; |
142 | } | |
143 | #undef T | |
144 | ||
82a74fd2 RS |
145 | static void |
146 | nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) | |
147 | { | |
148 | ram_mask(hwsq, mr[0], 0x100, 0x100); | |
149 | ram_mask(hwsq, mr[0], 0x100, 0x000); | |
150 | ram_nsec(hwsq, 24000); | |
151 | } | |
aae95ca7 BS |
152 | |
153 | static int | |
b1e4553c | 154 | nv50_ram_calc(struct nvkm_fb *fb, u32 freq) |
aae95ca7 | 155 | { |
b1e4553c BS |
156 | struct nvkm_bios *bios = nvkm_bios(fb); |
157 | struct nv50_ram *ram = (void *)fb->ram; | |
aae95ca7 BS |
158 | struct nv50_ramseq *hwsq = &ram->hwsq; |
159 | struct nvbios_perfE perfE; | |
160 | struct nvbios_pll mpll; | |
35fe024a RS |
161 | struct nvkm_ram_data *next; |
162 | u8 ver, hdr, cnt, len, strap, size; | |
163 | u32 data; | |
82a74fd2 | 164 | u32 r100da0, r004008, unk710, unk714, unk718, unk71c; |
aae95ca7 BS |
165 | int N1, M1, N2, M2, P; |
166 | int ret, i; | |
35fe024a RS |
167 | u32 timing[9]; |
168 | ||
169 | next = &ram->base.target; | |
170 | next->freq = freq; | |
171 | ram->base.next = next; | |
aae95ca7 BS |
172 | |
173 | /* lookup closest matching performance table entry for frequency */ | |
174 | i = 0; | |
175 | do { | |
35fe024a RS |
176 | data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, |
177 | &size, &perfE); | |
178 | if (!data || (ver < 0x25 || ver >= 0x40) || | |
179 | (size < 2)) { | |
b1e4553c | 180 | nv_error(fb, "invalid/missing perftab entry\n"); |
aae95ca7 BS |
181 | return -EINVAL; |
182 | } | |
183 | } while (perfE.memory < freq); | |
184 | ||
2813e19f RS |
185 | nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios); |
186 | ||
aae95ca7 | 187 | /* locate specific data set for the attached memory */ |
b1e4553c | 188 | strap = nvbios_ramcfg_index(nv_subdev(fb)); |
aae95ca7 | 189 | if (strap >= cnt) { |
b1e4553c | 190 | nv_error(fb, "invalid ramcfg strap\n"); |
aae95ca7 BS |
191 | return -EINVAL; |
192 | } | |
193 | ||
35fe024a RS |
194 | data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap, |
195 | &next->bios); | |
196 | if (!data) { | |
b1e4553c | 197 | nv_error(fb, "invalid/missing rammap entry "); |
35fe024a RS |
198 | return -EINVAL; |
199 | } | |
aae95ca7 BS |
200 | |
201 | /* lookup memory timings, if bios says they're present */ | |
35fe024a RS |
202 | if (next->bios.ramcfg_timing != 0xff) { |
203 | data = nvbios_timingEp(bios, next->bios.ramcfg_timing, | |
204 | &ver, &hdr, &cnt, &len, &next->bios); | |
205 | if (!data || ver != 0x10 || hdr < 0x12) { | |
b1e4553c | 206 | nv_error(fb, "invalid/missing timing entry " |
aae95ca7 | 207 | "%02x %04x %02x %02x\n", |
35fe024a | 208 | strap, data, ver, hdr); |
aae95ca7 BS |
209 | return -EINVAL; |
210 | } | |
aae95ca7 BS |
211 | } |
212 | ||
b1e4553c | 213 | nv50_ram_timing_calc(fb, timing); |
35fe024a | 214 | |
b1e4553c | 215 | ret = ram_init(hwsq, nv_subdev(fb)); |
35fe024a RS |
216 | if (ret) |
217 | return ret; | |
218 | ||
219 | /* Determine ram-specific MR values */ | |
220 | ram->base.mr[0] = ram_rd32(hwsq, mr[0]); | |
221 | ram->base.mr[1] = ram_rd32(hwsq, mr[1]); | |
222 | ram->base.mr[2] = ram_rd32(hwsq, mr[2]); | |
223 | ||
224 | switch (ram->base.type) { | |
225 | case NV_MEM_TYPE_GDDR3: | |
226 | ret = nvkm_gddr3_calc(&ram->base); | |
227 | break; | |
228 | default: | |
229 | ret = -ENOSYS; | |
230 | break; | |
231 | } | |
232 | ||
233 | if (ret) | |
234 | return ret; | |
235 | ||
82a74fd2 RS |
236 | /* Always disable this bit during reclock */ |
237 | ram_mask(hwsq, 0x100200, 0x00000800, 0x00000000); | |
d4cc5f0c | 238 | |
aae95ca7 BS |
239 | ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */ |
240 | ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */ | |
241 | ram_wr32(hwsq, 0x611200, 0x00003300); | |
242 | ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */ | |
243 | ram_nsec(hwsq, 8000); | |
244 | ram_setf(hwsq, 0x10, 0x00); /* disable fb */ | |
245 | ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */ | |
82a74fd2 | 246 | ram_nsec(hwsq, 2000); |
aae95ca7 BS |
247 | |
248 | ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */ | |
249 | ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ | |
250 | ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ | |
251 | ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */ | |
252 | ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */ | |
253 | ||
254 | ret = nvbios_pll_parse(bios, 0x004008, &mpll); | |
255 | mpll.vco2.max_freq = 0; | |
b1e4553c BS |
256 | if (ret >= 0) { |
257 | ret = nv04_pll_calc(nv_subdev(fb), &mpll, freq, | |
639c308e | 258 | &N1, &M1, &N2, &M2, &P); |
b1e4553c | 259 | if (ret <= 0) |
aae95ca7 BS |
260 | ret = -EINVAL; |
261 | } | |
262 | ||
263 | if (ret < 0) | |
264 | return ret; | |
265 | ||
82a74fd2 RS |
266 | /* XXX: 750MHz seems rather arbitrary */ |
267 | if (freq <= 750000) { | |
268 | r100da0 = 0x00000010; | |
269 | r004008 = 0x90000000; | |
270 | } else { | |
271 | r100da0 = 0x00000000; | |
272 | r004008 = 0x80000000; | |
273 | } | |
274 | ||
275 | r004008 |= (mpll.bias_p << 19) | (P << 22) | (P << 16); | |
276 | ||
aae95ca7 | 277 | ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000); |
82a74fd2 RS |
278 | /* XXX: Is rammap_00_16_40 the DLL bit we've seen in GT215? Why does |
279 | * it have a different rammap bit from DLLoff? */ | |
280 | ram_mask(hwsq, 0x004008, 0x00004200, 0x00000200 | | |
281 | next->bios.rammap_00_16_40 << 14); | |
aae95ca7 | 282 | ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); |
82a74fd2 | 283 | ram_mask(hwsq, 0x004008, 0x91ff0000, r004008); |
b1e4553c | 284 | if (nv_device(fb)->chipset >= 0x96) |
82a74fd2 RS |
285 | ram_wr32(hwsq, 0x100da0, r100da0); |
286 | ram_nsec(hwsq, 64000); /*XXX*/ | |
287 | ram_nsec(hwsq, 32000); /*XXX*/ | |
d4cc5f0c | 288 | |
aae95ca7 BS |
289 | ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000); |
290 | ||
291 | ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */ | |
82a74fd2 | 292 | ram_wr32(hwsq, 0x1002d4, 0x00000001); /* disable self-refresh */ |
aae95ca7 BS |
293 | ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */ |
294 | ||
295 | ram_nsec(hwsq, 12000); | |
296 | ||
297 | switch (ram->base.type) { | |
298 | case NV_MEM_TYPE_DDR2: | |
299 | ram_nuke(hwsq, mr[0]); /* force update */ | |
300 | ram_mask(hwsq, mr[0], 0x000, 0x000); | |
301 | break; | |
302 | case NV_MEM_TYPE_GDDR3: | |
82a74fd2 RS |
303 | ram_nuke(hwsq, mr[1]); /* force update */ |
304 | ram_wr32(hwsq, mr[1], ram->base.mr[1]); | |
aae95ca7 | 305 | ram_nuke(hwsq, mr[0]); /* force update */ |
82a74fd2 | 306 | ram_wr32(hwsq, mr[0], ram->base.mr[0]); |
aae95ca7 BS |
307 | break; |
308 | default: | |
309 | break; | |
310 | } | |
311 | ||
35fe024a RS |
312 | ram_mask(hwsq, timing[3], 0xffffffff, timing[3]); |
313 | ram_mask(hwsq, timing[1], 0xffffffff, timing[1]); | |
314 | ram_mask(hwsq, timing[6], 0xffffffff, timing[6]); | |
315 | ram_mask(hwsq, timing[7], 0xffffffff, timing[7]); | |
316 | ram_mask(hwsq, timing[8], 0xffffffff, timing[8]); | |
317 | ram_mask(hwsq, timing[0], 0xffffffff, timing[0]); | |
318 | ram_mask(hwsq, timing[2], 0xffffffff, timing[2]); | |
319 | ram_mask(hwsq, timing[4], 0xffffffff, timing[4]); | |
320 | ram_mask(hwsq, timing[5], 0xffffffff, timing[5]); | |
aae95ca7 | 321 | |
82a74fd2 RS |
322 | if (!next->bios.ramcfg_00_03_02) |
323 | ram_mask(hwsq, 0x10021c, 0x00010000, 0x00000000); | |
324 | ram_mask(hwsq, 0x100200, 0x00001000, !next->bios.ramcfg_00_04_02 << 12); | |
325 | ||
326 | /* XXX: A lot of this could be "chipset"/"ram type" specific stuff */ | |
327 | unk710 = ram_rd32(hwsq, 0x100710) & ~0x00000101; | |
328 | unk714 = ram_rd32(hwsq, 0x100714) & ~0xf0000020; | |
329 | unk718 = ram_rd32(hwsq, 0x100718) & ~0x00000100; | |
330 | unk71c = ram_rd32(hwsq, 0x10071c) & ~0x00000100; | |
331 | ||
332 | if ( next->bios.ramcfg_00_03_01) | |
333 | unk71c |= 0x00000100; | |
334 | if ( next->bios.ramcfg_00_03_02) | |
335 | unk710 |= 0x00000100; | |
336 | if (!next->bios.ramcfg_00_03_08) { | |
337 | unk710 |= 0x1; | |
338 | unk714 |= 0x20; | |
339 | } | |
340 | if ( next->bios.ramcfg_00_04_04) | |
341 | unk714 |= 0x70000000; | |
342 | if ( next->bios.ramcfg_00_04_20) | |
343 | unk718 |= 0x00000100; | |
344 | ||
345 | ram_mask(hwsq, 0x100714, 0xffffffff, unk714); | |
346 | ram_mask(hwsq, 0x10071c, 0xffffffff, unk71c); | |
347 | ram_mask(hwsq, 0x100718, 0xffffffff, unk718); | |
348 | ram_mask(hwsq, 0x100710, 0xffffffff, unk710); | |
349 | ||
350 | if (next->bios.rammap_00_16_20) { | |
351 | ram_wr32(hwsq, 0x1005a0, next->bios.ramcfg_00_07 << 16 | | |
352 | next->bios.ramcfg_00_06 << 8 | | |
353 | next->bios.ramcfg_00_05); | |
354 | ram_wr32(hwsq, 0x1005a4, next->bios.ramcfg_00_09 << 8 | | |
355 | next->bios.ramcfg_00_08); | |
356 | ram_mask(hwsq, 0x10053c, 0x00001000, 0x00000000); | |
357 | } else { | |
358 | ram_mask(hwsq, 0x10053c, 0x00001000, 0x00001000); | |
359 | } | |
360 | ram_mask(hwsq, mr[1], 0xffffffff, ram->base.mr[1]); | |
aae95ca7 | 361 | |
82a74fd2 RS |
362 | /* Reset DLL */ |
363 | if (!next->bios.ramcfg_DLLoff) | |
364 | nvkm_sddr2_dll_reset(hwsq); | |
aae95ca7 BS |
365 | |
366 | ram_setf(hwsq, 0x10, 0x01); /* enable fb */ | |
367 | ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */ | |
368 | ram_wr32(hwsq, 0x611200, 0x00003330); | |
369 | ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */ | |
82a74fd2 RS |
370 | |
371 | if (next->bios.rammap_00_17_02) | |
372 | ram_mask(hwsq, 0x100200, 0x00000800, 0x00000800); | |
373 | if (!next->bios.rammap_00_16_40) | |
374 | ram_mask(hwsq, 0x004008, 0x00004000, 0x00000000); | |
375 | if (next->bios.ramcfg_00_03_02) | |
376 | ram_mask(hwsq, 0x10021c, 0x00010000, 0x00010000); | |
377 | ||
aae95ca7 BS |
378 | return 0; |
379 | } | |
380 | ||
381 | static int | |
b1e4553c | 382 | nv50_ram_prog(struct nvkm_fb *fb) |
aae95ca7 | 383 | { |
b1e4553c BS |
384 | struct nvkm_device *device = nv_device(fb); |
385 | struct nv50_ram *ram = (void *)fb->ram; | |
aae95ca7 BS |
386 | struct nv50_ramseq *hwsq = &ram->hwsq; |
387 | ||
639c308e | 388 | ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); |
aae95ca7 BS |
389 | return 0; |
390 | } | |
391 | ||
392 | static void | |
b1e4553c | 393 | nv50_ram_tidy(struct nvkm_fb *fb) |
aae95ca7 | 394 | { |
b1e4553c | 395 | struct nv50_ram *ram = (void *)fb->ram; |
aae95ca7 BS |
396 | struct nv50_ramseq *hwsq = &ram->hwsq; |
397 | ram_exec(hwsq, false); | |
398 | } | |
399 | ||
dceef5d8 | 400 | void |
b1e4553c | 401 | __nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem *mem) |
dceef5d8 | 402 | { |
639c308e | 403 | struct nvkm_mm_node *this; |
dceef5d8 | 404 | |
dceef5d8 BS |
405 | while (!list_empty(&mem->regions)) { |
406 | this = list_first_entry(&mem->regions, typeof(*this), rl_entry); | |
407 | ||
408 | list_del(&this->rl_entry); | |
b1e4553c | 409 | nvkm_mm_free(&fb->vram, &this); |
dceef5d8 BS |
410 | } |
411 | ||
b1e4553c | 412 | nvkm_mm_free(&fb->tags, &mem->tag); |
dedaa8f0 RS |
413 | } |
414 | ||
415 | void | |
b1e4553c | 416 | nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) |
dedaa8f0 | 417 | { |
639c308e | 418 | struct nvkm_mem *mem = *pmem; |
dedaa8f0 RS |
419 | |
420 | *pmem = NULL; | |
421 | if (unlikely(mem == NULL)) | |
422 | return; | |
423 | ||
b1e4553c BS |
424 | mutex_lock(&fb->subdev.mutex); |
425 | __nv50_ram_put(fb, mem); | |
426 | mutex_unlock(&fb->subdev.mutex); | |
dceef5d8 BS |
427 | |
428 | kfree(mem); | |
429 | } | |
430 | ||
75faef78 | 431 | int |
b1e4553c | 432 | nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, |
639c308e | 433 | u32 memtype, struct nvkm_mem **pmem) |
dceef5d8 | 434 | { |
b1e4553c BS |
435 | struct nvkm_mm *heap = &fb->vram; |
436 | struct nvkm_mm *tags = &fb->tags; | |
639c308e BS |
437 | struct nvkm_mm_node *r; |
438 | struct nvkm_mem *mem; | |
dceef5d8 BS |
439 | int comp = (memtype & 0x300) >> 8; |
440 | int type = (memtype & 0x07f); | |
441 | int back = (memtype & 0x800); | |
442 | int min, max, ret; | |
443 | ||
444 | max = (size >> 12); | |
445 | min = ncmin ? (ncmin >> 12) : max; | |
446 | align >>= 12; | |
447 | ||
448 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | |
449 | if (!mem) | |
450 | return -ENOMEM; | |
451 | ||
b1e4553c | 452 | mutex_lock(&fb->subdev.mutex); |
dceef5d8 BS |
453 | if (comp) { |
454 | if (align == 16) { | |
455 | int n = (max >> 4) * comp; | |
456 | ||
639c308e | 457 | ret = nvkm_mm_head(tags, 0, 1, n, n, 1, &mem->tag); |
dceef5d8 BS |
458 | if (ret) |
459 | mem->tag = NULL; | |
460 | } | |
461 | ||
462 | if (unlikely(!mem->tag)) | |
463 | comp = 0; | |
464 | } | |
465 | ||
466 | INIT_LIST_HEAD(&mem->regions); | |
467 | mem->memtype = (comp << 7) | type; | |
468 | mem->size = max; | |
469 | ||
470 | type = nv50_fb_memtype[type]; | |
471 | do { | |
472 | if (back) | |
639c308e | 473 | ret = nvkm_mm_tail(heap, 0, type, max, min, align, &r); |
dceef5d8 | 474 | else |
639c308e | 475 | ret = nvkm_mm_head(heap, 0, type, max, min, align, &r); |
dceef5d8 | 476 | if (ret) { |
b1e4553c BS |
477 | mutex_unlock(&fb->subdev.mutex); |
478 | fb->ram->put(fb, &mem); | |
dceef5d8 BS |
479 | return ret; |
480 | } | |
481 | ||
482 | list_add_tail(&r->rl_entry, &mem->regions); | |
483 | max -= r->length; | |
484 | } while (max); | |
b1e4553c | 485 | mutex_unlock(&fb->subdev.mutex); |
dceef5d8 | 486 | |
639c308e | 487 | r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); |
dceef5d8 BS |
488 | mem->offset = (u64)r->offset << 12; |
489 | *pmem = mem; | |
490 | return 0; | |
491 | } | |
492 | ||
493 | static u32 | |
b1e4553c | 494 | nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) |
dceef5d8 | 495 | { |
de1c4e28 | 496 | int colbits, rowbitsa, rowbitsb, banks; |
dceef5d8 | 497 | u64 rowsize, predicted; |
de1c4e28 | 498 | u32 r0, r4, rt, rblock_size; |
dceef5d8 | 499 | |
b1e4553c BS |
500 | r0 = nv_rd32(fb, 0x100200); |
501 | r4 = nv_rd32(fb, 0x100204); | |
502 | rt = nv_rd32(fb, 0x100250); | |
503 | nv_debug(fb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
504 | r0, r4, rt, nv_rd32(fb, 0x001540)); | |
dceef5d8 BS |
505 | |
506 | colbits = (r4 & 0x0000f000) >> 12; | |
507 | rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; | |
508 | rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; | |
509 | banks = 1 << (((r4 & 0x03000000) >> 24) + 2); | |
510 | ||
de1c4e28 | 511 | rowsize = ram->parts * banks * (1 << colbits) * 8; |
dceef5d8 BS |
512 | predicted = rowsize << rowbitsa; |
513 | if (r0 & 0x00000004) | |
514 | predicted += rowsize << rowbitsb; | |
515 | ||
516 | if (predicted != ram->size) { | |
b1e4553c | 517 | nv_warn(fb, "memory controller reports %d MiB VRAM\n", |
dceef5d8 BS |
518 | (u32)(ram->size >> 20)); |
519 | } | |
520 | ||
521 | rblock_size = rowsize; | |
522 | if (rt & 1) | |
523 | rblock_size *= 3; | |
524 | ||
b1e4553c | 525 | nv_debug(fb, "rblock %d bytes\n", rblock_size); |
dceef5d8 BS |
526 | return rblock_size; |
527 | } | |
528 | ||
75faef78 | 529 | int |
639c308e BS |
530 | nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, |
531 | struct nvkm_oclass *oclass, int length, void **pobject) | |
dceef5d8 | 532 | { |
dceef5d8 BS |
533 | const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ |
534 | const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ | |
639c308e | 535 | struct nvkm_bios *bios = nvkm_bios(parent); |
b1e4553c | 536 | struct nvkm_fb *fb = nvkm_fb(parent); |
639c308e | 537 | struct nvkm_ram *ram; |
dceef5d8 BS |
538 | int ret; |
539 | ||
639c308e | 540 | ret = nvkm_ram_create_(parent, engine, oclass, length, pobject); |
75faef78 | 541 | ram = *pobject; |
dceef5d8 BS |
542 | if (ret) |
543 | return ret; | |
544 | ||
b1e4553c | 545 | ram->size = nv_rd32(fb, 0x10020c); |
75faef78 | 546 | ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); |
dceef5d8 | 547 | |
b1e4553c | 548 | ram->part_mask = (nv_rd32(fb, 0x001540) & 0x00ff0000) >> 16; |
de1c4e28 RS |
549 | ram->parts = hweight8(ram->part_mask); |
550 | ||
b1e4553c | 551 | switch (nv_rd32(fb, 0x100714) & 0x00000007) { |
75faef78 BS |
552 | case 0: ram->type = NV_MEM_TYPE_DDR1; break; |
553 | case 1: | |
639c308e | 554 | if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) |
75faef78 BS |
555 | ram->type = NV_MEM_TYPE_DDR3; |
556 | else | |
557 | ram->type = NV_MEM_TYPE_DDR2; | |
dceef5d8 | 558 | break; |
75faef78 BS |
559 | case 2: ram->type = NV_MEM_TYPE_GDDR3; break; |
560 | case 3: ram->type = NV_MEM_TYPE_GDDR4; break; | |
561 | case 4: ram->type = NV_MEM_TYPE_GDDR5; break; | |
dceef5d8 | 562 | default: |
dceef5d8 BS |
563 | break; |
564 | } | |
565 | ||
b1e4553c | 566 | ret = nvkm_mm_init(&fb->vram, rsvd_head, (ram->size >> 12) - |
639c308e | 567 | (rsvd_head + rsvd_tail), |
b1e4553c | 568 | nv50_fb_vram_rblock(fb, ram) >> 12); |
75faef78 BS |
569 | if (ret) |
570 | return ret; | |
571 | ||
b1e4553c BS |
572 | ram->ranks = (nv_rd32(fb, 0x100200) & 0x4) ? 2 : 1; |
573 | ram->tags = nv_rd32(fb, 0x100320); | |
dceef5d8 BS |
574 | ram->get = nv50_ram_get; |
575 | ram->put = nv50_ram_put; | |
576 | return 0; | |
577 | } | |
578 | ||
75faef78 | 579 | static int |
639c308e BS |
580 | nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, |
581 | struct nvkm_oclass *oclass, void *data, u32 datasize, | |
582 | struct nvkm_object **pobject) | |
75faef78 BS |
583 | { |
584 | struct nv50_ram *ram; | |
aae95ca7 | 585 | int ret, i; |
75faef78 BS |
586 | |
587 | ret = nv50_ram_create(parent, engine, oclass, &ram); | |
588 | *pobject = nv_object(ram); | |
589 | if (ret) | |
590 | return ret; | |
591 | ||
aae95ca7 | 592 | switch (ram->base.type) { |
aae95ca7 BS |
593 | case NV_MEM_TYPE_GDDR3: |
594 | ram->base.calc = nv50_ram_calc; | |
595 | ram->base.prog = nv50_ram_prog; | |
596 | ram->base.tidy = nv50_ram_tidy; | |
597 | break; | |
82a74fd2 | 598 | case NV_MEM_TYPE_DDR2: |
aae95ca7 BS |
599 | default: |
600 | nv_warn(ram, "reclocking of this ram type unsupported\n"); | |
601 | return 0; | |
602 | } | |
603 | ||
604 | ram->hwsq.r_0x002504 = hwsq_reg(0x002504); | |
605 | ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040); | |
606 | ram->hwsq.r_0x004008 = hwsq_reg(0x004008); | |
607 | ram->hwsq.r_0x00400c = hwsq_reg(0x00400c); | |
82a74fd2 | 608 | ram->hwsq.r_0x100200 = hwsq_reg(0x100200); |
aae95ca7 | 609 | ram->hwsq.r_0x100210 = hwsq_reg(0x100210); |
82a74fd2 | 610 | ram->hwsq.r_0x10021c = hwsq_reg(0x10021c); |
aae95ca7 BS |
611 | ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0); |
612 | ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4); | |
613 | ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc); | |
82a74fd2 RS |
614 | ram->hwsq.r_0x10053c = hwsq_reg(0x10053c); |
615 | ram->hwsq.r_0x1005a0 = hwsq_reg(0x1005a0); | |
616 | ram->hwsq.r_0x1005a4 = hwsq_reg(0x1005a4); | |
617 | ram->hwsq.r_0x100710 = hwsq_reg(0x100710); | |
618 | ram->hwsq.r_0x100714 = hwsq_reg(0x100714); | |
619 | ram->hwsq.r_0x100718 = hwsq_reg(0x100718); | |
620 | ram->hwsq.r_0x10071c = hwsq_reg(0x10071c); | |
d4cc5f0c | 621 | ram->hwsq.r_0x100da0 = hwsq_stride(0x100da0, 4, ram->base.part_mask); |
aae95ca7 BS |
622 | ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20); |
623 | ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24); | |
624 | ram->hwsq.r_0x611200 = hwsq_reg(0x611200); | |
625 | ||
626 | for (i = 0; i < 9; i++) | |
627 | ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04)); | |
628 | ||
629 | if (ram->base.ranks > 1) { | |
630 | ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8); | |
631 | ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc); | |
632 | ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8); | |
633 | ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec); | |
634 | } else { | |
635 | ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0); | |
636 | ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4); | |
637 | ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0); | |
638 | ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4); | |
639 | } | |
640 | ||
75faef78 BS |
641 | return 0; |
642 | } | |
643 | ||
639c308e | 644 | struct nvkm_oclass |
dceef5d8 | 645 | nv50_ram_oclass = { |
639c308e | 646 | .ofuncs = &(struct nvkm_ofuncs) { |
75faef78 | 647 | .ctor = nv50_ram_ctor, |
639c308e BS |
648 | .dtor = _nvkm_ram_dtor, |
649 | .init = _nvkm_ram_init, | |
650 | .fini = _nvkm_ram_fini, | |
dceef5d8 BS |
651 | } |
652 | }; |