1 | /* $NetBSD: nouveau_subdev_fb_ramnvc0.c,v 1.1.1.1 2014/08/06 12:36:30 riastradh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright 2013 Red Hat Inc. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the "Software"), |
8 | * to deal in the Software without restriction, including without limitation |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | * and/or sell copies of the Software, and to permit persons to whom the |
11 | * Software is furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
22 | * OTHER DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: Ben Skeggs |
25 | */ |
26 | |
27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: nouveau_subdev_fb_ramnvc0.c,v 1.1.1.1 2014/08/06 12:36:30 riastradh Exp $" ); |
29 | |
30 | #include <subdev/bios.h> |
31 | #include <subdev/bios/pll.h> |
32 | #include <subdev/bios/rammap.h> |
33 | #include <subdev/bios/timing.h> |
34 | #include <subdev/ltcg.h> |
35 | |
36 | #include <subdev/clock.h> |
37 | #include <subdev/clock/pll.h> |
38 | |
39 | #include <core/option.h> |
40 | |
41 | #include "ramfuc.h" |
42 | |
43 | #include "nvc0.h" |
44 | |
45 | struct nvc0_ramfuc { |
46 | struct ramfuc base; |
47 | |
48 | struct ramfuc_reg r_0x10fe20; |
49 | struct ramfuc_reg r_0x10fe24; |
50 | struct ramfuc_reg r_0x137320; |
51 | struct ramfuc_reg r_0x137330; |
52 | |
53 | struct ramfuc_reg r_0x132000; |
54 | struct ramfuc_reg r_0x132004; |
55 | struct ramfuc_reg r_0x132100; |
56 | |
57 | struct ramfuc_reg r_0x137390; |
58 | |
59 | struct ramfuc_reg r_0x10f290; |
60 | struct ramfuc_reg r_0x10f294; |
61 | struct ramfuc_reg r_0x10f298; |
62 | struct ramfuc_reg r_0x10f29c; |
63 | struct ramfuc_reg r_0x10f2a0; |
64 | |
65 | struct ramfuc_reg r_0x10f300; |
66 | struct ramfuc_reg r_0x10f338; |
67 | struct ramfuc_reg r_0x10f340; |
68 | struct ramfuc_reg r_0x10f344; |
69 | struct ramfuc_reg r_0x10f348; |
70 | |
71 | struct ramfuc_reg r_0x10f910; |
72 | struct ramfuc_reg r_0x10f914; |
73 | |
74 | struct ramfuc_reg r_0x100b0c; |
75 | struct ramfuc_reg r_0x10f050; |
76 | struct ramfuc_reg r_0x10f090; |
77 | struct ramfuc_reg r_0x10f200; |
78 | struct ramfuc_reg r_0x10f210; |
79 | struct ramfuc_reg r_0x10f310; |
80 | struct ramfuc_reg r_0x10f314; |
81 | struct ramfuc_reg r_0x10f610; |
82 | struct ramfuc_reg r_0x10f614; |
83 | struct ramfuc_reg r_0x10f800; |
84 | struct ramfuc_reg r_0x10f808; |
85 | struct ramfuc_reg r_0x10f824; |
86 | struct ramfuc_reg r_0x10f830; |
87 | struct ramfuc_reg r_0x10f988; |
88 | struct ramfuc_reg r_0x10f98c; |
89 | struct ramfuc_reg r_0x10f990; |
90 | struct ramfuc_reg r_0x10f998; |
91 | struct ramfuc_reg r_0x10f9b0; |
92 | struct ramfuc_reg r_0x10f9b4; |
93 | struct ramfuc_reg r_0x10fb04; |
94 | struct ramfuc_reg r_0x10fb08; |
95 | struct ramfuc_reg r_0x137300; |
96 | struct ramfuc_reg r_0x137310; |
97 | struct ramfuc_reg r_0x137360; |
98 | struct ramfuc_reg r_0x1373ec; |
99 | struct ramfuc_reg r_0x1373f0; |
100 | struct ramfuc_reg r_0x1373f8; |
101 | |
102 | struct ramfuc_reg r_0x61c140; |
103 | struct ramfuc_reg r_0x611200; |
104 | |
105 | struct ramfuc_reg r_0x13d8f4; |
106 | }; |
107 | |
108 | struct nvc0_ram { |
109 | struct nouveau_ram base; |
110 | struct nvc0_ramfuc fuc; |
111 | struct nvbios_pll refpll; |
112 | struct nvbios_pll mempll; |
113 | }; |
114 | |
115 | static void |
116 | nvc0_ram_train(struct nvc0_ramfuc *fuc, u32 magic) |
117 | { |
118 | struct nvc0_ram *ram = container_of(fuc, typeof(*ram), fuc); |
119 | struct nouveau_fb *pfb = nouveau_fb(ram); |
120 | u32 part = nv_rd32(pfb, 0x022438), i; |
121 | u32 mask = nv_rd32(pfb, 0x022554); |
122 | u32 addr = 0x110974; |
123 | |
124 | ram_wr32(fuc, 0x10f910, magic); |
125 | ram_wr32(fuc, 0x10f914, magic); |
126 | |
127 | for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) { |
128 | if (mask & (1 << i)) |
129 | continue; |
130 | ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000); |
131 | } |
132 | } |
133 | |
134 | static int |
135 | nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq) |
136 | { |
137 | struct nouveau_clock *clk = nouveau_clock(pfb); |
138 | struct nouveau_bios *bios = nouveau_bios(pfb); |
139 | struct nvc0_ram *ram = (void *)pfb->ram; |
140 | struct nvc0_ramfuc *fuc = &ram->fuc; |
141 | u8 ver, cnt, len, strap; |
142 | struct { |
143 | u32 data; |
144 | u8 size; |
145 | } rammap, ramcfg, timing; |
146 | int ref, div, out; |
147 | int from, mode; |
148 | int N1, M1, P; |
149 | int ret; |
150 | |
151 | /* lookup memory config data relevant to the target frequency */ |
152 | rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, |
153 | &cnt, &ramcfg.size); |
154 | if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { |
155 | nv_error(pfb, "invalid/missing rammap entry\n" ); |
156 | return -EINVAL; |
157 | } |
158 | |
159 | /* locate specific data set for the attached memory */ |
160 | strap = nvbios_ramcfg_index(nv_subdev(pfb)); |
161 | if (strap >= cnt) { |
162 | nv_error(pfb, "invalid ramcfg strap\n" ); |
163 | return -EINVAL; |
164 | } |
165 | |
166 | ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); |
167 | if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { |
168 | nv_error(pfb, "invalid/missing ramcfg entry\n" ); |
169 | return -EINVAL; |
170 | } |
171 | |
172 | /* lookup memory timings, if bios says they're present */ |
173 | strap = nv_ro08(bios, ramcfg.data + 0x01); |
174 | if (strap != 0xff) { |
175 | timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, |
176 | &cnt, &len); |
177 | if (!timing.data || ver != 0x10 || timing.size < 0x19) { |
178 | nv_error(pfb, "invalid/missing timing entry\n" ); |
179 | return -EINVAL; |
180 | } |
181 | } else { |
182 | timing.data = 0; |
183 | } |
184 | |
185 | ret = ram_init(fuc, pfb); |
186 | if (ret) |
187 | return ret; |
188 | |
189 | /* determine current mclk configuration */ |
190 | from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */ |
191 | |
192 | /* determine target mclk configuration */ |
193 | if (!(ram_rd32(fuc, 0x137300) & 0x00000100)) |
194 | ref = clk->read(clk, nv_clk_src_sppll0); |
195 | else |
196 | ref = clk->read(clk, nv_clk_src_sppll1); |
197 | div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2; |
198 | out = (ref * 2) / (div + 2); |
199 | mode = freq != out; |
200 | |
201 | ram_mask(fuc, 0x137360, 0x00000002, 0x00000000); |
202 | |
203 | if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) { |
204 | ram_nuke(fuc, 0x132000); |
205 | ram_mask(fuc, 0x132000, 0x00000002, 0x00000002); |
206 | ram_mask(fuc, 0x132000, 0x00000002, 0x00000000); |
207 | } |
208 | |
209 | if (mode == 1) { |
210 | ram_nuke(fuc, 0x10fe20); |
211 | ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002); |
212 | ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000); |
213 | } |
214 | |
215 | // 0x00020034 // 0x0000000a |
216 | ram_wr32(fuc, 0x132100, 0x00000001); |
217 | |
218 | if (mode == 1 && from == 0) { |
219 | /* calculate refpll */ |
220 | ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll, |
221 | ram->mempll.refclk, &N1, NULL, &M1, &P); |
222 | if (ret <= 0) { |
223 | nv_error(pfb, "unable to calc refpll\n" ); |
224 | return ret ? ret : -ERANGE; |
225 | } |
226 | |
227 | ram_wr32(fuc, 0x10fe20, 0x20010000); |
228 | ram_wr32(fuc, 0x137320, 0x00000003); |
229 | ram_wr32(fuc, 0x137330, 0x81200006); |
230 | ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1); |
231 | ram_wr32(fuc, 0x10fe20, 0x20010001); |
232 | ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); |
233 | |
234 | /* calculate mempll */ |
235 | ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq, |
236 | &N1, NULL, &M1, &P); |
237 | if (ret <= 0) { |
238 | nv_error(pfb, "unable to calc refpll\n" ); |
239 | return ret ? ret : -ERANGE; |
240 | } |
241 | |
242 | ram_wr32(fuc, 0x10fe20, 0x20010005); |
243 | ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1); |
244 | ram_wr32(fuc, 0x132000, 0x18010101); |
245 | ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000); |
246 | } else |
247 | if (mode == 0) { |
248 | ram_wr32(fuc, 0x137300, 0x00000003); |
249 | } |
250 | |
251 | if (from == 0) { |
252 | ram_nuke(fuc, 0x10fb04); |
253 | ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000); |
254 | ram_nuke(fuc, 0x10fb08); |
255 | ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000); |
256 | ram_wr32(fuc, 0x10f988, 0x2004ff00); |
257 | ram_wr32(fuc, 0x10f98c, 0x003fc040); |
258 | ram_wr32(fuc, 0x10f990, 0x20012001); |
259 | ram_wr32(fuc, 0x10f998, 0x00011a00); |
260 | ram_wr32(fuc, 0x13d8f4, 0x00000000); |
261 | } else { |
262 | ram_wr32(fuc, 0x10f988, 0x20010000); |
263 | ram_wr32(fuc, 0x10f98c, 0x00000000); |
264 | ram_wr32(fuc, 0x10f990, 0x20012001); |
265 | ram_wr32(fuc, 0x10f998, 0x00010a00); |
266 | } |
267 | |
268 | if (from == 0) { |
269 | // 0x00020039 // 0x000000ba |
270 | } |
271 | |
272 | // 0x0002003a // 0x00000002 |
273 | ram_wr32(fuc, 0x100b0c, 0x00080012); |
274 | // 0x00030014 // 0x00000000 // 0x02b5f070 |
275 | // 0x00030014 // 0x00010000 // 0x02b5f070 |
276 | ram_wr32(fuc, 0x611200, 0x00003300); |
277 | // 0x00020034 // 0x0000000a |
278 | // 0x00030020 // 0x00000001 // 0x00000000 |
279 | |
280 | ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000); |
281 | ram_wr32(fuc, 0x10f210, 0x00000000); |
282 | ram_nsec(fuc, 1000); |
283 | if (mode == 0) |
284 | nvc0_ram_train(fuc, 0x000c1001); |
285 | ram_wr32(fuc, 0x10f310, 0x00000001); |
286 | ram_nsec(fuc, 1000); |
287 | ram_wr32(fuc, 0x10f090, 0x00000061); |
288 | ram_wr32(fuc, 0x10f090, 0xc000007f); |
289 | ram_nsec(fuc, 1000); |
290 | |
291 | if (from == 0) { |
292 | ram_wr32(fuc, 0x10f824, 0x00007fd4); |
293 | } else { |
294 | ram_wr32(fuc, 0x1373ec, 0x00020404); |
295 | } |
296 | |
297 | if (mode == 0) { |
298 | ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000); |
299 | ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000); |
300 | ram_wr32(fuc, 0x10f830, 0x41500010); |
301 | ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000); |
302 | ram_mask(fuc, 0x132100, 0x00000100, 0x00000100); |
303 | ram_wr32(fuc, 0x10f050, 0xff000090); |
304 | ram_wr32(fuc, 0x1373ec, 0x00020f0f); |
305 | ram_wr32(fuc, 0x1373f0, 0x00000003); |
306 | ram_wr32(fuc, 0x137310, 0x81201616); |
307 | ram_wr32(fuc, 0x132100, 0x00000001); |
308 | // 0x00020039 // 0x000000ba |
309 | ram_wr32(fuc, 0x10f830, 0x00300017); |
310 | ram_wr32(fuc, 0x1373f0, 0x00000001); |
311 | ram_wr32(fuc, 0x10f824, 0x00007e77); |
312 | ram_wr32(fuc, 0x132000, 0x18030001); |
313 | ram_wr32(fuc, 0x10f090, 0x4000007e); |
314 | ram_nsec(fuc, 2000); |
315 | ram_wr32(fuc, 0x10f314, 0x00000001); |
316 | ram_wr32(fuc, 0x10f210, 0x80000000); |
317 | ram_wr32(fuc, 0x10f338, 0x00300220); |
318 | ram_wr32(fuc, 0x10f300, 0x0000011d); |
319 | ram_nsec(fuc, 1000); |
320 | ram_wr32(fuc, 0x10f290, 0x02060505); |
321 | ram_wr32(fuc, 0x10f294, 0x34208288); |
322 | ram_wr32(fuc, 0x10f298, 0x44050411); |
323 | ram_wr32(fuc, 0x10f29c, 0x0000114c); |
324 | ram_wr32(fuc, 0x10f2a0, 0x42e10069); |
325 | ram_wr32(fuc, 0x10f614, 0x40044f77); |
326 | ram_wr32(fuc, 0x10f610, 0x40044f77); |
327 | ram_wr32(fuc, 0x10f344, 0x00600009); |
328 | ram_nsec(fuc, 1000); |
329 | ram_wr32(fuc, 0x10f348, 0x00700008); |
330 | ram_wr32(fuc, 0x61c140, 0x19240000); |
331 | ram_wr32(fuc, 0x10f830, 0x00300017); |
332 | nvc0_ram_train(fuc, 0x80021001); |
333 | nvc0_ram_train(fuc, 0x80081001); |
334 | ram_wr32(fuc, 0x10f340, 0x00500004); |
335 | ram_nsec(fuc, 1000); |
336 | ram_wr32(fuc, 0x10f830, 0x01300017); |
337 | ram_wr32(fuc, 0x10f830, 0x00300017); |
338 | // 0x00030020 // 0x00000000 // 0x00000000 |
339 | // 0x00020034 // 0x0000000b |
340 | ram_wr32(fuc, 0x100b0c, 0x00080028); |
341 | ram_wr32(fuc, 0x611200, 0x00003330); |
342 | } else { |
343 | ram_wr32(fuc, 0x10f800, 0x00001800); |
344 | ram_wr32(fuc, 0x13d8f4, 0x00000000); |
345 | ram_wr32(fuc, 0x1373ec, 0x00020404); |
346 | ram_wr32(fuc, 0x1373f0, 0x00000003); |
347 | ram_wr32(fuc, 0x10f830, 0x40700010); |
348 | ram_wr32(fuc, 0x10f830, 0x40500010); |
349 | ram_wr32(fuc, 0x13d8f4, 0x00000000); |
350 | ram_wr32(fuc, 0x1373f8, 0x00000000); |
351 | ram_wr32(fuc, 0x132100, 0x00000101); |
352 | ram_wr32(fuc, 0x137310, 0x89201616); |
353 | ram_wr32(fuc, 0x10f050, 0xff000090); |
354 | ram_wr32(fuc, 0x1373ec, 0x00030404); |
355 | ram_wr32(fuc, 0x1373f0, 0x00000002); |
356 | // 0x00020039 // 0x00000011 |
357 | ram_wr32(fuc, 0x132100, 0x00000001); |
358 | ram_wr32(fuc, 0x1373f8, 0x00002000); |
359 | ram_nsec(fuc, 2000); |
360 | ram_wr32(fuc, 0x10f808, 0x7aaa0050); |
361 | ram_wr32(fuc, 0x10f830, 0x00500010); |
362 | ram_wr32(fuc, 0x10f200, 0x00ce1000); |
363 | ram_wr32(fuc, 0x10f090, 0x4000007e); |
364 | ram_nsec(fuc, 2000); |
365 | ram_wr32(fuc, 0x10f314, 0x00000001); |
366 | ram_wr32(fuc, 0x10f210, 0x80000000); |
367 | ram_wr32(fuc, 0x10f338, 0x00300200); |
368 | ram_wr32(fuc, 0x10f300, 0x0000084d); |
369 | ram_nsec(fuc, 1000); |
370 | ram_wr32(fuc, 0x10f290, 0x0b343825); |
371 | ram_wr32(fuc, 0x10f294, 0x3483028e); |
372 | ram_wr32(fuc, 0x10f298, 0x440c0600); |
373 | ram_wr32(fuc, 0x10f29c, 0x0000214c); |
374 | ram_wr32(fuc, 0x10f2a0, 0x42e20069); |
375 | ram_wr32(fuc, 0x10f200, 0x00ce0000); |
376 | ram_wr32(fuc, 0x10f614, 0x60044e77); |
377 | ram_wr32(fuc, 0x10f610, 0x60044e77); |
378 | ram_wr32(fuc, 0x10f340, 0x00500000); |
379 | ram_nsec(fuc, 1000); |
380 | ram_wr32(fuc, 0x10f344, 0x00600228); |
381 | ram_nsec(fuc, 1000); |
382 | ram_wr32(fuc, 0x10f348, 0x00700000); |
383 | ram_wr32(fuc, 0x13d8f4, 0x00000000); |
384 | ram_wr32(fuc, 0x61c140, 0x09a40000); |
385 | |
386 | nvc0_ram_train(fuc, 0x800e1008); |
387 | |
388 | ram_nsec(fuc, 1000); |
389 | ram_wr32(fuc, 0x10f800, 0x00001804); |
390 | // 0x00030020 // 0x00000000 // 0x00000000 |
391 | // 0x00020034 // 0x0000000b |
392 | ram_wr32(fuc, 0x13d8f4, 0x00000000); |
393 | ram_wr32(fuc, 0x100b0c, 0x00080028); |
394 | ram_wr32(fuc, 0x611200, 0x00003330); |
395 | ram_nsec(fuc, 100000); |
396 | ram_wr32(fuc, 0x10f9b0, 0x05313f41); |
397 | ram_wr32(fuc, 0x10f9b4, 0x00002f50); |
398 | |
399 | nvc0_ram_train(fuc, 0x010c1001); |
400 | } |
401 | |
402 | ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800); |
403 | // 0x00020016 // 0x00000000 |
404 | |
405 | if (mode == 0) |
406 | ram_mask(fuc, 0x132000, 0x00000001, 0x00000000); |
407 | return 0; |
408 | } |
409 | |
410 | static int |
411 | nvc0_ram_prog(struct nouveau_fb *pfb) |
412 | { |
413 | struct nouveau_device *device = nv_device(pfb); |
414 | struct nvc0_ram *ram = (void *)pfb->ram; |
415 | struct nvc0_ramfuc *fuc = &ram->fuc; |
416 | ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec" , false)); |
417 | return 0; |
418 | } |
419 | |
420 | static void |
421 | nvc0_ram_tidy(struct nouveau_fb *pfb) |
422 | { |
423 | struct nvc0_ram *ram = (void *)pfb->ram; |
424 | struct nvc0_ramfuc *fuc = &ram->fuc; |
425 | ram_exec(fuc, false); |
426 | } |
427 | |
428 | extern const u8 nvc0_pte_storage_type_map[256]; |
429 | |
430 | void |
431 | nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) |
432 | { |
433 | struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); |
434 | struct nouveau_mem *mem = *pmem; |
435 | |
436 | *pmem = NULL; |
437 | if (unlikely(mem == NULL)) |
438 | return; |
439 | |
440 | mutex_lock(&pfb->base.mutex); |
441 | if (mem->tag) |
442 | ltcg->tags_free(ltcg, &mem->tag); |
443 | __nv50_ram_put(pfb, mem); |
444 | mutex_unlock(&pfb->base.mutex); |
445 | |
446 | kfree(mem); |
447 | } |
448 | |
449 | int |
450 | nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, |
451 | u32 memtype, struct nouveau_mem **pmem) |
452 | { |
453 | struct nouveau_mm *mm = &pfb->vram; |
454 | struct nouveau_mm_node *r; |
455 | struct nouveau_mem *mem; |
456 | int type = (memtype & 0x0ff); |
457 | int back = (memtype & 0x800); |
458 | const bool comp = nvc0_pte_storage_type_map[type] != type; |
459 | int ret; |
460 | |
461 | size >>= 12; |
462 | align >>= 12; |
463 | ncmin >>= 12; |
464 | if (!ncmin) |
465 | ncmin = size; |
466 | |
467 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); |
468 | if (!mem) |
469 | return -ENOMEM; |
470 | |
471 | INIT_LIST_HEAD(&mem->regions); |
472 | mem->size = size; |
473 | |
474 | mutex_lock(&pfb->base.mutex); |
475 | if (comp) { |
476 | struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); |
477 | |
478 | /* compression only works with lpages */ |
479 | if (align == (1 << (17 - 12))) { |
480 | int n = size >> 5; |
481 | ltcg->tags_alloc(ltcg, n, &mem->tag); |
482 | } |
483 | |
484 | if (unlikely(!mem->tag)) |
485 | type = nvc0_pte_storage_type_map[type]; |
486 | } |
487 | mem->memtype = type; |
488 | |
489 | do { |
490 | if (back) |
491 | ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); |
492 | else |
493 | ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); |
494 | if (ret) { |
495 | mutex_unlock(&pfb->base.mutex); |
496 | pfb->ram->put(pfb, &mem); |
497 | return ret; |
498 | } |
499 | |
500 | list_add_tail(&r->rl_entry, &mem->regions); |
501 | size -= r->length; |
502 | } while (size); |
503 | mutex_unlock(&pfb->base.mutex); |
504 | |
505 | r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); |
506 | mem->offset = (u64)r->offset << 12; |
507 | *pmem = mem; |
508 | return 0; |
509 | } |
510 | |
511 | int |
512 | nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, |
513 | struct nouveau_oclass *oclass, u32 maskaddr, int size, |
514 | void **pobject) |
515 | { |
516 | struct nouveau_fb *pfb = nouveau_fb(parent); |
517 | struct nouveau_bios *bios = nouveau_bios(pfb); |
518 | struct nouveau_ram *ram; |
519 | const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ |
520 | const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ |
521 | u32 parts = nv_rd32(pfb, 0x022438); |
522 | u32 pmask = nv_rd32(pfb, maskaddr); |
523 | u32 bsize = nv_rd32(pfb, 0x10f20c); |
524 | u32 offset, length; |
525 | bool uniform = true; |
526 | int ret, part; |
527 | |
528 | ret = nouveau_ram_create_(parent, engine, oclass, size, pobject); |
529 | ram = *pobject; |
530 | if (ret) |
531 | return ret; |
532 | |
533 | nv_debug(pfb, "0x100800: 0x%08x\n" , nv_rd32(pfb, 0x100800)); |
534 | nv_debug(pfb, "parts 0x%08x mask 0x%08x\n" , parts, pmask); |
535 | |
536 | ram->type = nouveau_fb_bios_memtype(bios); |
537 | ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1; |
538 | |
539 | /* read amount of vram attached to each memory controller */ |
540 | for (part = 0; part < parts; part++) { |
541 | if (!(pmask & (1 << part))) { |
542 | u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000)); |
543 | if (psize != bsize) { |
544 | if (psize < bsize) |
545 | bsize = psize; |
546 | uniform = false; |
547 | } |
548 | |
549 | nv_debug(pfb, "%d: mem_amount 0x%08x\n" , part, psize); |
550 | ram->size += (u64)psize << 20; |
551 | } |
552 | } |
553 | |
554 | /* if all controllers have the same amount attached, there's no holes */ |
555 | if (uniform) { |
556 | offset = rsvd_head; |
557 | length = (ram->size >> 12) - rsvd_head - rsvd_tail; |
558 | ret = nouveau_mm_init(&pfb->vram, offset, length, 1); |
559 | } else { |
560 | /* otherwise, address lowest common amount from 0GiB */ |
561 | ret = nouveau_mm_init(&pfb->vram, rsvd_head, |
562 | (bsize << 8) * parts, 1); |
563 | if (ret) |
564 | return ret; |
565 | |
566 | /* and the rest starting from (8GiB + common_size) */ |
567 | offset = (0x0200000000ULL >> 12) + (bsize << 8); |
568 | length = (ram->size >> 12) - (bsize << 8) - rsvd_tail; |
569 | |
570 | ret = nouveau_mm_init(&pfb->vram, offset, length, 0); |
571 | if (ret) |
572 | nouveau_mm_fini(&pfb->vram); |
573 | } |
574 | |
575 | if (ret) |
576 | return ret; |
577 | |
578 | ram->get = nvc0_ram_get; |
579 | ram->put = nvc0_ram_put; |
580 | return 0; |
581 | } |
582 | |
583 | static int |
584 | nvc0_ram_init(struct nouveau_object *object) |
585 | { |
586 | struct nouveau_fb *pfb = (void *)object->parent; |
587 | struct nvc0_ram *ram = (void *)object; |
588 | int ret, i; |
589 | |
590 | ret = nouveau_ram_init(&ram->base); |
591 | if (ret) |
592 | return ret; |
593 | |
594 | /* prepare for ddr link training, and load training patterns */ |
595 | switch (ram->base.type) { |
596 | case NV_MEM_TYPE_GDDR5: { |
597 | static const u8 train0[] = { |
598 | 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, |
599 | 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, |
600 | }; |
601 | static const u32 train1[] = { |
602 | 0x00000000, 0xffffffff, |
603 | 0x55555555, 0xaaaaaaaa, |
604 | 0x33333333, 0xcccccccc, |
605 | 0xf0f0f0f0, 0x0f0f0f0f, |
606 | 0x00ff00ff, 0xff00ff00, |
607 | 0x0000ffff, 0xffff0000, |
608 | }; |
609 | |
610 | for (i = 0; i < 0x30; i++) { |
611 | nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8)); |
612 | nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8)); |
613 | nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]); |
614 | nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]); |
615 | nv_wr32(pfb, 0x10f918, train1[i % 12]); |
616 | nv_wr32(pfb, 0x10f91c, train1[i % 12]); |
617 | nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]); |
618 | nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]); |
619 | nv_wr32(pfb, 0x10f918, train1[i % 12]); |
620 | nv_wr32(pfb, 0x10f91c, train1[i % 12]); |
621 | } |
622 | } break; |
623 | default: |
624 | break; |
625 | } |
626 | |
627 | return 0; |
628 | } |
629 | |
630 | static int |
631 | nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
632 | struct nouveau_oclass *oclass, void *data, u32 size, |
633 | struct nouveau_object **pobject) |
634 | { |
635 | struct nouveau_bios *bios = nouveau_bios(parent); |
636 | struct nvc0_ram *ram; |
637 | int ret; |
638 | |
639 | ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); |
640 | *pobject = nv_object(ram); |
641 | if (ret) |
642 | return ret; |
643 | |
644 | ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll); |
645 | if (ret) { |
646 | nv_error(ram, "mclk refpll data not found\n" ); |
647 | return ret; |
648 | } |
649 | |
650 | ret = nvbios_pll_parse(bios, 0x04, &ram->mempll); |
651 | if (ret) { |
652 | nv_error(ram, "mclk pll data not found\n" ); |
653 | return ret; |
654 | } |
655 | |
656 | switch (ram->base.type) { |
657 | case NV_MEM_TYPE_GDDR5: |
658 | ram->base.calc = nvc0_ram_calc; |
659 | ram->base.prog = nvc0_ram_prog; |
660 | ram->base.tidy = nvc0_ram_tidy; |
661 | break; |
662 | default: |
663 | nv_warn(ram, "reclocking of this ram type unsupported\n" ); |
664 | return 0; |
665 | } |
666 | |
667 | ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20); |
668 | ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24); |
669 | ram->fuc.r_0x137320 = ramfuc_reg(0x137320); |
670 | ram->fuc.r_0x137330 = ramfuc_reg(0x137330); |
671 | |
672 | ram->fuc.r_0x132000 = ramfuc_reg(0x132000); |
673 | ram->fuc.r_0x132004 = ramfuc_reg(0x132004); |
674 | ram->fuc.r_0x132100 = ramfuc_reg(0x132100); |
675 | |
676 | ram->fuc.r_0x137390 = ramfuc_reg(0x137390); |
677 | |
678 | ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290); |
679 | ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294); |
680 | ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298); |
681 | ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c); |
682 | ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0); |
683 | |
684 | ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300); |
685 | ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338); |
686 | ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340); |
687 | ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344); |
688 | ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348); |
689 | |
690 | ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910); |
691 | ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); |
692 | |
693 | ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c); |
694 | ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050); |
695 | ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090); |
696 | ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200); |
697 | ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210); |
698 | ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310); |
699 | ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314); |
700 | ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610); |
701 | ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614); |
702 | ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800); |
703 | ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808); |
704 | ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824); |
705 | ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830); |
706 | ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988); |
707 | ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c); |
708 | ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990); |
709 | ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998); |
710 | ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0); |
711 | ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4); |
712 | ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04); |
713 | ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08); |
714 | ram->fuc.r_0x137310 = ramfuc_reg(0x137300); |
715 | ram->fuc.r_0x137310 = ramfuc_reg(0x137310); |
716 | ram->fuc.r_0x137360 = ramfuc_reg(0x137360); |
717 | ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec); |
718 | ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0); |
719 | ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8); |
720 | |
721 | ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140); |
722 | ram->fuc.r_0x611200 = ramfuc_reg(0x611200); |
723 | |
724 | ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4); |
725 | return 0; |
726 | } |
727 | |
728 | struct nouveau_oclass |
729 | nvc0_ram_oclass = { |
730 | .handle = 0, |
731 | .ofuncs = &(struct nouveau_ofuncs) { |
732 | .ctor = nvc0_ram_ctor, |
733 | .dtor = _nouveau_ram_dtor, |
734 | .init = nvc0_ram_init, |
735 | .fini = _nouveau_ram_fini, |
736 | } |
737 | }; |
738 | |