]>
Commit | Line | Data |
---|---|---|
6ee73861 BS |
1 | /* |
2 | * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. | |
3 | * Copyright 2005 Stephane Marchesin | |
4 | * | |
5 | * The Weather Channel (TM) funded Tungsten Graphics to develop the | |
6 | * initial release of the Radeon 8500 driver under the XFree86 license. | |
7 | * This notice must be preserved. | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice (including the next | |
17 | * paragraph) shall be included in all copies or substantial portions of the | |
18 | * Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
23 | * THE AUTHORS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
24 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
26 | * DEALINGS IN THE SOFTWARE. | |
27 | * | |
28 | * Authors: | |
29 | * Keith Whitwell <keith@tungstengraphics.com> | |
30 | */ | |
31 | ||
32 | ||
33 | #include "drmP.h" | |
34 | #include "drm.h" | |
35 | #include "drm_sarea.h" | |
6ee73861 | 36 | |
cbab95db FJ |
37 | #include "nouveau_drv.h" |
38 | #include "nouveau_pm.h" | |
573a2a37 | 39 | #include "nouveau_mm.h" |
a11c3198 | 40 | #include "nouveau_vm.h" |
a845fff8 | 41 | |
a0af9add FJ |
42 | /* |
43 | * NV10-NV40 tiling helpers | |
44 | */ | |
45 | ||
46 | static void | |
a5cf68b0 FJ |
47 | nv10_mem_update_tile_region(struct drm_device *dev, |
48 | struct nouveau_tile_reg *tile, uint32_t addr, | |
49 | uint32_t size, uint32_t pitch, uint32_t flags) | |
a0af9add FJ |
50 | { |
51 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
52 | struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; | |
53 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | |
96c50082 | 54 | int i = tile - dev_priv->tile.reg, j; |
a5cf68b0 | 55 | unsigned long save; |
a0af9add | 56 | |
382d62e5 | 57 | nouveau_fence_unref(&tile->fence); |
a0af9add | 58 | |
a5cf68b0 FJ |
59 | if (tile->pitch) |
60 | pfb->free_tile_region(dev, i); | |
61 | ||
62 | if (pitch) | |
63 | pfb->init_tile_region(dev, i, addr, size, pitch, flags); | |
64 | ||
65 | spin_lock_irqsave(&dev_priv->context_switch_lock, save); | |
a0af9add | 66 | pfifo->reassign(dev, false); |
a0af9add FJ |
67 | pfifo->cache_pull(dev, false); |
68 | ||
69 | nouveau_wait_for_idle(dev); | |
70 | ||
a5cf68b0 | 71 | pfb->set_tile_region(dev, i); |
96c50082 BS |
72 | for (j = 0; j < NVOBJ_ENGINE_NR; j++) { |
73 | if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region) | |
74 | dev_priv->eng[j]->set_tile_region(dev, i); | |
75 | } | |
a0af9add FJ |
76 | |
77 | pfifo->cache_pull(dev, true); | |
78 | pfifo->reassign(dev, true); | |
a5cf68b0 | 79 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, save); |
a0af9add FJ |
80 | } |
81 | ||
a5cf68b0 FJ |
82 | static struct nouveau_tile_reg * |
83 | nv10_mem_get_tile_region(struct drm_device *dev, int i) | |
a0af9add FJ |
84 | { |
85 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
a5cf68b0 | 86 | struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; |
a0af9add | 87 | |
a5cf68b0 | 88 | spin_lock(&dev_priv->tile.lock); |
a0af9add | 89 | |
a5cf68b0 FJ |
90 | if (!tile->used && |
91 | (!tile->fence || nouveau_fence_signalled(tile->fence))) | |
92 | tile->used = true; | |
93 | else | |
94 | tile = NULL; | |
a0af9add | 95 | |
a5cf68b0 FJ |
96 | spin_unlock(&dev_priv->tile.lock); |
97 | return tile; | |
98 | } | |
a0af9add | 99 | |
a5cf68b0 FJ |
100 | void |
101 | nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile, | |
102 | struct nouveau_fence *fence) | |
103 | { | |
104 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
a0af9add | 105 | |
a5cf68b0 FJ |
106 | if (tile) { |
107 | spin_lock(&dev_priv->tile.lock); | |
108 | if (fence) { | |
109 | /* Mark it as pending. */ | |
110 | tile->fence = fence; | |
111 | nouveau_fence_ref(fence); | |
a0af9add | 112 | } |
a0af9add | 113 | |
a5cf68b0 FJ |
114 | tile->used = false; |
115 | spin_unlock(&dev_priv->tile.lock); | |
116 | } | |
a0af9add FJ |
117 | } |
118 | ||
a5cf68b0 FJ |
119 | struct nouveau_tile_reg * |
120 | nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, | |
121 | uint32_t pitch, uint32_t flags) | |
a0af9add | 122 | { |
a5cf68b0 FJ |
123 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
124 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | |
125 | struct nouveau_tile_reg *tile, *found = NULL; | |
126 | int i; | |
127 | ||
128 | for (i = 0; i < pfb->num_tiles; i++) { | |
129 | tile = nv10_mem_get_tile_region(dev, i); | |
130 | ||
131 | if (pitch && !found) { | |
132 | found = tile; | |
133 | continue; | |
134 | ||
135 | } else if (tile && tile->pitch) { | |
136 | /* Kill an unused tile region. */ | |
137 | nv10_mem_update_tile_region(dev, tile, 0, 0, 0, 0); | |
138 | } | |
139 | ||
140 | nv10_mem_put_tile_region(dev, tile, NULL); | |
a0af9add FJ |
141 | } |
142 | ||
a5cf68b0 FJ |
143 | if (found) |
144 | nv10_mem_update_tile_region(dev, found, addr, size, | |
145 | pitch, flags); | |
146 | return found; | |
a0af9add FJ |
147 | } |
148 | ||
6ee73861 BS |
149 | /* |
150 | * Cleanup everything | |
151 | */ | |
b833ac26 | 152 | void |
fbd2895e | 153 | nouveau_mem_vram_fini(struct drm_device *dev) |
6ee73861 BS |
154 | { |
155 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
156 | ||
6ee73861 BS |
157 | ttm_bo_device_release(&dev_priv->ttm.bdev); |
158 | ||
159 | nouveau_ttm_global_release(dev_priv); | |
160 | ||
fbd2895e BS |
161 | if (dev_priv->fb_mtrr >= 0) { |
162 | drm_mtrr_del(dev_priv->fb_mtrr, | |
163 | pci_resource_start(dev->pdev, 1), | |
164 | pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); | |
165 | dev_priv->fb_mtrr = -1; | |
166 | } | |
167 | } | |
168 | ||
169 | void | |
170 | nouveau_mem_gart_fini(struct drm_device *dev) | |
171 | { | |
172 | nouveau_sgdma_takedown(dev); | |
173 | ||
cd0b072f | 174 | if (drm_core_has_AGP(dev) && dev->agp) { |
6ee73861 BS |
175 | struct drm_agp_mem *entry, *tempe; |
176 | ||
177 | /* Remove AGP resources, but leave dev->agp | |
178 | intact until drv_cleanup is called. */ | |
179 | list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) { | |
180 | if (entry->bound) | |
181 | drm_unbind_agp(entry->memory); | |
182 | drm_free_agp(entry->memory, entry->pages); | |
183 | kfree(entry); | |
184 | } | |
185 | INIT_LIST_HEAD(&dev->agp->memory); | |
186 | ||
187 | if (dev->agp->acquired) | |
188 | drm_agp_release(dev); | |
189 | ||
190 | dev->agp->acquired = 0; | |
191 | dev->agp->enabled = 0; | |
192 | } | |
6ee73861 BS |
193 | } |
194 | ||
60d2a88a BS |
195 | bool |
196 | nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) | |
197 | { | |
198 | if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) | |
199 | return true; | |
200 | ||
201 | return false; | |
202 | } | |
203 | ||
71d06186 FJ |
204 | #if __OS_HAS_AGP |
205 | static unsigned long | |
206 | get_agp_mode(struct drm_device *dev, unsigned long mode) | |
207 | { | |
208 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
209 | ||
210 | /* | |
211 | * FW seems to be broken on nv18, it makes the card lock up | |
212 | * randomly. | |
213 | */ | |
214 | if (dev_priv->chipset == 0x18) | |
215 | mode &= ~PCI_AGP_COMMAND_FW; | |
216 | ||
de5899bd FJ |
217 | /* |
218 | * AGP mode set in the command line. | |
219 | */ | |
220 | if (nouveau_agpmode > 0) { | |
221 | bool agpv3 = mode & 0x8; | |
222 | int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; | |
223 | ||
224 | mode = (mode & ~0x7) | (rate & 0x7); | |
225 | } | |
226 | ||
71d06186 FJ |
227 | return mode; |
228 | } | |
229 | #endif | |
230 | ||
e04d8e82 FJ |
231 | int |
232 | nouveau_mem_reset_agp(struct drm_device *dev) | |
6ee73861 | 233 | { |
e04d8e82 FJ |
234 | #if __OS_HAS_AGP |
235 | uint32_t saved_pci_nv_1, pmc_enable; | |
236 | int ret; | |
237 | ||
238 | /* First of all, disable fast writes, otherwise if it's | |
239 | * already enabled in the AGP bridge and we disable the card's | |
240 | * AGP controller we might be locking ourselves out of it. */ | |
316f60a1 FJ |
241 | if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) | |
242 | dev->agp->mode) & PCI_AGP_COMMAND_FW) { | |
e04d8e82 FJ |
243 | struct drm_agp_info info; |
244 | struct drm_agp_mode mode; | |
245 | ||
246 | ret = drm_agp_info(dev, &info); | |
247 | if (ret) | |
248 | return ret; | |
249 | ||
71d06186 | 250 | mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW; |
e04d8e82 FJ |
251 | ret = drm_agp_enable(dev, mode); |
252 | if (ret) | |
253 | return ret; | |
254 | } | |
6ee73861 BS |
255 | |
256 | saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1); | |
6ee73861 BS |
257 | |
258 | /* clear busmaster bit */ | |
259 | nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4); | |
e04d8e82 FJ |
260 | /* disable AGP */ |
261 | nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0); | |
6ee73861 BS |
262 | |
263 | /* power cycle pgraph, if enabled */ | |
264 | pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); | |
265 | if (pmc_enable & NV_PMC_ENABLE_PGRAPH) { | |
266 | nv_wr32(dev, NV03_PMC_ENABLE, | |
267 | pmc_enable & ~NV_PMC_ENABLE_PGRAPH); | |
268 | nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | | |
269 | NV_PMC_ENABLE_PGRAPH); | |
270 | } | |
271 | ||
272 | /* and restore (gives effect of resetting AGP) */ | |
6ee73861 | 273 | nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1); |
b694dfb2 | 274 | #endif |
6ee73861 | 275 | |
e04d8e82 FJ |
276 | return 0; |
277 | } | |
278 | ||
6ee73861 BS |
279 | int |
280 | nouveau_mem_init_agp(struct drm_device *dev) | |
281 | { | |
b694dfb2 | 282 | #if __OS_HAS_AGP |
6ee73861 BS |
283 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
284 | struct drm_agp_info info; | |
285 | struct drm_agp_mode mode; | |
286 | int ret; | |
287 | ||
6ee73861 BS |
288 | if (!dev->agp->acquired) { |
289 | ret = drm_agp_acquire(dev); | |
290 | if (ret) { | |
291 | NV_ERROR(dev, "Unable to acquire AGP: %d\n", ret); | |
292 | return ret; | |
293 | } | |
294 | } | |
295 | ||
2b495268 FJ |
296 | nouveau_mem_reset_agp(dev); |
297 | ||
6ee73861 BS |
298 | ret = drm_agp_info(dev, &info); |
299 | if (ret) { | |
300 | NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); | |
301 | return ret; | |
302 | } | |
303 | ||
304 | /* see agp.h for the AGPSTAT_* modes available */ | |
71d06186 | 305 | mode.mode = get_agp_mode(dev, info.mode); |
6ee73861 BS |
306 | ret = drm_agp_enable(dev, mode); |
307 | if (ret) { | |
308 | NV_ERROR(dev, "Unable to enable AGP: %d\n", ret); | |
309 | return ret; | |
310 | } | |
311 | ||
312 | dev_priv->gart_info.type = NOUVEAU_GART_AGP; | |
313 | dev_priv->gart_info.aper_base = info.aperture_base; | |
314 | dev_priv->gart_info.aper_size = info.aperture_size; | |
b694dfb2 | 315 | #endif |
6ee73861 BS |
316 | return 0; |
317 | } | |
318 | ||
7ad2d31c BS |
319 | static const struct vram_types { |
320 | int value; | |
321 | const char *name; | |
322 | } vram_type_map[] = { | |
323 | { NV_MEM_TYPE_STOLEN , "stolen system memory" }, | |
324 | { NV_MEM_TYPE_SGRAM , "SGRAM" }, | |
325 | { NV_MEM_TYPE_SDRAM , "SDRAM" }, | |
326 | { NV_MEM_TYPE_DDR1 , "DDR1" }, | |
327 | { NV_MEM_TYPE_DDR2 , "DDR2" }, | |
328 | { NV_MEM_TYPE_DDR3 , "DDR3" }, | |
329 | { NV_MEM_TYPE_GDDR2 , "GDDR2" }, | |
330 | { NV_MEM_TYPE_GDDR3 , "GDDR3" }, | |
331 | { NV_MEM_TYPE_GDDR4 , "GDDR4" }, | |
332 | { NV_MEM_TYPE_GDDR5 , "GDDR5" }, | |
333 | { NV_MEM_TYPE_UNKNOWN, "unknown type" } | |
334 | }; | |
335 | ||
6ee73861 | 336 | int |
fbd2895e | 337 | nouveau_mem_vram_init(struct drm_device *dev) |
6ee73861 BS |
338 | { |
339 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
340 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | |
7ad2d31c | 341 | const struct vram_types *vram_type; |
fbd2895e | 342 | int ret, dma_bits; |
6ee73861 | 343 | |
e0435120 BS |
344 | dma_bits = 32; |
345 | if (dev_priv->card_type >= NV_50) { | |
346 | if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) | |
347 | dma_bits = 40; | |
348 | } else | |
58b6542b | 349 | if (0 && pci_is_pcie(dev->pdev) && |
01d15332 | 350 | dev_priv->chipset > 0x40 && |
e0435120 BS |
351 | dev_priv->chipset != 0x45) { |
352 | if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) | |
353 | dma_bits = 39; | |
354 | } | |
6ee73861 BS |
355 | |
356 | ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); | |
fbd2895e | 357 | if (ret) |
6ee73861 | 358 | return ret; |
3230cfc3 KRW |
359 | ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); |
360 | if (ret) { | |
361 | /* Reset to default value. */ | |
362 | pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32)); | |
363 | } | |
364 | ||
fbd2895e | 365 | |
6ee73861 BS |
366 | ret = nouveau_ttm_global_init(dev_priv); |
367 | if (ret) | |
368 | return ret; | |
369 | ||
370 | ret = ttm_bo_device_init(&dev_priv->ttm.bdev, | |
371 | dev_priv->ttm.bo_global_ref.ref.object, | |
372 | &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET, | |
373 | dma_bits <= 32 ? true : false); | |
374 | if (ret) { | |
375 | NV_ERROR(dev, "Error initialising bo driver: %d\n", ret); | |
376 | return ret; | |
377 | } | |
378 | ||
7ad2d31c BS |
379 | vram_type = vram_type_map; |
380 | while (vram_type->value != NV_MEM_TYPE_UNKNOWN) { | |
381 | if (nouveau_vram_type) { | |
382 | if (!strcasecmp(nouveau_vram_type, vram_type->name)) | |
383 | break; | |
384 | dev_priv->vram_type = vram_type->value; | |
385 | } else { | |
386 | if (vram_type->value == dev_priv->vram_type) | |
387 | break; | |
388 | } | |
389 | vram_type++; | |
390 | } | |
391 | ||
392 | NV_INFO(dev, "Detected %dMiB VRAM (%s)\n", | |
393 | (int)(dev_priv->vram_size >> 20), vram_type->name); | |
60d2a88a BS |
394 | if (dev_priv->vram_sys_base) { |
395 | NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", | |
396 | dev_priv->vram_sys_base); | |
397 | } | |
398 | ||
573a2a37 BS |
399 | dev_priv->fb_available_size = dev_priv->vram_size; |
400 | dev_priv->fb_mappable_pages = dev_priv->fb_available_size; | |
401 | if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) | |
402 | dev_priv->fb_mappable_pages = pci_resource_len(dev->pdev, 1); | |
403 | dev_priv->fb_mappable_pages >>= PAGE_SHIFT; | |
404 | ||
6ee73861 BS |
405 | dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; |
406 | dev_priv->fb_aper_free = dev_priv->fb_available_size; | |
407 | ||
408 | /* mappable vram */ | |
409 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | |
410 | dev_priv->fb_available_size >> PAGE_SHIFT); | |
411 | if (ret) { | |
412 | NV_ERROR(dev, "Failed VRAM mm init: %d\n", ret); | |
413 | return ret; | |
414 | } | |
415 | ||
d550c41e | 416 | if (dev_priv->card_type < NV_50) { |
7375c95b | 417 | ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM, |
d550c41e BS |
418 | 0, 0, &dev_priv->vga_ram); |
419 | if (ret == 0) | |
420 | ret = nouveau_bo_pin(dev_priv->vga_ram, | |
421 | TTM_PL_FLAG_VRAM); | |
422 | ||
423 | if (ret) { | |
424 | NV_WARN(dev, "failed to reserve VGA memory\n"); | |
425 | nouveau_bo_ref(NULL, &dev_priv->vga_ram); | |
426 | } | |
ac8fb975 BS |
427 | } |
428 | ||
fbd2895e BS |
429 | dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), |
430 | pci_resource_len(dev->pdev, 1), | |
431 | DRM_MTRR_WC); | |
432 | return 0; | |
433 | } | |
434 | ||
435 | int | |
436 | nouveau_mem_gart_init(struct drm_device *dev) | |
437 | { | |
438 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
439 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | |
440 | int ret; | |
441 | ||
442 | dev_priv->gart_info.type = NOUVEAU_GART_NONE; | |
443 | ||
6ee73861 | 444 | #if !defined(__powerpc__) && !defined(__ia64__) |
8410ea3b | 445 | if (drm_pci_device_is_agp(dev) && dev->agp && nouveau_agpmode) { |
6ee73861 BS |
446 | ret = nouveau_mem_init_agp(dev); |
447 | if (ret) | |
448 | NV_ERROR(dev, "Error initialising AGP: %d\n", ret); | |
449 | } | |
450 | #endif | |
451 | ||
452 | if (dev_priv->gart_info.type == NOUVEAU_GART_NONE) { | |
453 | ret = nouveau_sgdma_init(dev); | |
454 | if (ret) { | |
455 | NV_ERROR(dev, "Error initialising PCI(E): %d\n", ret); | |
456 | return ret; | |
457 | } | |
458 | } | |
459 | ||
460 | NV_INFO(dev, "%d MiB GART (aperture)\n", | |
461 | (int)(dev_priv->gart_info.aper_size >> 20)); | |
462 | dev_priv->gart_info.aper_free = dev_priv->gart_info.aper_size; | |
463 | ||
464 | ret = ttm_bo_init_mm(bdev, TTM_PL_TT, | |
465 | dev_priv->gart_info.aper_size >> PAGE_SHIFT); | |
466 | if (ret) { | |
467 | NV_ERROR(dev, "Failed TT mm init: %d\n", ret); | |
468 | return ret; | |
469 | } | |
470 | ||
6ee73861 BS |
471 | return 0; |
472 | } | |
473 | ||
fd99fd61 BS |
474 | static int |
475 | nv40_mem_timing_calc(struct drm_device *dev, u32 freq, | |
476 | struct nouveau_pm_tbl_entry *e, u8 len, | |
477 | struct nouveau_pm_memtiming *boot, | |
478 | struct nouveau_pm_memtiming *t) | |
ddb20055 | 479 | { |
c7c039fd | 480 | t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); |
9a782488 RS |
481 | |
482 | /* XXX: I don't trust the -1's and +1's... they must come | |
483 | * from somewhere! */ | |
c7c039fd RS |
484 | t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | |
485 | 1 << 16 | | |
486 | (e->tWTR + 2 + (t->tCWL - 1)) << 8 | | |
487 | (e->tCL + 2 - (t->tCWL - 1)); | |
488 | ||
489 | t->reg[2] = 0x20200000 | | |
490 | ((t->tCWL - 1) << 24 | | |
491 | e->tRRD << 16 | | |
492 | e->tRCDWR << 8 | | |
493 | e->tRCDRD); | |
494 | ||
495 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", t->id, | |
496 | t->reg[0], t->reg[1], t->reg[2]); | |
fd99fd61 | 497 | return 0; |
9a782488 RS |
498 | } |
499 | ||
fd99fd61 BS |
500 | static int |
501 | nv50_mem_timing_calc(struct drm_device *dev, u32 freq, | |
502 | struct nouveau_pm_tbl_entry *e, u8 len, | |
503 | struct nouveau_pm_memtiming *boot, | |
504 | struct nouveau_pm_memtiming *t) | |
ddb20055 | 505 | { |
9a782488 | 506 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
fd99fd61 | 507 | struct bit_entry P; |
c7c039fd | 508 | uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3; |
9a782488 | 509 | |
fd99fd61 BS |
510 | if (bit_table(dev, 'P', &P)) |
511 | return -EINVAL; | |
512 | ||
513 | switch (min(len, (u8) 22)) { | |
9a782488 RS |
514 | case 22: |
515 | unk21 = e->tUNK_21; | |
516 | case 21: | |
517 | unk20 = e->tUNK_20; | |
518 | case 20: | |
bfb31465 | 519 | if (e->tCWL > 0) |
c7c039fd | 520 | t->tCWL = e->tCWL; |
9a782488 RS |
521 | case 19: |
522 | unk18 = e->tUNK_18; | |
523 | break; | |
524 | } | |
525 | ||
c7c039fd | 526 | t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); |
9a782488 | 527 | |
c7c039fd | 528 | t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | |
bfb31465 | 529 | max(unk18, (u8) 1) << 16 | |
c7c039fd | 530 | (e->tWTR + 2 + (t->tCWL - 1)) << 8; |
bfb31465 | 531 | |
c7c039fd RS |
532 | t->reg[2] = ((t->tCWL - 1) << 24 | |
533 | e->tRRD << 16 | | |
534 | e->tRCDWR << 8 | | |
535 | e->tRCDRD); | |
ddb20055 | 536 | |
c7c039fd | 537 | t->reg[4] = e->tUNK_13 << 8 | e->tUNK_13; |
9a782488 | 538 | |
c7c039fd | 539 | t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP); |
bfb31465 | 540 | |
c7c039fd | 541 | t->reg[8] = boot->reg[8] & 0xffffff00; |
9a782488 | 542 | |
fd99fd61 | 543 | if (P.version == 1) { |
c7c039fd | 544 | t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1)); |
ddb20055 | 545 | |
c7c039fd RS |
546 | t->reg[3] = (0x14 + e->tCL) << 24 | |
547 | 0x16 << 16 | | |
548 | (e->tCL - 1) << 8 | | |
549 | (e->tCL - 1); | |
ddb20055 | 550 | |
c7c039fd | 551 | t->reg[4] |= boot->reg[4] & 0xffff0000; |
ddb20055 | 552 | |
c7c039fd RS |
553 | t->reg[6] = (0x33 - t->tCWL) << 16 | |
554 | t->tCWL << 8 | | |
555 | (0x2e + e->tCL - t->tCWL); | |
ddb20055 | 556 | |
c7c039fd | 557 | t->reg[7] = 0x4000202 | (e->tCL - 1) << 16; |
bfb31465 RS |
558 | |
559 | /* XXX: P.version == 1 only has DDR2 and GDDR3? */ | |
560 | if (dev_priv->vram_type == NV_MEM_TYPE_DDR2) { | |
c7c039fd RS |
561 | t->reg[5] |= (e->tCL + 3) << 8; |
562 | t->reg[6] |= (t->tCWL - 2) << 8; | |
563 | t->reg[8] |= (e->tCL - 4); | |
bfb31465 | 564 | } else { |
c7c039fd RS |
565 | t->reg[5] |= (e->tCL + 2) << 8; |
566 | t->reg[6] |= t->tCWL << 8; | |
567 | t->reg[8] |= (e->tCL - 2); | |
bfb31465 | 568 | } |
9a782488 | 569 | } else { |
c7c039fd | 570 | t->reg[1] |= (5 + e->tCL - (t->tCWL)); |
bfb31465 RS |
571 | |
572 | /* XXX: 0xb? 0x30? */ | |
c7c039fd RS |
573 | t->reg[3] = (0x30 + e->tCL) << 24 | |
574 | (boot->reg[3] & 0x00ff0000)| | |
575 | (0xb + e->tCL) << 8 | | |
576 | (e->tCL - 1); | |
bfb31465 | 577 | |
c7c039fd | 578 | t->reg[4] |= (unk20 << 24 | unk21 << 16); |
bfb31465 | 579 | |
9a782488 | 580 | /* XXX: +6? */ |
c7c039fd | 581 | t->reg[5] |= (t->tCWL + 6) << 8; |
9a782488 | 582 | |
c7c039fd RS |
583 | t->reg[6] = (0x5a + e->tCL) << 16 | |
584 | (6 - e->tCL + t->tCWL) << 8 | | |
585 | (0x50 + e->tCL - t->tCWL); | |
bfb31465 | 586 | |
c7c039fd RS |
587 | tmp7_3 = (boot->reg[7] & 0xff000000) >> 24; |
588 | t->reg[7] = (tmp7_3 << 24) | | |
589 | ((tmp7_3 - 6 + e->tCL) << 16) | | |
590 | 0x202; | |
9a782488 RS |
591 | } |
592 | ||
c7c039fd RS |
593 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", t->id, |
594 | t->reg[0], t->reg[1], t->reg[2], t->reg[3]); | |
9a782488 | 595 | NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", |
c7c039fd RS |
596 | t->reg[4], t->reg[5], t->reg[6], t->reg[7]); |
597 | NV_DEBUG(dev, " 240: %08x\n", t->reg[8]); | |
fd99fd61 | 598 | return 0; |
9a782488 RS |
599 | } |
600 | ||
fd99fd61 BS |
601 | static int |
602 | nvc0_mem_timing_calc(struct drm_device *dev, u32 freq, | |
603 | struct nouveau_pm_tbl_entry *e, u8 len, | |
604 | struct nouveau_pm_memtiming *boot, | |
605 | struct nouveau_pm_memtiming *t) | |
ddb20055 | 606 | { |
c7c039fd RS |
607 | if (e->tCWL > 0) |
608 | t->tCWL = e->tCWL; | |
bfb31465 | 609 | |
c7c039fd RS |
610 | t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 | |
611 | e->tRFC << 8 | e->tRC); | |
ddb20055 | 612 | |
c7c039fd RS |
613 | t->reg[1] = (boot->reg[1] & 0xff000000) | |
614 | (e->tRCDWR & 0x0f) << 20 | | |
615 | (e->tRCDRD & 0x0f) << 14 | | |
616 | (e->tCWL << 7) | | |
617 | (e->tCL & 0x0f); | |
ddb20055 | 618 | |
c7c039fd RS |
619 | t->reg[2] = (boot->reg[2] & 0xff0000ff) | |
620 | e->tWR << 16 | e->tWTR << 8; | |
ddb20055 | 621 | |
c7c039fd RS |
622 | t->reg[3] = (e->tUNK_20 & 0xf) << 9 | |
623 | (e->tUNK_21 & 0xf) << 5 | | |
624 | (e->tUNK_13 & 0x1f); | |
ddb20055 | 625 | |
c7c039fd RS |
626 | t->reg[4] = (boot->reg[4] & 0xfff00fff) | |
627 | (e->tRRD&0x1f) << 15; | |
ddb20055 | 628 | |
c7c039fd RS |
629 | NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", t->id, |
630 | t->reg[0], t->reg[1], t->reg[2], t->reg[3]); | |
631 | NV_DEBUG(dev, " 2a0: %08x\n", t->reg[4]); | |
fd99fd61 | 632 | return 0; |
bfb31465 RS |
633 | } |
634 | ||
c7c039fd RS |
635 | /** |
636 | * MR generation methods | |
637 | */ | |
638 | ||
fd99fd61 BS |
639 | static int |
640 | nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq, | |
641 | struct nouveau_pm_tbl_entry *e, u8 len, | |
642 | struct nouveau_pm_memtiming *boot, | |
643 | struct nouveau_pm_memtiming *t) | |
c7c039fd RS |
644 | { |
645 | t->drive_strength = 0; | |
fd99fd61 | 646 | if (len < 15) { |
c7c039fd RS |
647 | t->odt = boot->odt; |
648 | } else { | |
649 | t->odt = e->RAM_FT1 & 0x07; | |
650 | } | |
651 | ||
652 | if (e->tCL >= NV_MEM_CL_DDR2_MAX) { | |
653 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | |
fd99fd61 | 654 | return -ERANGE; |
c7c039fd RS |
655 | } |
656 | ||
657 | if (e->tWR >= NV_MEM_WR_DDR2_MAX) { | |
658 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | |
fd99fd61 | 659 | return -ERANGE; |
c7c039fd RS |
660 | } |
661 | ||
662 | if (t->odt > 3) { | |
663 | NV_WARN(dev, "(%u) Invalid odt value, assuming disabled: %x", | |
664 | t->id, t->odt); | |
665 | t->odt = 0; | |
666 | } | |
667 | ||
668 | t->mr[0] = (boot->mr[0] & 0x100f) | | |
669 | (e->tCL) << 4 | | |
670 | (e->tWR - 1) << 9; | |
671 | t->mr[1] = (boot->mr[1] & 0x101fbb) | | |
672 | (t->odt & 0x1) << 2 | | |
673 | (t->odt & 0x2) << 5; | |
674 | ||
675 | NV_DEBUG(dev, "(%u) MR: %08x", t->id, t->mr[0]); | |
fd99fd61 | 676 | return 0; |
c7c039fd RS |
677 | } |
678 | ||
679 | uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = { | |
680 | 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; | |
681 | ||
fd99fd61 BS |
682 | static int |
683 | nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq, | |
684 | struct nouveau_pm_tbl_entry *e, u8 len, | |
685 | struct nouveau_pm_memtiming *boot, | |
686 | struct nouveau_pm_memtiming *t) | |
c7c039fd RS |
687 | { |
688 | u8 cl = e->tCL - 4; | |
689 | ||
690 | t->drive_strength = 0; | |
fd99fd61 | 691 | if (len < 15) { |
c7c039fd RS |
692 | t->odt = boot->odt; |
693 | } else { | |
694 | t->odt = e->RAM_FT1 & 0x07; | |
695 | } | |
696 | ||
697 | if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) { | |
698 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | |
fd99fd61 | 699 | return -ERANGE; |
c7c039fd RS |
700 | } |
701 | ||
702 | if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) { | |
703 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | |
fd99fd61 | 704 | return -ERANGE; |
c7c039fd RS |
705 | } |
706 | ||
707 | if (e->tCWL < 5) { | |
708 | NV_WARN(dev, "(%u) Invalid tCWL: %u", t->id, e->tCWL); | |
fd99fd61 | 709 | return -ERANGE; |
c7c039fd RS |
710 | } |
711 | ||
712 | t->mr[0] = (boot->mr[0] & 0x180b) | | |
713 | /* CAS */ | |
714 | (cl & 0x7) << 4 | | |
715 | (cl & 0x8) >> 1 | | |
716 | (nv_mem_wr_lut_ddr3[e->tWR]) << 9; | |
717 | t->mr[1] = (boot->mr[1] & 0x101dbb) | | |
718 | (t->odt & 0x1) << 2 | | |
719 | (t->odt & 0x2) << 5 | | |
720 | (t->odt & 0x4) << 7; | |
721 | t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3; | |
722 | ||
723 | NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]); | |
fd99fd61 | 724 | return 0; |
c7c039fd RS |
725 | } |
726 | ||
727 | uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = { | |
728 | 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11}; | |
729 | uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = { | |
730 | 0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3}; | |
731 | ||
fd99fd61 BS |
732 | static int |
733 | nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq, | |
734 | struct nouveau_pm_tbl_entry *e, u8 len, | |
735 | struct nouveau_pm_memtiming *boot, | |
736 | struct nouveau_pm_memtiming *t) | |
bfb31465 | 737 | { |
a9bc247c BS |
738 | u8 rver, rlen, *ramcfg = nouveau_perf_ramcfg(dev, freq, &rver, &rlen); |
739 | ||
fd99fd61 | 740 | if (len < 15) { |
c7c039fd RS |
741 | t->drive_strength = boot->drive_strength; |
742 | t->odt = boot->odt; | |
743 | } else { | |
744 | t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; | |
745 | t->odt = e->RAM_FT1 & 0x07; | |
bfb31465 | 746 | } |
c7c039fd RS |
747 | |
748 | if (e->tCL >= NV_MEM_CL_GDDR3_MAX) { | |
749 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | |
fd99fd61 | 750 | return -ERANGE; |
c7c039fd RS |
751 | } |
752 | ||
753 | if (e->tWR >= NV_MEM_WR_GDDR3_MAX) { | |
754 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | |
fd99fd61 | 755 | return -ERANGE; |
c7c039fd RS |
756 | } |
757 | ||
758 | if (t->odt > 3) { | |
759 | NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x", | |
760 | t->id, t->odt); | |
761 | t->odt = 0; | |
762 | } | |
763 | ||
764 | t->mr[0] = (boot->mr[0] & 0xe0b) | | |
765 | /* CAS */ | |
766 | ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) | | |
767 | ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2); | |
a9bc247c | 768 | |
c7c039fd RS |
769 | t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength | |
770 | (t->odt << 2) | | |
771 | (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4; | |
a9bc247c BS |
772 | if (ramcfg && rver == 0x00) { |
773 | /* DLL enable/disable */ | |
774 | t->mr[1] &= ~0x00000040; | |
775 | if (ramcfg[3] & 0x08) | |
776 | t->mr[1] |= 0x00000040; | |
777 | } | |
778 | ||
1a7287ea | 779 | t->mr[2] = boot->mr[2]; |
c7c039fd | 780 | |
1a7287ea BS |
781 | NV_DEBUG(dev, "(%u) MR: %08x %08x %08x", t->id, |
782 | t->mr[0], t->mr[1], t->mr[2]); | |
fd99fd61 | 783 | return 0; |
c7c039fd RS |
784 | } |
785 | ||
fd99fd61 BS |
786 | static int |
787 | nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq, | |
788 | struct nouveau_pm_tbl_entry *e, u8 len, | |
789 | struct nouveau_pm_memtiming *boot, | |
790 | struct nouveau_pm_memtiming *t) | |
c7c039fd | 791 | { |
fd99fd61 | 792 | if (len < 15) { |
c7c039fd RS |
793 | t->drive_strength = boot->drive_strength; |
794 | t->odt = boot->odt; | |
795 | } else { | |
796 | t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; | |
797 | t->odt = e->RAM_FT1 & 0x03; | |
798 | } | |
799 | ||
800 | if (e->tCL >= NV_MEM_CL_GDDR5_MAX) { | |
801 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | |
fd99fd61 | 802 | return -ERANGE; |
c7c039fd RS |
803 | } |
804 | ||
805 | if (e->tWR >= NV_MEM_WR_GDDR5_MAX) { | |
806 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | |
fd99fd61 | 807 | return -ERANGE; |
c7c039fd RS |
808 | } |
809 | ||
810 | if (t->odt > 3) { | |
811 | NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x", | |
812 | t->id, t->odt); | |
813 | t->odt = 0; | |
814 | } | |
815 | ||
816 | t->mr[0] = (boot->mr[0] & 0x007) | | |
817 | ((e->tCL - 5) << 3) | | |
818 | ((e->tWR - 4) << 8); | |
819 | t->mr[1] = (boot->mr[1] & 0x1007f0) | | |
820 | t->drive_strength | | |
821 | (t->odt << 2); | |
822 | ||
823 | NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]); | |
fd99fd61 | 824 | return 0; |
c7c039fd RS |
825 | } |
826 | ||
085028ce BS |
827 | int |
828 | nouveau_mem_timing_calc(struct drm_device *dev, u32 freq, | |
829 | struct nouveau_pm_memtiming *t) | |
fd99fd61 BS |
830 | { |
831 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
832 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | |
085028ce | 833 | struct nouveau_pm_memtiming *boot = &pm->boot.timing; |
fd99fd61 BS |
834 | struct nouveau_pm_tbl_entry *e; |
835 | u8 ver, len, *ptr; | |
836 | int ret; | |
837 | ||
838 | ptr = nouveau_perf_timing(dev, freq, &ver, &len); | |
085028ce BS |
839 | if (!ptr || ptr[0] == 0x00) { |
840 | *t = *boot; | |
841 | return 0; | |
842 | } | |
fd99fd61 BS |
843 | e = (struct nouveau_pm_tbl_entry *)ptr; |
844 | ||
085028ce | 845 | t->tCWL = boot->tCWL; |
fd99fd61 | 846 | |
085028ce BS |
847 | switch (dev_priv->card_type) { |
848 | case NV_40: | |
849 | ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t); | |
850 | break; | |
851 | case NV_50: | |
852 | ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t); | |
853 | break; | |
854 | case NV_C0: | |
855 | ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t); | |
856 | break; | |
857 | default: | |
858 | ret = -ENODEV; | |
859 | break; | |
860 | } | |
fd99fd61 | 861 | |
085028ce BS |
862 | switch (dev_priv->vram_type * !ret) { |
863 | case NV_MEM_TYPE_GDDR3: | |
864 | ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t); | |
865 | break; | |
866 | case NV_MEM_TYPE_GDDR5: | |
867 | ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t); | |
868 | break; | |
869 | case NV_MEM_TYPE_DDR2: | |
870 | ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t); | |
871 | break; | |
872 | case NV_MEM_TYPE_DDR3: | |
873 | ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t); | |
874 | break; | |
875 | default: | |
876 | ret = -EINVAL; | |
fd99fd61 BS |
877 | } |
878 | ||
085028ce | 879 | return ret; |
fd99fd61 BS |
880 | } |
881 | ||
882 | void | |
883 | nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t) | |
c7c039fd RS |
884 | { |
885 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
886 | u32 timing_base, timing_regs, mr_base; | |
887 | int i; | |
888 | ||
889 | if (dev_priv->card_type >= 0xC0) { | |
890 | timing_base = 0x10f290; | |
891 | mr_base = 0x10f300; | |
892 | } else { | |
893 | timing_base = 0x100220; | |
894 | mr_base = 0x1002c0; | |
895 | } | |
896 | ||
897 | t->id = -1; | |
898 | ||
899 | switch (dev_priv->card_type) { | |
900 | case NV_50: | |
901 | timing_regs = 9; | |
902 | break; | |
903 | case NV_C0: | |
904 | case NV_D0: | |
905 | timing_regs = 5; | |
906 | break; | |
907 | case NV_30: | |
908 | case NV_40: | |
909 | timing_regs = 3; | |
910 | break; | |
911 | default: | |
912 | timing_regs = 0; | |
913 | return; | |
914 | } | |
915 | for(i = 0; i < timing_regs; i++) | |
916 | t->reg[i] = nv_rd32(dev, timing_base + (0x04 * i)); | |
917 | ||
918 | t->tCWL = 0; | |
919 | if (dev_priv->card_type < NV_C0) { | |
920 | t->tCWL = ((nv_rd32(dev, 0x100228) & 0x0f000000) >> 24) + 1; | |
921 | } | |
922 | ||
923 | t->mr[0] = nv_rd32(dev, mr_base); | |
924 | t->mr[1] = nv_rd32(dev, mr_base + 0x04); | |
925 | t->mr[2] = nv_rd32(dev, mr_base + 0x20); | |
926 | t->mr[3] = nv_rd32(dev, mr_base + 0x24); | |
927 | ||
928 | t->odt = 0; | |
929 | t->drive_strength = 0; | |
930 | ||
931 | switch (dev_priv->vram_type) { | |
932 | case NV_MEM_TYPE_DDR3: | |
933 | t->odt |= (t->mr[1] & 0x200) >> 7; | |
934 | case NV_MEM_TYPE_DDR2: | |
935 | t->odt |= (t->mr[1] & 0x04) >> 2 | | |
936 | (t->mr[1] & 0x40) >> 5; | |
937 | break; | |
938 | case NV_MEM_TYPE_GDDR3: | |
939 | case NV_MEM_TYPE_GDDR5: | |
940 | t->drive_strength = t->mr[1] & 0x03; | |
941 | t->odt = (t->mr[1] & 0x0c) >> 2; | |
942 | break; | |
943 | default: | |
944 | break; | |
945 | } | |
946 | } | |
947 | ||
2d85bc88 BS |
948 | int |
949 | nouveau_mem_exec(struct nouveau_mem_exec_func *exec, | |
950 | struct nouveau_pm_level *perflvl) | |
951 | { | |
952 | struct drm_nouveau_private *dev_priv = exec->dev->dev_private; | |
953 | struct nouveau_pm_memtiming *info = &perflvl->timing; | |
954 | u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0; | |
955 | u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] }; | |
956 | u32 mr1_dlloff; | |
957 | ||
958 | switch (dev_priv->vram_type) { | |
959 | case NV_MEM_TYPE_DDR2: | |
960 | tDLLK = 2000; | |
961 | mr1_dlloff = 0x00000001; | |
962 | break; | |
963 | case NV_MEM_TYPE_DDR3: | |
964 | tDLLK = 12000; | |
965 | mr1_dlloff = 0x00000001; | |
966 | break; | |
967 | case NV_MEM_TYPE_GDDR3: | |
968 | tDLLK = 40000; | |
969 | mr1_dlloff = 0x00000040; | |
970 | break; | |
971 | default: | |
972 | NV_ERROR(exec->dev, "cannot reclock unsupported memtype\n"); | |
973 | return -ENODEV; | |
974 | } | |
975 | ||
976 | /* fetch current MRs */ | |
977 | switch (dev_priv->vram_type) { | |
1a7287ea | 978 | case NV_MEM_TYPE_GDDR3: |
2d85bc88 BS |
979 | case NV_MEM_TYPE_DDR3: |
980 | mr[2] = exec->mrg(exec, 2); | |
981 | default: | |
982 | mr[1] = exec->mrg(exec, 1); | |
983 | mr[0] = exec->mrg(exec, 0); | |
984 | break; | |
985 | } | |
986 | ||
987 | /* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh */ | |
988 | if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) { | |
989 | exec->precharge(exec); | |
990 | exec->mrs (exec, 1, mr[1] | mr1_dlloff); | |
991 | exec->wait(exec, tMRD); | |
992 | } | |
993 | ||
994 | /* enter self-refresh mode */ | |
995 | exec->precharge(exec); | |
996 | exec->refresh(exec); | |
997 | exec->refresh(exec); | |
998 | exec->refresh_auto(exec, false); | |
999 | exec->refresh_self(exec, true); | |
1000 | exec->wait(exec, tCKSRE); | |
1001 | ||
1002 | /* modify input clock frequency */ | |
1003 | exec->clock_set(exec); | |
1004 | ||
1005 | /* exit self-refresh mode */ | |
1006 | exec->wait(exec, tCKSRX); | |
1007 | exec->precharge(exec); | |
1008 | exec->refresh_self(exec, false); | |
1009 | exec->refresh_auto(exec, true); | |
1010 | exec->wait(exec, tXS); | |
1011 | ||
1012 | /* update MRs */ | |
1013 | if (mr[2] != info->mr[2]) { | |
1014 | exec->mrs (exec, 2, info->mr[2]); | |
1015 | exec->wait(exec, tMRD); | |
1016 | } | |
1017 | ||
1018 | if (mr[1] != info->mr[1]) { | |
b830973b BS |
1019 | /* need to keep DLL off until later, at least on GDDR3 */ |
1020 | exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff)); | |
2d85bc88 BS |
1021 | exec->wait(exec, tMRD); |
1022 | } | |
1023 | ||
1024 | if (mr[0] != info->mr[0]) { | |
1025 | exec->mrs (exec, 0, info->mr[0]); | |
1026 | exec->wait(exec, tMRD); | |
1027 | } | |
1028 | ||
1029 | /* update PFB timing registers */ | |
1030 | exec->timing_set(exec); | |
1031 | ||
b830973b | 1032 | /* DLL (enable + ) reset */ |
2d85bc88 | 1033 | if (!(info->mr[1] & mr1_dlloff)) { |
b830973b BS |
1034 | if (mr[1] & mr1_dlloff) { |
1035 | exec->mrs (exec, 1, info->mr[1]); | |
1036 | exec->wait(exec, tMRD); | |
1037 | } | |
2d85bc88 BS |
1038 | exec->mrs (exec, 0, info->mr[0] | 0x00000100); |
1039 | exec->wait(exec, tMRD); | |
1040 | exec->mrs (exec, 0, info->mr[0] | 0x00000000); | |
1041 | exec->wait(exec, tMRD); | |
1042 | exec->wait(exec, tDLLK); | |
1043 | if (dev_priv->vram_type == NV_MEM_TYPE_GDDR3) | |
1044 | exec->precharge(exec); | |
1045 | } | |
1046 | ||
1047 | return 0; | |
1048 | } | |
1049 | ||
c70c41e8 BS |
1050 | int |
1051 | nouveau_mem_vbios_type(struct drm_device *dev) | |
1052 | { | |
1053 | struct bit_entry M; | |
1054 | u8 ramcfg = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2; | |
1055 | if (!bit_table(dev, 'M', &M) || M.version != 2 || M.length < 5) { | |
1056 | u8 *table = ROMPTR(dev, M.data[3]); | |
1057 | if (table && table[0] == 0x10 && ramcfg < table[3]) { | |
1058 | u8 *entry = table + table[1] + (ramcfg * table[2]); | |
1059 | switch (entry[0] & 0x0f) { | |
1060 | case 0: return NV_MEM_TYPE_DDR2; | |
1061 | case 1: return NV_MEM_TYPE_DDR3; | |
1062 | case 2: return NV_MEM_TYPE_GDDR3; | |
1063 | case 3: return NV_MEM_TYPE_GDDR5; | |
1064 | default: | |
1065 | break; | |
1066 | } | |
1067 | ||
1068 | } | |
1069 | } | |
1070 | return NV_MEM_TYPE_UNKNOWN; | |
1071 | } | |
1072 | ||
573a2a37 | 1073 | static int |
24f246ac | 1074 | nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) |
573a2a37 | 1075 | { |
24f246ac | 1076 | /* nothing to do */ |
573a2a37 BS |
1077 | return 0; |
1078 | } | |
1079 | ||
1080 | static int | |
1081 | nouveau_vram_manager_fini(struct ttm_mem_type_manager *man) | |
1082 | { | |
24f246ac | 1083 | /* nothing to do */ |
573a2a37 BS |
1084 | return 0; |
1085 | } | |
1086 | ||
d2f96666 BS |
1087 | static inline void |
1088 | nouveau_mem_node_cleanup(struct nouveau_mem *node) | |
1089 | { | |
1090 | if (node->vma[0].node) { | |
1091 | nouveau_vm_unmap(&node->vma[0]); | |
1092 | nouveau_vm_put(&node->vma[0]); | |
1093 | } | |
1094 | ||
1095 | if (node->vma[1].node) { | |
1096 | nouveau_vm_unmap(&node->vma[1]); | |
1097 | nouveau_vm_put(&node->vma[1]); | |
1098 | } | |
1099 | } | |
1100 | ||
573a2a37 BS |
1101 | static void |
1102 | nouveau_vram_manager_del(struct ttm_mem_type_manager *man, | |
1103 | struct ttm_mem_reg *mem) | |
1104 | { | |
1105 | struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); | |
60d2a88a | 1106 | struct nouveau_vram_engine *vram = &dev_priv->engine.vram; |
573a2a37 BS |
1107 | struct drm_device *dev = dev_priv->dev; |
1108 | ||
d2f96666 | 1109 | nouveau_mem_node_cleanup(mem->mm_node); |
d5f42394 | 1110 | vram->put(dev, (struct nouveau_mem **)&mem->mm_node); |
573a2a37 BS |
1111 | } |
1112 | ||
1113 | static int | |
1114 | nouveau_vram_manager_new(struct ttm_mem_type_manager *man, | |
1115 | struct ttm_buffer_object *bo, | |
1116 | struct ttm_placement *placement, | |
1117 | struct ttm_mem_reg *mem) | |
1118 | { | |
1119 | struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); | |
60d2a88a | 1120 | struct nouveau_vram_engine *vram = &dev_priv->engine.vram; |
573a2a37 BS |
1121 | struct drm_device *dev = dev_priv->dev; |
1122 | struct nouveau_bo *nvbo = nouveau_bo(bo); | |
d5f42394 | 1123 | struct nouveau_mem *node; |
5f6fdca5 | 1124 | u32 size_nc = 0; |
573a2a37 BS |
1125 | int ret; |
1126 | ||
5f6fdca5 | 1127 | if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) |
f91bac5b | 1128 | size_nc = 1 << nvbo->page_shift; |
5f6fdca5 | 1129 | |
60d2a88a BS |
1130 | ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, |
1131 | mem->page_alignment << PAGE_SHIFT, size_nc, | |
8f7286f8 | 1132 | (nvbo->tile_flags >> 8) & 0x3ff, &node); |
ef1b2871 BS |
1133 | if (ret) { |
1134 | mem->mm_node = NULL; | |
1135 | return (ret == -ENOSPC) ? 0 : ret; | |
1136 | } | |
573a2a37 | 1137 | |
f91bac5b | 1138 | node->page_shift = nvbo->page_shift; |
4c74eb7f | 1139 | |
60d2a88a BS |
1140 | mem->mm_node = node; |
1141 | mem->start = node->offset >> PAGE_SHIFT; | |
573a2a37 BS |
1142 | return 0; |
1143 | } | |
1144 | ||
1145 | void | |
1146 | nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) | |
1147 | { | |
573a2a37 BS |
1148 | struct nouveau_mm *mm = man->priv; |
1149 | struct nouveau_mm_node *r; | |
8b464bfe | 1150 | u32 total = 0, free = 0; |
573a2a37 BS |
1151 | |
1152 | mutex_lock(&mm->mutex); | |
1153 | list_for_each_entry(r, &mm->nodes, nl_entry) { | |
8b464bfe BS |
1154 | printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", |
1155 | prefix, r->type, ((u64)r->offset << 12), | |
573a2a37 | 1156 | (((u64)r->offset + r->length) << 12)); |
8b464bfe | 1157 | |
573a2a37 | 1158 | total += r->length; |
8b464bfe BS |
1159 | if (!r->type) |
1160 | free += r->length; | |
573a2a37 BS |
1161 | } |
1162 | mutex_unlock(&mm->mutex); | |
1163 | ||
8b464bfe BS |
1164 | printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", |
1165 | prefix, (u64)total << 12, (u64)free << 12); | |
1166 | printk(KERN_DEBUG "%s block: 0x%08x\n", | |
1167 | prefix, mm->block_size << 12); | |
573a2a37 BS |
1168 | } |
1169 | ||
1170 | const struct ttm_mem_type_manager_func nouveau_vram_manager = { | |
1171 | nouveau_vram_manager_init, | |
1172 | nouveau_vram_manager_fini, | |
1173 | nouveau_vram_manager_new, | |
1174 | nouveau_vram_manager_del, | |
1175 | nouveau_vram_manager_debug | |
1176 | }; | |
26c0c9e3 BS |
1177 | |
1178 | static int | |
1179 | nouveau_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) | |
1180 | { | |
1181 | return 0; | |
1182 | } | |
1183 | ||
1184 | static int | |
1185 | nouveau_gart_manager_fini(struct ttm_mem_type_manager *man) | |
1186 | { | |
1187 | return 0; | |
1188 | } | |
1189 | ||
1190 | static void | |
1191 | nouveau_gart_manager_del(struct ttm_mem_type_manager *man, | |
1192 | struct ttm_mem_reg *mem) | |
1193 | { | |
d2f96666 | 1194 | nouveau_mem_node_cleanup(mem->mm_node); |
d2f96666 | 1195 | kfree(mem->mm_node); |
0de53a54 | 1196 | mem->mm_node = NULL; |
26c0c9e3 BS |
1197 | } |
1198 | ||
1199 | static int | |
1200 | nouveau_gart_manager_new(struct ttm_mem_type_manager *man, | |
1201 | struct ttm_buffer_object *bo, | |
1202 | struct ttm_placement *placement, | |
1203 | struct ttm_mem_reg *mem) | |
1204 | { | |
1205 | struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); | |
26c0c9e3 | 1206 | struct nouveau_mem *node; |
26c0c9e3 BS |
1207 | |
1208 | if (unlikely((mem->num_pages << PAGE_SHIFT) >= | |
1209 | dev_priv->gart_info.aper_size)) | |
1210 | return -ENOMEM; | |
1211 | ||
1212 | node = kzalloc(sizeof(*node), GFP_KERNEL); | |
1213 | if (!node) | |
1214 | return -ENOMEM; | |
d2f96666 | 1215 | node->page_shift = 12; |
26c0c9e3 | 1216 | |
26c0c9e3 BS |
1217 | mem->mm_node = node; |
1218 | mem->start = 0; | |
1219 | return 0; | |
1220 | } | |
1221 | ||
1222 | void | |
1223 | nouveau_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) | |
1224 | { | |
1225 | } | |
1226 | ||
1227 | const struct ttm_mem_type_manager_func nouveau_gart_manager = { | |
1228 | nouveau_gart_manager_init, | |
1229 | nouveau_gart_manager_fini, | |
1230 | nouveau_gart_manager_new, | |
1231 | nouveau_gart_manager_del, | |
1232 | nouveau_gart_manager_debug | |
1233 | }; |