diff options
author | Roy Spliet <r.spliet@student.tudelft.nl> | 2011-07-09 15:18:11 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:08:25 -0400 |
commit | 9a7824887690836448eb73ccf0d8232da2e5bee3 (patch) | |
tree | 1ff9018bd20a87724db585c2329e30d33e101cdf /drivers/gpu | |
parent | 1cb70b30e4c6f25cf69ec0ab33db0218490f928d (diff) |
drm/nouveau/pm: add initial NV3x/NVCx memtiming support, improve other cards
NV30: Create framework for memtm
NV50: Improve reg creation,
NV50: Use P.version instead of card codename/stepping,
NVC0: Initial memtiming code for Fermi,
Renamed regs for consistency,
Overall redesign to improve readability,
Avoid kfree on null-pointer
Signed-off-by: Roy Spliet <r.spliet@student.tudelft.nl>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 278 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_perf.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 2 |
4 files changed, 206 insertions, 143 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e5d4e7d291bc..7991c1b3b911 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -429,17 +429,43 @@ struct nouveau_pm_voltage { | |||
429 | 429 | ||
430 | struct nouveau_pm_memtiming { | 430 | struct nouveau_pm_memtiming { |
431 | int id; | 431 | int id; |
432 | u32 reg_100220; | 432 | u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */ |
433 | u32 reg_100224; | 433 | u32 reg_1; |
434 | u32 reg_100228; | 434 | u32 reg_2; |
435 | u32 reg_10022c; | 435 | u32 reg_3; |
436 | u32 reg_100230; | 436 | u32 reg_4; |
437 | u32 reg_100234; | 437 | u32 reg_5; |
438 | u32 reg_100238; | 438 | u32 reg_6; |
439 | u32 reg_10023c; | 439 | u32 reg_7; |
440 | u32 reg_100240; | 440 | u32 reg_8; |
441 | }; | 441 | }; |
442 | 442 | ||
443 | struct nouveau_pm_tbl_header{ | ||
444 | u8 version; | ||
445 | u8 header_len; | ||
446 | u8 entry_cnt; | ||
447 | u8 entry_len; | ||
448 | }; | ||
449 | |||
450 | struct nouveau_pm_tbl_entry{ | ||
451 | u8 tUNK_0, tUNK_1, tUNK_2; | ||
452 | u8 tRP; /* Byte 3 */ | ||
453 | u8 empty_4; | ||
454 | u8 tRAS; /* Byte 5 */ | ||
455 | u8 empty_6; | ||
456 | u8 tRFC; /* Byte 7 */ | ||
457 | u8 empty_8; | ||
458 | u8 tRC; /* Byte 9 */ | ||
459 | u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; | ||
460 | u8 empty_15,empty_16,empty_17; | ||
461 | u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; | ||
462 | }; | ||
463 | |||
464 | /* nouveau_mem.c */ | ||
465 | void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | ||
466 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number, | ||
467 | struct nouveau_pm_memtiming *timing); | ||
468 | |||
443 | #define NOUVEAU_PM_MAX_LEVEL 8 | 469 | #define NOUVEAU_PM_MAX_LEVEL 8 |
444 | struct nouveau_pm_level { | 470 | struct nouveau_pm_level { |
445 | struct device_attribute dev_attr; | 471 | struct device_attribute dev_attr; |
@@ -648,7 +674,6 @@ struct drm_nouveau_private { | |||
648 | enum nouveau_card_type card_type; | 674 | enum nouveau_card_type card_type; |
649 | /* exact chipset, derived from NV_PMC_BOOT_0 */ | 675 | /* exact chipset, derived from NV_PMC_BOOT_0 */ |
650 | int chipset; | 676 | int chipset; |
651 | int stepping; | ||
652 | int flags; | 677 | int flags; |
653 | 678 | ||
654 | void __iomem *mmio; | 679 | void __iomem *mmio; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index bd3c39f69388..65c12ed14257 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -502,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev) | |||
502 | return 0; | 502 | return 0; |
503 | } | 503 | } |
504 | 504 | ||
505 | /* XXX: For now a dummy. More samples required, possibly even a card | ||
506 | * Called from nouveau_perf.c */ | ||
507 | void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | ||
508 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number, | ||
509 | struct nouveau_pm_memtiming *timing) { | ||
510 | |||
511 | NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); | ||
512 | } | ||
513 | |||
514 | void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | ||
515 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number, | ||
516 | struct nouveau_pm_memtiming *timing) { | ||
517 | |||
518 | timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); | ||
519 | |||
520 | /* XXX: I don't trust the -1's and +1's... they must come | ||
521 | * from somewhere! */ | ||
522 | timing->reg_1 = (e->tUNK_0 + 2 + magic_number) << 24 | | ||
523 | 1 << 16 | | ||
524 | (e->tUNK_1 + 2 + magic_number) << 8 | | ||
525 | (e->tUNK_2 + 2 - magic_number); | ||
526 | timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); | ||
527 | timing->reg_2 |= 0x20200000; | ||
528 | |||
529 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, | ||
530 | timing->reg_0, timing->reg_1,timing->reg_2); | ||
531 | } | ||
532 | |||
533 | void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, | ||
534 | struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { | ||
535 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
536 | |||
537 | uint8_t unk18 = 1, | ||
538 | unk19 = 1, | ||
539 | unk20 = 0, | ||
540 | unk21 = 0; | ||
541 | |||
542 | switch (min(hdr->entry_len, (u8) 22)) { | ||
543 | case 22: | ||
544 | unk21 = e->tUNK_21; | ||
545 | case 21: | ||
546 | unk20 = e->tUNK_20; | ||
547 | case 20: | ||
548 | unk19 = e->tUNK_19; | ||
549 | case 19: | ||
550 | unk18 = e->tUNK_18; | ||
551 | break; | ||
552 | } | ||
553 | |||
554 | timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); | ||
555 | |||
556 | /* XXX: I don't trust the -1's and +1's... they must come | ||
557 | * from somewhere! */ | ||
558 | timing->reg_1 = (e->tUNK_0 + unk19 + 1 + magic_number) << 24 | | ||
559 | max(unk18, (u8) 1) << 16 | | ||
560 | (e->tUNK_1 + unk19 + 1 + magic_number) << 8; | ||
561 | if (dev_priv->chipset == 0xa8) { | ||
562 | timing->reg_1 |= (e->tUNK_2 - 1); | ||
563 | } else { | ||
564 | timing->reg_1 |= (e->tUNK_2 + 2 - magic_number); | ||
565 | } | ||
566 | timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); | ||
567 | |||
568 | timing->reg_5 = (e->tRAS << 24 | e->tRC); | ||
569 | timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; | ||
570 | |||
571 | if (P->version == 1) { | ||
572 | timing->reg_2 |= magic_number << 24; | ||
573 | timing->reg_3 = (0x14 + e->tUNK_2) << 24 | | ||
574 | 0x16 << 16 | | ||
575 | (e->tUNK_2 - 1) << 8 | | ||
576 | (e->tUNK_2 - 1); | ||
577 | timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; | ||
578 | timing->reg_5 |= (e->tUNK_2 + 2) << 8; | ||
579 | timing->reg_7 = 0x4000202 | (e->tUNK_2 - 1) << 16; | ||
580 | } else { | ||
581 | timing->reg_2 |= (unk19 - 1) << 24; | ||
582 | /* XXX: reg_10022c for recentish cards pretty much unknown*/ | ||
583 | timing->reg_3 = e->tUNK_2 - 1; | ||
584 | timing->reg_4 = (unk20 << 24 | unk21 << 16 | | ||
585 | e->tUNK_13 << 8 | e->tUNK_13); | ||
586 | /* XXX: +6? */ | ||
587 | timing->reg_5 |= (unk19 + 6) << 8; | ||
588 | |||
589 | /* XXX: reg_10023c currently unknown | ||
590 | * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ | ||
591 | timing->reg_7 = 0x202; | ||
592 | } | ||
593 | |||
594 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, | ||
595 | timing->reg_0, timing->reg_1, | ||
596 | timing->reg_2, timing->reg_3); | ||
597 | NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", | ||
598 | timing->reg_4, timing->reg_5, | ||
599 | timing->reg_6, timing->reg_7); | ||
600 | NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); | ||
601 | } | ||
602 | |||
603 | void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, | ||
604 | struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { | ||
605 | timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); | ||
606 | timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tUNK_2 & 0x0f); | ||
607 | timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tUNK_0 << 16 | e->tUNK_1 << 8; | ||
608 | timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; | ||
609 | timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; | ||
610 | NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, | ||
611 | timing->reg_0, timing->reg_1, | ||
612 | timing->reg_2, timing->reg_3); | ||
613 | NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", | ||
614 | timing->reg_4, timing->reg_5, | ||
615 | timing->reg_6, timing->reg_7); | ||
616 | } | ||
617 | |||
618 | /** | ||
619 | * Processes the Memory Timing BIOS table, stores generated | ||
620 | * register values | ||
621 | * @pre init scripts were run, memtiming regs are initialized | ||
622 | */ | ||
505 | void | 623 | void |
506 | nouveau_mem_timing_init(struct drm_device *dev) | 624 | nouveau_mem_timing_init(struct drm_device *dev) |
507 | { | 625 | { |
508 | /* cards < NVC0 only */ | ||
509 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 626 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
510 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | 627 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; |
511 | struct nouveau_pm_memtimings *memtimings = &pm->memtimings; | 628 | struct nouveau_pm_memtimings *memtimings = &pm->memtimings; |
512 | struct nvbios *bios = &dev_priv->vbios; | 629 | struct nvbios *bios = &dev_priv->vbios; |
513 | struct bit_entry P; | 630 | struct bit_entry P; |
514 | u8 tUNK_0, tUNK_1, tUNK_2; | 631 | struct nouveau_pm_tbl_header *hdr = NULL; |
515 | u8 tRP; /* Byte 3 */ | 632 | uint8_t magic_number; |
516 | u8 tRAS; /* Byte 5 */ | 633 | u8 *entry; |
517 | u8 tRFC; /* Byte 7 */ | 634 | int i; |
518 | u8 tRC; /* Byte 9 */ | ||
519 | u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; | ||
520 | u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; | ||
521 | u8 magic_number = 0; /* Yeah... sorry*/ | ||
522 | u8 *mem = NULL, *entry; | ||
523 | int i, recordlen, entries; | ||
524 | 635 | ||
525 | if (bios->type == NVBIOS_BIT) { | 636 | if (bios->type == NVBIOS_BIT) { |
526 | if (bit_table(dev, 'P', &P)) | 637 | if (bit_table(dev, 'P', &P)) |
527 | return; | 638 | return; |
528 | 639 | ||
529 | if (P.version == 1) | 640 | if (P.version == 1) |
530 | mem = ROMPTR(bios, P.data[4]); | 641 | hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]); |
531 | else | 642 | else |
532 | if (P.version == 2) | 643 | if (P.version == 2) |
533 | mem = ROMPTR(bios, P.data[8]); | 644 | hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]); |
534 | else { | 645 | else { |
535 | NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); | 646 | NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); |
536 | } | 647 | } |
@@ -539,150 +650,54 @@ nouveau_mem_timing_init(struct drm_device *dev) | |||
539 | return; | 650 | return; |
540 | } | 651 | } |
541 | 652 | ||
542 | if (!mem) { | 653 | if (!hdr) { |
543 | NV_DEBUG(dev, "memory timing table pointer invalid\n"); | 654 | NV_DEBUG(dev, "memory timing table pointer invalid\n"); |
544 | return; | 655 | return; |
545 | } | 656 | } |
546 | 657 | ||
547 | if (mem[0] != 0x10) { | 658 | if (hdr->version != 0x10) { |
548 | NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]); | 659 | NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); |
549 | return; | 660 | return; |
550 | } | 661 | } |
551 | 662 | ||
552 | /* validate record length */ | 663 | /* validate record length */ |
553 | entries = mem[2]; | 664 | if (hdr->entry_len < 15) { |
554 | recordlen = mem[3]; | 665 | NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); |
555 | if (recordlen < 15) { | ||
556 | NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]); | ||
557 | return; | 666 | return; |
558 | } | 667 | } |
559 | 668 | ||
560 | /* parse vbios entries into common format */ | 669 | /* parse vbios entries into common format */ |
561 | memtimings->timing = | 670 | memtimings->timing = |
562 | kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); | 671 | kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); |
563 | if (!memtimings->timing) | 672 | if (!memtimings->timing) |
564 | return; | 673 | return; |
565 | 674 | ||
566 | /* Get "some number" from the timing reg for NV_40 and NV_50 | 675 | /* Get "some number" from the timing reg for NV_40 and NV_50 |
567 | * Used in calculations later */ | 676 | * Used in calculations later... source unknown */ |
568 | if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { | 677 | magic_number = 0; |
678 | if (P.version == 1) { | ||
569 | magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; | 679 | magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; |
570 | } | 680 | } |
571 | 681 | ||
572 | entry = mem + mem[1]; | 682 | entry = (u8*) hdr + hdr->header_len; |
573 | for (i = 0; i < entries; i++, entry += recordlen) { | 683 | for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { |
574 | struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; | 684 | struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; |
575 | if (entry[0] == 0) | 685 | if (entry[0] == 0) |
576 | continue; | 686 | continue; |
577 | 687 | ||
578 | tUNK_18 = 1; | ||
579 | tUNK_19 = 1; | ||
580 | tUNK_20 = 0; | ||
581 | tUNK_21 = 0; | ||
582 | switch (min(recordlen, 22)) { | ||
583 | case 22: | ||
584 | tUNK_21 = entry[21]; | ||
585 | case 21: | ||
586 | tUNK_20 = entry[20]; | ||
587 | case 20: | ||
588 | tUNK_19 = entry[19]; | ||
589 | case 19: | ||
590 | tUNK_18 = entry[18]; | ||
591 | default: | ||
592 | tUNK_0 = entry[0]; | ||
593 | tUNK_1 = entry[1]; | ||
594 | tUNK_2 = entry[2]; | ||
595 | tRP = entry[3]; | ||
596 | tRAS = entry[5]; | ||
597 | tRFC = entry[7]; | ||
598 | tRC = entry[9]; | ||
599 | tUNK_10 = entry[10]; | ||
600 | tUNK_11 = entry[11]; | ||
601 | tUNK_12 = entry[12]; | ||
602 | tUNK_13 = entry[13]; | ||
603 | tUNK_14 = entry[14]; | ||
604 | break; | ||
605 | } | ||
606 | |||
607 | timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP); | ||
608 | |||
609 | /* XXX: I don't trust the -1's and +1's... they must come | ||
610 | * from somewhere! */ | ||
611 | timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | | ||
612 | max(tUNK_18, (u8) 1) << 16 | | ||
613 | (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; | ||
614 | if (dev_priv->chipset == 0xa8) { | ||
615 | timing->reg_100224 |= (tUNK_2 - 1); | ||
616 | } else { | ||
617 | timing->reg_100224 |= (tUNK_2 + 2 - magic_number); | ||
618 | } | ||
619 | |||
620 | timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); | ||
621 | if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) | ||
622 | timing->reg_100228 |= (tUNK_19 - 1) << 24; | ||
623 | else | ||
624 | timing->reg_100228 |= magic_number << 24; | ||
625 | |||
626 | if (dev_priv->card_type == NV_40) { | ||
627 | /* NV40: don't know what the rest of the regs are.. | ||
628 | * And don't need to know either */ | ||
629 | timing->reg_100228 |= 0x20200000; | ||
630 | } else if (dev_priv->card_type >= NV_50) { | ||
631 | if (dev_priv->chipset < 0x98 || | ||
632 | (dev_priv->chipset == 0x98 && | ||
633 | dev_priv->stepping <= 0xa1)) { | ||
634 | timing->reg_10022c = (0x14 + tUNK_2) << 24 | | ||
635 | 0x16 << 16 | | ||
636 | (tUNK_2 - 1) << 8 | | ||
637 | (tUNK_2 - 1); | ||
638 | } else { | ||
639 | /* XXX: reg_10022c for recentish cards */ | ||
640 | timing->reg_10022c = tUNK_2 - 1; | ||
641 | } | ||
642 | |||
643 | timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | | ||
644 | tUNK_13 << 8 | tUNK_13); | ||
645 | |||
646 | timing->reg_100234 = (tRAS << 24 | tRC); | ||
647 | timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; | ||
648 | |||
649 | if (dev_priv->chipset < 0x98 || | ||
650 | (dev_priv->chipset == 0x98 && | ||
651 | dev_priv->stepping <= 0xa1)) { | ||
652 | timing->reg_100234 |= (tUNK_2 + 2) << 8; | ||
653 | } else { | ||
654 | /* XXX: +6? */ | ||
655 | timing->reg_100234 |= (tUNK_19 + 6) << 8; | ||
656 | } | ||
657 | |||
658 | /* XXX; reg_100238 | ||
659 | * reg_100238: 0x00?????? */ | ||
660 | timing->reg_10023c = 0x202; | ||
661 | if (dev_priv->chipset < 0x98 || | ||
662 | (dev_priv->chipset == 0x98 && | ||
663 | dev_priv->stepping <= 0xa1)) { | ||
664 | timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; | ||
665 | } else { | ||
666 | /* XXX: reg_10023c | ||
667 | * currently unknown | ||
668 | * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ | ||
669 | } | ||
670 | |||
671 | /* XXX: reg_100240? */ | ||
672 | } | ||
673 | timing->id = i; | 688 | timing->id = i; |
674 | 689 | ||
675 | NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, | 690 | if(dev_priv->card_type <= NV_40) { |
676 | timing->reg_100220, timing->reg_100224, | 691 | nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); |
677 | timing->reg_100228, timing->reg_10022c); | 692 | } else if(dev_priv->card_type == NV_50){ |
678 | NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", | 693 | nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); |
679 | timing->reg_100230, timing->reg_100234, | 694 | } else if(dev_priv->card_type == NV_C0) { |
680 | timing->reg_100238, timing->reg_10023c); | 695 | nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); |
681 | NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); | 696 | } |
682 | } | 697 | } |
683 | 698 | ||
684 | memtimings->nr_timing = entries; | 699 | memtimings->nr_timing = hdr->entry_cnt; |
685 | memtimings->supported = (dev_priv->chipset <= 0x98); | 700 | memtimings->supported = P.version == 1; |
686 | } | 701 | } |
687 | 702 | ||
688 | void | 703 | void |
@@ -691,7 +706,10 @@ nouveau_mem_timing_fini(struct drm_device *dev) | |||
691 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 706 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
692 | struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; | 707 | struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; |
693 | 708 | ||
694 | kfree(mem->timing); | 709 | if(mem->timing) { |
710 | kfree(mem->timing); | ||
711 | mem->timing = NULL; | ||
712 | } | ||
695 | } | 713 | } |
696 | 714 | ||
697 | static int | 715 | static int |
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index b4327dad6e56..854ca8573168 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c | |||
@@ -185,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev) | |||
185 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | 185 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; |
186 | struct nvbios *bios = &dev_priv->vbios; | 186 | struct nvbios *bios = &dev_priv->vbios; |
187 | struct bit_entry P; | 187 | struct bit_entry P; |
188 | struct nouveau_pm_memtimings *memtimings = &pm->memtimings; | ||
189 | struct nouveau_pm_tbl_header mt_hdr; | ||
188 | u8 version, headerlen, recordlen, entries; | 190 | u8 version, headerlen, recordlen, entries; |
189 | u8 *perf, *entry; | 191 | u8 *perf, *entry; |
190 | int vid, i; | 192 | int vid, i; |
@@ -232,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev) | |||
232 | } | 234 | } |
233 | 235 | ||
234 | entry = perf + headerlen; | 236 | entry = perf + headerlen; |
237 | |||
238 | /* For version 0x15, initialize memtiming table */ | ||
239 | if(version == 0x15) { | ||
240 | memtimings->timing = | ||
241 | kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); | ||
242 | if(!memtimings) { | ||
243 | NV_WARN(dev,"Could not allocate memtiming table\n"); | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | mt_hdr.entry_cnt = entries; | ||
248 | mt_hdr.entry_len = 14; | ||
249 | mt_hdr.version = version; | ||
250 | mt_hdr.header_len = 4; | ||
251 | } | ||
252 | |||
235 | for (i = 0; i < entries; i++) { | 253 | for (i = 0; i < entries; i++) { |
236 | struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; | 254 | struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; |
237 | 255 | ||
@@ -321,7 +339,11 @@ nouveau_perf_init(struct drm_device *dev) | |||
321 | } | 339 | } |
322 | 340 | ||
323 | /* get the corresponding memory timings */ | 341 | /* get the corresponding memory timings */ |
324 | if (version > 0x15) { | 342 | if (version == 0x15) { |
343 | memtimings->timing[i].id = i; | ||
344 | nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]); | ||
345 | perflvl->timing = &memtimings->timing[i]; | ||
346 | } else if (version > 0x15) { | ||
325 | /* last 3 args are for < 0x40, ignored for >= 0x40 */ | 347 | /* last 3 args are for < 0x40, ignored for >= 0x40 */ |
326 | perflvl->timing = | 348 | perflvl->timing = |
327 | nouveau_perf_timing(dev, &P, | 349 | nouveau_perf_timing(dev, &P, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index fd8287ef2f86..f1047254e820 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -1028,13 +1028,11 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) | |||
1028 | 1028 | ||
1029 | /* Time to determine the card architecture */ | 1029 | /* Time to determine the card architecture */ |
1030 | reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); | 1030 | reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); |
1031 | dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ | ||
1032 | 1031 | ||
1033 | /* We're dealing with >=NV10 */ | 1032 | /* We're dealing with >=NV10 */ |
1034 | if ((reg0 & 0x0f000000) > 0) { | 1033 | if ((reg0 & 0x0f000000) > 0) { |
1035 | /* Bit 27-20 contain the architecture in hex */ | 1034 | /* Bit 27-20 contain the architecture in hex */ |
1036 | dev_priv->chipset = (reg0 & 0xff00000) >> 20; | 1035 | dev_priv->chipset = (reg0 & 0xff00000) >> 20; |
1037 | dev_priv->stepping = (reg0 & 0xff); | ||
1038 | /* NV04 or NV05 */ | 1036 | /* NV04 or NV05 */ |
1039 | } else if ((reg0 & 0xff00fff0) == 0x20004000) { | 1037 | } else if ((reg0 & 0xff00fff0) == 0x20004000) { |
1040 | if (reg0 & 0x00f00000) | 1038 | if (reg0 & 0x00f00000) |