diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_mem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 809 |
1 files changed, 587 insertions, 222 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index c3a5745e9c79..b08065f981df 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -26,7 +26,8 @@ | |||
26 | * DEALINGS IN THE SOFTWARE. | 26 | * DEALINGS IN THE SOFTWARE. |
27 | * | 27 | * |
28 | * Authors: | 28 | * Authors: |
29 | * Keith Whitwell <keith@tungstengraphics.com> | 29 | * Ben Skeggs <bskeggs@redhat.com> |
30 | * Roy Spliet <r.spliet@student.tudelft.nl> | ||
30 | */ | 31 | */ |
31 | 32 | ||
32 | 33 | ||
@@ -192,75 +193,6 @@ nouveau_mem_gart_fini(struct drm_device *dev) | |||
192 | } | 193 | } |
193 | } | 194 | } |
194 | 195 | ||
195 | static uint32_t | ||
196 | nouveau_mem_detect_nv04(struct drm_device *dev) | ||
197 | { | ||
198 | uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0); | ||
199 | |||
200 | if (boot0 & 0x00000100) | ||
201 | return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024; | ||
202 | |||
203 | switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { | ||
204 | case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: | ||
205 | return 32 * 1024 * 1024; | ||
206 | case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: | ||
207 | return 16 * 1024 * 1024; | ||
208 | case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: | ||
209 | return 8 * 1024 * 1024; | ||
210 | case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: | ||
211 | return 4 * 1024 * 1024; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static uint32_t | ||
218 | nouveau_mem_detect_nforce(struct drm_device *dev) | ||
219 | { | ||
220 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
221 | struct pci_dev *bridge; | ||
222 | uint32_t mem; | ||
223 | |||
224 | bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); | ||
225 | if (!bridge) { | ||
226 | NV_ERROR(dev, "no bridge device\n"); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | if (dev_priv->flags & NV_NFORCE) { | ||
231 | pci_read_config_dword(bridge, 0x7C, &mem); | ||
232 | return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024; | ||
233 | } else | ||
234 | if (dev_priv->flags & NV_NFORCE2) { | ||
235 | pci_read_config_dword(bridge, 0x84, &mem); | ||
236 | return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024; | ||
237 | } | ||
238 | |||
239 | NV_ERROR(dev, "impossible!\n"); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | int | ||
244 | nouveau_mem_detect(struct drm_device *dev) | ||
245 | { | ||
246 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
247 | |||
248 | if (dev_priv->card_type == NV_04) { | ||
249 | dev_priv->vram_size = nouveau_mem_detect_nv04(dev); | ||
250 | } else | ||
251 | if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { | ||
252 | dev_priv->vram_size = nouveau_mem_detect_nforce(dev); | ||
253 | } else | ||
254 | if (dev_priv->card_type < NV_50) { | ||
255 | dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); | ||
256 | dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; | ||
257 | } | ||
258 | |||
259 | if (dev_priv->vram_size) | ||
260 | return 0; | ||
261 | return -ENOMEM; | ||
262 | } | ||
263 | |||
264 | bool | 196 | bool |
265 | nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) | 197 | nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) |
266 | { | 198 | { |
@@ -385,11 +317,29 @@ nouveau_mem_init_agp(struct drm_device *dev) | |||
385 | return 0; | 317 | return 0; |
386 | } | 318 | } |
387 | 319 | ||
320 | static const struct vram_types { | ||
321 | int value; | ||
322 | const char *name; | ||
323 | } vram_type_map[] = { | ||
324 | { NV_MEM_TYPE_STOLEN , "stolen system memory" }, | ||
325 | { NV_MEM_TYPE_SGRAM , "SGRAM" }, | ||
326 | { NV_MEM_TYPE_SDRAM , "SDRAM" }, | ||
327 | { NV_MEM_TYPE_DDR1 , "DDR1" }, | ||
328 | { NV_MEM_TYPE_DDR2 , "DDR2" }, | ||
329 | { NV_MEM_TYPE_DDR3 , "DDR3" }, | ||
330 | { NV_MEM_TYPE_GDDR2 , "GDDR2" }, | ||
331 | { NV_MEM_TYPE_GDDR3 , "GDDR3" }, | ||
332 | { NV_MEM_TYPE_GDDR4 , "GDDR4" }, | ||
333 | { NV_MEM_TYPE_GDDR5 , "GDDR5" }, | ||
334 | { NV_MEM_TYPE_UNKNOWN, "unknown type" } | ||
335 | }; | ||
336 | |||
388 | int | 337 | int |
389 | nouveau_mem_vram_init(struct drm_device *dev) | 338 | nouveau_mem_vram_init(struct drm_device *dev) |
390 | { | 339 | { |
391 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 340 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
392 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | 341 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; |
342 | const struct vram_types *vram_type; | ||
393 | int ret, dma_bits; | 343 | int ret, dma_bits; |
394 | 344 | ||
395 | dma_bits = 32; | 345 | dma_bits = 32; |
@@ -427,7 +377,21 @@ nouveau_mem_vram_init(struct drm_device *dev) | |||
427 | return ret; | 377 | return ret; |
428 | } | 378 | } |
429 | 379 | ||
430 | NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); | 380 | vram_type = vram_type_map; |
381 | while (vram_type->value != NV_MEM_TYPE_UNKNOWN) { | ||
382 | if (nouveau_vram_type) { | ||
383 | if (!strcasecmp(nouveau_vram_type, vram_type->name)) | ||
384 | break; | ||
385 | dev_priv->vram_type = vram_type->value; | ||
386 | } else { | ||
387 | if (vram_type->value == dev_priv->vram_type) | ||
388 | break; | ||
389 | } | ||
390 | vram_type++; | ||
391 | } | ||
392 | |||
393 | NV_INFO(dev, "Detected %dMiB VRAM (%s)\n", | ||
394 | (int)(dev_priv->vram_size >> 20), vram_type->name); | ||
431 | if (dev_priv->vram_sys_base) { | 395 | if (dev_priv->vram_sys_base) { |
432 | NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", | 396 | NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", |
433 | dev_priv->vram_sys_base); | 397 | dev_priv->vram_sys_base); |
@@ -508,216 +472,617 @@ nouveau_mem_gart_init(struct drm_device *dev) | |||
508 | return 0; | 472 | return 0; |
509 | } | 473 | } |
510 | 474 | ||
511 | /* XXX: For now a dummy. More samples required, possibly even a card | 475 | static int |
512 | * Called from nouveau_perf.c */ | 476 | nv40_mem_timing_calc(struct drm_device *dev, u32 freq, |
513 | void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | 477 | struct nouveau_pm_tbl_entry *e, u8 len, |
514 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number, | 478 | struct nouveau_pm_memtiming *boot, |
515 | struct nouveau_pm_memtiming *timing) { | 479 | struct nouveau_pm_memtiming *t) |
516 | 480 | { | |
517 | NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); | 481 | t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); |
518 | } | ||
519 | |||
520 | void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | ||
521 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number, | ||
522 | struct nouveau_pm_memtiming *timing) { | ||
523 | |||
524 | timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); | ||
525 | 482 | ||
526 | /* XXX: I don't trust the -1's and +1's... they must come | 483 | /* XXX: I don't trust the -1's and +1's... they must come |
527 | * from somewhere! */ | 484 | * from somewhere! */ |
528 | timing->reg_1 = (e->tWR + 2 + magic_number) << 24 | | 485 | t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | |
529 | 1 << 16 | | 486 | 1 << 16 | |
530 | (e->tUNK_1 + 2 + magic_number) << 8 | | 487 | (e->tWTR + 2 + (t->tCWL - 1)) << 8 | |
531 | (e->tCL + 2 - magic_number); | 488 | (e->tCL + 2 - (t->tCWL - 1)); |
532 | timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); | 489 | |
533 | timing->reg_2 |= 0x20200000; | 490 | t->reg[2] = 0x20200000 | |
534 | 491 | ((t->tCWL - 1) << 24 | | |
535 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, | 492 | e->tRRD << 16 | |
536 | timing->reg_0, timing->reg_1,timing->reg_2); | 493 | e->tRCDWR << 8 | |
494 | e->tRCDRD); | ||
495 | |||
496 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", t->id, | ||
497 | t->reg[0], t->reg[1], t->reg[2]); | ||
498 | return 0; | ||
537 | } | 499 | } |
538 | 500 | ||
539 | void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, | 501 | static int |
540 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { | 502 | nv50_mem_timing_calc(struct drm_device *dev, u32 freq, |
503 | struct nouveau_pm_tbl_entry *e, u8 len, | ||
504 | struct nouveau_pm_memtiming *boot, | ||
505 | struct nouveau_pm_memtiming *t) | ||
506 | { | ||
541 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 507 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
508 | struct bit_entry P; | ||
509 | uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3; | ||
542 | 510 | ||
543 | uint8_t unk18 = 1, | 511 | if (bit_table(dev, 'P', &P)) |
544 | unk19 = 1, | 512 | return -EINVAL; |
545 | unk20 = 0, | ||
546 | unk21 = 0; | ||
547 | 513 | ||
548 | switch (min(hdr->entry_len, (u8) 22)) { | 514 | switch (min(len, (u8) 22)) { |
549 | case 22: | 515 | case 22: |
550 | unk21 = e->tUNK_21; | 516 | unk21 = e->tUNK_21; |
551 | case 21: | 517 | case 21: |
552 | unk20 = e->tUNK_20; | 518 | unk20 = e->tUNK_20; |
553 | case 20: | 519 | case 20: |
554 | unk19 = e->tUNK_19; | 520 | if (e->tCWL > 0) |
521 | t->tCWL = e->tCWL; | ||
555 | case 19: | 522 | case 19: |
556 | unk18 = e->tUNK_18; | 523 | unk18 = e->tUNK_18; |
557 | break; | 524 | break; |
558 | } | 525 | } |
559 | 526 | ||
560 | timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); | 527 | t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); |
561 | 528 | ||
562 | /* XXX: I don't trust the -1's and +1's... they must come | 529 | t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | |
563 | * from somewhere! */ | 530 | max(unk18, (u8) 1) << 16 | |
564 | timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 | | 531 | (e->tWTR + 2 + (t->tCWL - 1)) << 8; |
565 | max(unk18, (u8) 1) << 16 | | 532 | |
566 | (e->tUNK_1 + unk19 + 1 + magic_number) << 8; | 533 | t->reg[2] = ((t->tCWL - 1) << 24 | |
567 | if (dev_priv->chipset == 0xa8) { | 534 | e->tRRD << 16 | |
568 | timing->reg_1 |= (e->tCL - 1); | 535 | e->tRCDWR << 8 | |
569 | } else { | 536 | e->tRCDRD); |
570 | timing->reg_1 |= (e->tCL + 2 - magic_number); | 537 | |
571 | } | 538 | t->reg[4] = e->tUNK_13 << 8 | e->tUNK_13; |
572 | timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); | 539 | |
573 | 540 | t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP); | |
574 | timing->reg_5 = (e->tRAS << 24 | e->tRC); | 541 | |
575 | timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; | 542 | t->reg[8] = boot->reg[8] & 0xffffff00; |
576 | 543 | ||
577 | if (P->version == 1) { | 544 | if (P.version == 1) { |
578 | timing->reg_2 |= magic_number << 24; | 545 | t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1)); |
579 | timing->reg_3 = (0x14 + e->tCL) << 24 | | 546 | |
580 | 0x16 << 16 | | 547 | t->reg[3] = (0x14 + e->tCL) << 24 | |
581 | (e->tCL - 1) << 8 | | 548 | 0x16 << 16 | |
582 | (e->tCL - 1); | 549 | (e->tCL - 1) << 8 | |
583 | timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; | 550 | (e->tCL - 1); |
584 | timing->reg_5 |= (e->tCL + 2) << 8; | 551 | |
585 | timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16; | 552 | t->reg[4] |= boot->reg[4] & 0xffff0000; |
553 | |||
554 | t->reg[6] = (0x33 - t->tCWL) << 16 | | ||
555 | t->tCWL << 8 | | ||
556 | (0x2e + e->tCL - t->tCWL); | ||
557 | |||
558 | t->reg[7] = 0x4000202 | (e->tCL - 1) << 16; | ||
559 | |||
560 | /* XXX: P.version == 1 only has DDR2 and GDDR3? */ | ||
561 | if (dev_priv->vram_type == NV_MEM_TYPE_DDR2) { | ||
562 | t->reg[5] |= (e->tCL + 3) << 8; | ||
563 | t->reg[6] |= (t->tCWL - 2) << 8; | ||
564 | t->reg[8] |= (e->tCL - 4); | ||
565 | } else { | ||
566 | t->reg[5] |= (e->tCL + 2) << 8; | ||
567 | t->reg[6] |= t->tCWL << 8; | ||
568 | t->reg[8] |= (e->tCL - 2); | ||
569 | } | ||
586 | } else { | 570 | } else { |
587 | timing->reg_2 |= (unk19 - 1) << 24; | 571 | t->reg[1] |= (5 + e->tCL - (t->tCWL)); |
588 | /* XXX: reg_10022c for recentish cards pretty much unknown*/ | 572 | |
589 | timing->reg_3 = e->tCL - 1; | 573 | /* XXX: 0xb? 0x30? */ |
590 | timing->reg_4 = (unk20 << 24 | unk21 << 16 | | 574 | t->reg[3] = (0x30 + e->tCL) << 24 | |
591 | e->tUNK_13 << 8 | e->tUNK_13); | 575 | (boot->reg[3] & 0x00ff0000)| |
576 | (0xb + e->tCL) << 8 | | ||
577 | (e->tCL - 1); | ||
578 | |||
579 | t->reg[4] |= (unk20 << 24 | unk21 << 16); | ||
580 | |||
592 | /* XXX: +6? */ | 581 | /* XXX: +6? */ |
593 | timing->reg_5 |= (unk19 + 6) << 8; | 582 | t->reg[5] |= (t->tCWL + 6) << 8; |
594 | 583 | ||
595 | /* XXX: reg_10023c currently unknown | 584 | t->reg[6] = (0x5a + e->tCL) << 16 | |
596 | * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ | 585 | (6 - e->tCL + t->tCWL) << 8 | |
597 | timing->reg_7 = 0x202; | 586 | (0x50 + e->tCL - t->tCWL); |
587 | |||
588 | tmp7_3 = (boot->reg[7] & 0xff000000) >> 24; | ||
589 | t->reg[7] = (tmp7_3 << 24) | | ||
590 | ((tmp7_3 - 6 + e->tCL) << 16) | | ||
591 | 0x202; | ||
598 | } | 592 | } |
599 | 593 | ||
600 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, | 594 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", t->id, |
601 | timing->reg_0, timing->reg_1, | 595 | t->reg[0], t->reg[1], t->reg[2], t->reg[3]); |
602 | timing->reg_2, timing->reg_3); | ||
603 | NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", | 596 | NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", |
604 | timing->reg_4, timing->reg_5, | 597 | t->reg[4], t->reg[5], t->reg[6], t->reg[7]); |
605 | timing->reg_6, timing->reg_7); | 598 | NV_DEBUG(dev, " 240: %08x\n", t->reg[8]); |
606 | NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); | 599 | return 0; |
607 | } | 600 | } |
608 | 601 | ||
609 | void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | 602 | static int |
610 | struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { | 603 | nvc0_mem_timing_calc(struct drm_device *dev, u32 freq, |
611 | timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); | 604 | struct nouveau_pm_tbl_entry *e, u8 len, |
612 | timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f); | 605 | struct nouveau_pm_memtiming *boot, |
613 | timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8; | 606 | struct nouveau_pm_memtiming *t) |
614 | timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; | 607 | { |
615 | timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; | 608 | if (e->tCWL > 0) |
616 | NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, | 609 | t->tCWL = e->tCWL; |
617 | timing->reg_0, timing->reg_1, | 610 | |
618 | timing->reg_2, timing->reg_3); | 611 | t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 | |
619 | NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", | 612 | e->tRFC << 8 | e->tRC); |
620 | timing->reg_4, timing->reg_5, | 613 | |
621 | timing->reg_6, timing->reg_7); | 614 | t->reg[1] = (boot->reg[1] & 0xff000000) | |
615 | (e->tRCDWR & 0x0f) << 20 | | ||
616 | (e->tRCDRD & 0x0f) << 14 | | ||
617 | (t->tCWL << 7) | | ||
618 | (e->tCL & 0x0f); | ||
619 | |||
620 | t->reg[2] = (boot->reg[2] & 0xff0000ff) | | ||
621 | e->tWR << 16 | e->tWTR << 8; | ||
622 | |||
623 | t->reg[3] = (e->tUNK_20 & 0x1f) << 9 | | ||
624 | (e->tUNK_21 & 0xf) << 5 | | ||
625 | (e->tUNK_13 & 0x1f); | ||
626 | |||
627 | t->reg[4] = (boot->reg[4] & 0xfff00fff) | | ||
628 | (e->tRRD&0x1f) << 15; | ||
629 | |||
630 | NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", t->id, | ||
631 | t->reg[0], t->reg[1], t->reg[2], t->reg[3]); | ||
632 | NV_DEBUG(dev, " 2a0: %08x\n", t->reg[4]); | ||
633 | return 0; | ||
622 | } | 634 | } |
623 | 635 | ||
624 | /** | 636 | /** |
625 | * Processes the Memory Timing BIOS table, stores generated | 637 | * MR generation methods |
626 | * register values | ||
627 | * @pre init scripts were run, memtiming regs are initialized | ||
628 | */ | 638 | */ |
629 | void | 639 | |
630 | nouveau_mem_timing_init(struct drm_device *dev) | 640 | static int |
641 | nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq, | ||
642 | struct nouveau_pm_tbl_entry *e, u8 len, | ||
643 | struct nouveau_pm_memtiming *boot, | ||
644 | struct nouveau_pm_memtiming *t) | ||
645 | { | ||
646 | t->drive_strength = 0; | ||
647 | if (len < 15) { | ||
648 | t->odt = boot->odt; | ||
649 | } else { | ||
650 | t->odt = e->RAM_FT1 & 0x07; | ||
651 | } | ||
652 | |||
653 | if (e->tCL >= NV_MEM_CL_DDR2_MAX) { | ||
654 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | ||
655 | return -ERANGE; | ||
656 | } | ||
657 | |||
658 | if (e->tWR >= NV_MEM_WR_DDR2_MAX) { | ||
659 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | ||
660 | return -ERANGE; | ||
661 | } | ||
662 | |||
663 | if (t->odt > 3) { | ||
664 | NV_WARN(dev, "(%u) Invalid odt value, assuming disabled: %x", | ||
665 | t->id, t->odt); | ||
666 | t->odt = 0; | ||
667 | } | ||
668 | |||
669 | t->mr[0] = (boot->mr[0] & 0x100f) | | ||
670 | (e->tCL) << 4 | | ||
671 | (e->tWR - 1) << 9; | ||
672 | t->mr[1] = (boot->mr[1] & 0x101fbb) | | ||
673 | (t->odt & 0x1) << 2 | | ||
674 | (t->odt & 0x2) << 5; | ||
675 | |||
676 | NV_DEBUG(dev, "(%u) MR: %08x", t->id, t->mr[0]); | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = { | ||
681 | 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; | ||
682 | |||
683 | static int | ||
684 | nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq, | ||
685 | struct nouveau_pm_tbl_entry *e, u8 len, | ||
686 | struct nouveau_pm_memtiming *boot, | ||
687 | struct nouveau_pm_memtiming *t) | ||
688 | { | ||
689 | u8 cl = e->tCL - 4; | ||
690 | |||
691 | t->drive_strength = 0; | ||
692 | if (len < 15) { | ||
693 | t->odt = boot->odt; | ||
694 | } else { | ||
695 | t->odt = e->RAM_FT1 & 0x07; | ||
696 | } | ||
697 | |||
698 | if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) { | ||
699 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | ||
700 | return -ERANGE; | ||
701 | } | ||
702 | |||
703 | if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) { | ||
704 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | ||
705 | return -ERANGE; | ||
706 | } | ||
707 | |||
708 | if (e->tCWL < 5) { | ||
709 | NV_WARN(dev, "(%u) Invalid tCWL: %u", t->id, e->tCWL); | ||
710 | return -ERANGE; | ||
711 | } | ||
712 | |||
713 | t->mr[0] = (boot->mr[0] & 0x180b) | | ||
714 | /* CAS */ | ||
715 | (cl & 0x7) << 4 | | ||
716 | (cl & 0x8) >> 1 | | ||
717 | (nv_mem_wr_lut_ddr3[e->tWR]) << 9; | ||
718 | t->mr[1] = (boot->mr[1] & 0x101dbb) | | ||
719 | (t->odt & 0x1) << 2 | | ||
720 | (t->odt & 0x2) << 5 | | ||
721 | (t->odt & 0x4) << 7; | ||
722 | t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3; | ||
723 | |||
724 | NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]); | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = { | ||
729 | 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11}; | ||
730 | uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = { | ||
731 | 0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3}; | ||
732 | |||
733 | static int | ||
734 | nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq, | ||
735 | struct nouveau_pm_tbl_entry *e, u8 len, | ||
736 | struct nouveau_pm_memtiming *boot, | ||
737 | struct nouveau_pm_memtiming *t) | ||
738 | { | ||
739 | if (len < 15) { | ||
740 | t->drive_strength = boot->drive_strength; | ||
741 | t->odt = boot->odt; | ||
742 | } else { | ||
743 | t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; | ||
744 | t->odt = e->RAM_FT1 & 0x07; | ||
745 | } | ||
746 | |||
747 | if (e->tCL >= NV_MEM_CL_GDDR3_MAX) { | ||
748 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | ||
749 | return -ERANGE; | ||
750 | } | ||
751 | |||
752 | if (e->tWR >= NV_MEM_WR_GDDR3_MAX) { | ||
753 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | ||
754 | return -ERANGE; | ||
755 | } | ||
756 | |||
757 | if (t->odt > 3) { | ||
758 | NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x", | ||
759 | t->id, t->odt); | ||
760 | t->odt = 0; | ||
761 | } | ||
762 | |||
763 | t->mr[0] = (boot->mr[0] & 0xe0b) | | ||
764 | /* CAS */ | ||
765 | ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) | | ||
766 | ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2); | ||
767 | t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength | | ||
768 | (t->odt << 2) | | ||
769 | (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4; | ||
770 | t->mr[2] = boot->mr[2]; | ||
771 | |||
772 | NV_DEBUG(dev, "(%u) MR: %08x %08x %08x", t->id, | ||
773 | t->mr[0], t->mr[1], t->mr[2]); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static int | ||
778 | nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq, | ||
779 | struct nouveau_pm_tbl_entry *e, u8 len, | ||
780 | struct nouveau_pm_memtiming *boot, | ||
781 | struct nouveau_pm_memtiming *t) | ||
782 | { | ||
783 | if (len < 15) { | ||
784 | t->drive_strength = boot->drive_strength; | ||
785 | t->odt = boot->odt; | ||
786 | } else { | ||
787 | t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; | ||
788 | t->odt = e->RAM_FT1 & 0x03; | ||
789 | } | ||
790 | |||
791 | if (e->tCL >= NV_MEM_CL_GDDR5_MAX) { | ||
792 | NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL); | ||
793 | return -ERANGE; | ||
794 | } | ||
795 | |||
796 | if (e->tWR >= NV_MEM_WR_GDDR5_MAX) { | ||
797 | NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR); | ||
798 | return -ERANGE; | ||
799 | } | ||
800 | |||
801 | if (t->odt > 3) { | ||
802 | NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x", | ||
803 | t->id, t->odt); | ||
804 | t->odt = 0; | ||
805 | } | ||
806 | |||
807 | t->mr[0] = (boot->mr[0] & 0x007) | | ||
808 | ((e->tCL - 5) << 3) | | ||
809 | ((e->tWR - 4) << 8); | ||
810 | t->mr[1] = (boot->mr[1] & 0x1007f0) | | ||
811 | t->drive_strength | | ||
812 | (t->odt << 2); | ||
813 | |||
814 | NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]); | ||
815 | return 0; | ||
816 | } | ||
817 | |||
818 | int | ||
819 | nouveau_mem_timing_calc(struct drm_device *dev, u32 freq, | ||
820 | struct nouveau_pm_memtiming *t) | ||
631 | { | 821 | { |
632 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 822 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
633 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | 823 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; |
634 | struct nouveau_pm_memtimings *memtimings = &pm->memtimings; | 824 | struct nouveau_pm_memtiming *boot = &pm->boot.timing; |
635 | struct nvbios *bios = &dev_priv->vbios; | 825 | struct nouveau_pm_tbl_entry *e; |
636 | struct bit_entry P; | 826 | u8 ver, len, *ptr, *ramcfg; |
637 | struct nouveau_pm_tbl_header *hdr = NULL; | 827 | int ret; |
638 | uint8_t magic_number; | 828 | |
639 | u8 *entry; | 829 | ptr = nouveau_perf_timing(dev, freq, &ver, &len); |
640 | int i; | 830 | if (!ptr || ptr[0] == 0x00) { |
831 | *t = *boot; | ||
832 | return 0; | ||
833 | } | ||
834 | e = (struct nouveau_pm_tbl_entry *)ptr; | ||
835 | |||
836 | t->tCWL = boot->tCWL; | ||
837 | |||
838 | switch (dev_priv->card_type) { | ||
839 | case NV_40: | ||
840 | ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t); | ||
841 | break; | ||
842 | case NV_50: | ||
843 | ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t); | ||
844 | break; | ||
845 | case NV_C0: | ||
846 | ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t); | ||
847 | break; | ||
848 | default: | ||
849 | ret = -ENODEV; | ||
850 | break; | ||
851 | } | ||
641 | 852 | ||
642 | if (bios->type == NVBIOS_BIT) { | 853 | switch (dev_priv->vram_type * !ret) { |
643 | if (bit_table(dev, 'P', &P)) | 854 | case NV_MEM_TYPE_GDDR3: |
644 | return; | 855 | ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t); |
856 | break; | ||
857 | case NV_MEM_TYPE_GDDR5: | ||
858 | ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t); | ||
859 | break; | ||
860 | case NV_MEM_TYPE_DDR2: | ||
861 | ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t); | ||
862 | break; | ||
863 | case NV_MEM_TYPE_DDR3: | ||
864 | ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t); | ||
865 | break; | ||
866 | default: | ||
867 | ret = -EINVAL; | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | ramcfg = nouveau_perf_ramcfg(dev, freq, &ver, &len); | ||
872 | if (ramcfg) { | ||
873 | int dll_off; | ||
645 | 874 | ||
646 | if (P.version == 1) | 875 | if (ver == 0x00) |
647 | hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[4]); | 876 | dll_off = !!(ramcfg[3] & 0x04); |
648 | else | 877 | else |
649 | if (P.version == 2) | 878 | dll_off = !!(ramcfg[2] & 0x40); |
650 | hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[8]); | 879 | |
651 | else { | 880 | switch (dev_priv->vram_type) { |
652 | NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); | 881 | case NV_MEM_TYPE_GDDR3: |
882 | t->mr[1] &= ~0x00000040; | ||
883 | t->mr[1] |= 0x00000040 * dll_off; | ||
884 | break; | ||
885 | default: | ||
886 | t->mr[1] &= ~0x00000001; | ||
887 | t->mr[1] |= 0x00000001 * dll_off; | ||
888 | break; | ||
653 | } | 889 | } |
890 | } | ||
891 | |||
892 | return ret; | ||
893 | } | ||
894 | |||
895 | void | ||
896 | nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t) | ||
897 | { | ||
898 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
899 | u32 timing_base, timing_regs, mr_base; | ||
900 | int i; | ||
901 | |||
902 | if (dev_priv->card_type >= 0xC0) { | ||
903 | timing_base = 0x10f290; | ||
904 | mr_base = 0x10f300; | ||
654 | } else { | 905 | } else { |
655 | NV_DEBUG(dev, "BMP version too old for memory\n"); | 906 | timing_base = 0x100220; |
656 | return; | 907 | mr_base = 0x1002c0; |
657 | } | 908 | } |
658 | 909 | ||
659 | if (!hdr) { | 910 | t->id = -1; |
660 | NV_DEBUG(dev, "memory timing table pointer invalid\n"); | 911 | |
912 | switch (dev_priv->card_type) { | ||
913 | case NV_50: | ||
914 | timing_regs = 9; | ||
915 | break; | ||
916 | case NV_C0: | ||
917 | case NV_D0: | ||
918 | timing_regs = 5; | ||
919 | break; | ||
920 | case NV_30: | ||
921 | case NV_40: | ||
922 | timing_regs = 3; | ||
923 | break; | ||
924 | default: | ||
925 | timing_regs = 0; | ||
661 | return; | 926 | return; |
662 | } | 927 | } |
928 | for(i = 0; i < timing_regs; i++) | ||
929 | t->reg[i] = nv_rd32(dev, timing_base + (0x04 * i)); | ||
930 | |||
931 | t->tCWL = 0; | ||
932 | if (dev_priv->card_type < NV_C0) { | ||
933 | t->tCWL = ((nv_rd32(dev, 0x100228) & 0x0f000000) >> 24) + 1; | ||
934 | } else if (dev_priv->card_type <= NV_D0) { | ||
935 | t->tCWL = ((nv_rd32(dev, 0x10f294) & 0x00000f80) >> 7); | ||
936 | } | ||
663 | 937 | ||
664 | if (hdr->version != 0x10) { | 938 | t->mr[0] = nv_rd32(dev, mr_base); |
665 | NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); | 939 | t->mr[1] = nv_rd32(dev, mr_base + 0x04); |
666 | return; | 940 | t->mr[2] = nv_rd32(dev, mr_base + 0x20); |
941 | t->mr[3] = nv_rd32(dev, mr_base + 0x24); | ||
942 | |||
943 | t->odt = 0; | ||
944 | t->drive_strength = 0; | ||
945 | |||
946 | switch (dev_priv->vram_type) { | ||
947 | case NV_MEM_TYPE_DDR3: | ||
948 | t->odt |= (t->mr[1] & 0x200) >> 7; | ||
949 | case NV_MEM_TYPE_DDR2: | ||
950 | t->odt |= (t->mr[1] & 0x04) >> 2 | | ||
951 | (t->mr[1] & 0x40) >> 5; | ||
952 | break; | ||
953 | case NV_MEM_TYPE_GDDR3: | ||
954 | case NV_MEM_TYPE_GDDR5: | ||
955 | t->drive_strength = t->mr[1] & 0x03; | ||
956 | t->odt = (t->mr[1] & 0x0c) >> 2; | ||
957 | break; | ||
958 | default: | ||
959 | break; | ||
667 | } | 960 | } |
961 | } | ||
668 | 962 | ||
669 | /* validate record length */ | 963 | int |
670 | if (hdr->entry_len < 15) { | 964 | nouveau_mem_exec(struct nouveau_mem_exec_func *exec, |
671 | NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); | 965 | struct nouveau_pm_level *perflvl) |
672 | return; | 966 | { |
967 | struct drm_nouveau_private *dev_priv = exec->dev->dev_private; | ||
968 | struct nouveau_pm_memtiming *info = &perflvl->timing; | ||
969 | u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0; | ||
970 | u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] }; | ||
971 | u32 mr1_dlloff; | ||
972 | |||
973 | switch (dev_priv->vram_type) { | ||
974 | case NV_MEM_TYPE_DDR2: | ||
975 | tDLLK = 2000; | ||
976 | mr1_dlloff = 0x00000001; | ||
977 | break; | ||
978 | case NV_MEM_TYPE_DDR3: | ||
979 | tDLLK = 12000; | ||
980 | mr1_dlloff = 0x00000001; | ||
981 | break; | ||
982 | case NV_MEM_TYPE_GDDR3: | ||
983 | tDLLK = 40000; | ||
984 | mr1_dlloff = 0x00000040; | ||
985 | break; | ||
986 | default: | ||
987 | NV_ERROR(exec->dev, "cannot reclock unsupported memtype\n"); | ||
988 | return -ENODEV; | ||
673 | } | 989 | } |
674 | 990 | ||
675 | /* parse vbios entries into common format */ | 991 | /* fetch current MRs */ |
676 | memtimings->timing = | 992 | switch (dev_priv->vram_type) { |
677 | kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); | 993 | case NV_MEM_TYPE_GDDR3: |
678 | if (!memtimings->timing) | 994 | case NV_MEM_TYPE_DDR3: |
679 | return; | 995 | mr[2] = exec->mrg(exec, 2); |
996 | default: | ||
997 | mr[1] = exec->mrg(exec, 1); | ||
998 | mr[0] = exec->mrg(exec, 0); | ||
999 | break; | ||
1000 | } | ||
680 | 1001 | ||
681 | /* Get "some number" from the timing reg for NV_40 and NV_50 | 1002 | /* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh */ |
682 | * Used in calculations later... source unknown */ | 1003 | if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) { |
683 | magic_number = 0; | 1004 | exec->precharge(exec); |
684 | if (P.version == 1) { | 1005 | exec->mrs (exec, 1, mr[1] | mr1_dlloff); |
685 | magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; | 1006 | exec->wait(exec, tMRD); |
686 | } | 1007 | } |
687 | 1008 | ||
688 | entry = (u8*) hdr + hdr->header_len; | 1009 | /* enter self-refresh mode */ |
689 | for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { | 1010 | exec->precharge(exec); |
690 | struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; | 1011 | exec->refresh(exec); |
691 | if (entry[0] == 0) | 1012 | exec->refresh(exec); |
692 | continue; | 1013 | exec->refresh_auto(exec, false); |
1014 | exec->refresh_self(exec, true); | ||
1015 | exec->wait(exec, tCKSRE); | ||
1016 | |||
1017 | /* modify input clock frequency */ | ||
1018 | exec->clock_set(exec); | ||
1019 | |||
1020 | /* exit self-refresh mode */ | ||
1021 | exec->wait(exec, tCKSRX); | ||
1022 | exec->precharge(exec); | ||
1023 | exec->refresh_self(exec, false); | ||
1024 | exec->refresh_auto(exec, true); | ||
1025 | exec->wait(exec, tXS); | ||
1026 | |||
1027 | /* update MRs */ | ||
1028 | if (mr[2] != info->mr[2]) { | ||
1029 | exec->mrs (exec, 2, info->mr[2]); | ||
1030 | exec->wait(exec, tMRD); | ||
1031 | } | ||
1032 | |||
1033 | if (mr[1] != info->mr[1]) { | ||
1034 | /* need to keep DLL off until later, at least on GDDR3 */ | ||
1035 | exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff)); | ||
1036 | exec->wait(exec, tMRD); | ||
1037 | } | ||
1038 | |||
1039 | if (mr[0] != info->mr[0]) { | ||
1040 | exec->mrs (exec, 0, info->mr[0]); | ||
1041 | exec->wait(exec, tMRD); | ||
1042 | } | ||
693 | 1043 | ||
694 | timing->id = i; | 1044 | /* update PFB timing registers */ |
695 | timing->WR = entry[0]; | 1045 | exec->timing_set(exec); |
696 | timing->CL = entry[2]; | ||
697 | 1046 | ||
698 | if(dev_priv->card_type <= NV_40) { | 1047 | /* DLL (enable + ) reset */ |
699 | nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); | 1048 | if (!(info->mr[1] & mr1_dlloff)) { |
700 | } else if(dev_priv->card_type == NV_50){ | 1049 | if (mr[1] & mr1_dlloff) { |
701 | nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); | 1050 | exec->mrs (exec, 1, info->mr[1]); |
702 | } else if(dev_priv->card_type == NV_C0) { | 1051 | exec->wait(exec, tMRD); |
703 | nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); | ||
704 | } | 1052 | } |
1053 | exec->mrs (exec, 0, info->mr[0] | 0x00000100); | ||
1054 | exec->wait(exec, tMRD); | ||
1055 | exec->mrs (exec, 0, info->mr[0] | 0x00000000); | ||
1056 | exec->wait(exec, tMRD); | ||
1057 | exec->wait(exec, tDLLK); | ||
1058 | if (dev_priv->vram_type == NV_MEM_TYPE_GDDR3) | ||
1059 | exec->precharge(exec); | ||
705 | } | 1060 | } |
706 | 1061 | ||
707 | memtimings->nr_timing = hdr->entry_cnt; | 1062 | return 0; |
708 | memtimings->supported = P.version == 1; | ||
709 | } | 1063 | } |
710 | 1064 | ||
711 | void | 1065 | int |
712 | nouveau_mem_timing_fini(struct drm_device *dev) | 1066 | nouveau_mem_vbios_type(struct drm_device *dev) |
713 | { | 1067 | { |
714 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 1068 | struct bit_entry M; |
715 | struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; | 1069 | u8 ramcfg = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2; |
1070 | if (!bit_table(dev, 'M', &M) || M.version != 2 || M.length < 5) { | ||
1071 | u8 *table = ROMPTR(dev, M.data[3]); | ||
1072 | if (table && table[0] == 0x10 && ramcfg < table[3]) { | ||
1073 | u8 *entry = table + table[1] + (ramcfg * table[2]); | ||
1074 | switch (entry[0] & 0x0f) { | ||
1075 | case 0: return NV_MEM_TYPE_DDR2; | ||
1076 | case 1: return NV_MEM_TYPE_DDR3; | ||
1077 | case 2: return NV_MEM_TYPE_GDDR3; | ||
1078 | case 3: return NV_MEM_TYPE_GDDR5; | ||
1079 | default: | ||
1080 | break; | ||
1081 | } | ||
716 | 1082 | ||
717 | if(mem->timing) { | 1083 | } |
718 | kfree(mem->timing); | ||
719 | mem->timing = NULL; | ||
720 | } | 1084 | } |
1085 | return NV_MEM_TYPE_UNKNOWN; | ||
721 | } | 1086 | } |
722 | 1087 | ||
723 | static int | 1088 | static int |