aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorRoy Spliet <r.spliet@student.tudelft.nl>2010-09-17 17:17:24 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-10-04 19:57:32 -0400
commit7760fcb020b41352af4e675ce65a6aa0e93c170f (patch)
treed978de4a7f9d53f152c944f7254fdd0d90901b47 /drivers/gpu/drm
parent5b32165b044f7d2486e2815456b1b2894aaab4ee (diff)
drm/nouveau: Import initial memory timing work
This isn't correct everywhere yet, but since we don't use the data yet it's perfectly safe to push in, and the information we gain from logs will help to fix the remaining issues. v2 (Ben Skeggs <bskeggs@redhat.com>): - fixed up formatting - free parsed timing info on takedown - switched timing table printout to debug loglevel Signed-off-by: Roy Spliet <r.spliet@student.tudelft.nl> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c144
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h4
4 files changed, 169 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 799cd149745d..e1fb2c95eb90 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -401,10 +401,28 @@ struct nouveau_pm_threshold_temp {
401 s16 fan_boost; 401 s16 fan_boost;
402}; 402};
403 403
404struct nouveau_pm_memtiming {
405 u32 reg_100220;
406 u32 reg_100224;
407 u32 reg_100228;
408 u32 reg_10022c;
409 u32 reg_100230;
410 u32 reg_100234;
411 u32 reg_100238;
412 u32 reg_10023c;
413};
414
415struct nouveau_pm_memtimings {
416 bool supported;
417 struct nouveau_pm_memtiming *timing;
418 int nr_timing;
419};
420
404struct nouveau_pm_engine { 421struct nouveau_pm_engine {
405 struct nouveau_pm_voltage voltage; 422 struct nouveau_pm_voltage voltage;
406 struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL]; 423 struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
407 int nr_perflvl; 424 int nr_perflvl;
425 struct nouveau_pm_memtimings memtimings;
408 struct nouveau_pm_temp_sensor_constants sensor_constants; 426 struct nouveau_pm_temp_sensor_constants sensor_constants;
409 struct nouveau_pm_threshold_temp threshold_temp; 427 struct nouveau_pm_threshold_temp threshold_temp;
410 428
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 2db01f80f38e..00b31b5e16cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -648,3 +648,147 @@ nouveau_mem_gart_init(struct drm_device *dev)
648 return 0; 648 return 0;
649} 649}
650 650
651void
652nouveau_mem_timing_init(struct drm_device *dev)
653{
654 struct drm_nouveau_private *dev_priv = dev->dev_private;
655 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
656 struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
657 struct nvbios *bios = &dev_priv->vbios;
658 struct bit_entry P;
659 u8 tUNK_0, tUNK_1, tUNK_2;
660 u8 tRP; /* Byte 3 */
661 u8 tRAS; /* Byte 5 */
662 u8 tRFC; /* Byte 7 */
663 u8 tRC; /* Byte 9 */
664 u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
665 u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
666 u8 *mem = NULL, *entry;
667 int i, recordlen, entries;
668
669 if (bios->type == NVBIOS_BIT) {
670 if (bit_table(dev, 'P', &P))
671 return;
672
673 if (P.version == 1)
674 mem = ROMPTR(bios, P.data[4]);
675 else
676 if (P.version == 2)
677 mem = ROMPTR(bios, P.data[8]);
678 else {
679 NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
680 }
681 } else {
682 NV_DEBUG(dev, "BMP version too old for memory\n");
683 return;
684 }
685
686 if (!mem) {
687 NV_DEBUG(dev, "memory timing table pointer invalid\n");
688 return;
689 }
690
691 if (mem[0] != 0x10) {
692 NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]);
693 return;
694 }
695
696 /* validate record length */
697 entries = mem[2];
698 recordlen = mem[3];
699 if (recordlen < 15) {
700 NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]);
701 return;
702 }
703
704 /* parse vbios entries into common format */
705 memtimings->timing =
706 kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
707 if (!memtimings->timing)
708 return;
709
710 entry = mem + mem[1];
711 for (i = 0; i < entries; i++, entry += recordlen) {
712 struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
713 if (entry[0] == 0)
714 continue;
715
716 tUNK_18 = 1;
717 tUNK_19 = 1;
718 tUNK_20 = 0;
719 tUNK_21 = 0;
720 switch (recordlen) {
721 case 0x21:
722 tUNK_21 = entry[21];
723 case 0x20:
724 tUNK_20 = entry[20];
725 case 0x19:
726 tUNK_19 = entry[19];
727 case 0x18:
728 tUNK_18 = entry[18];
729 default:
730 tUNK_0 = entry[0];
731 tUNK_1 = entry[1];
732 tUNK_2 = entry[2];
733 tRP = entry[3];
734 tRAS = entry[5];
735 tRFC = entry[7];
736 tRC = entry[9];
737 tUNK_10 = entry[10];
738 tUNK_11 = entry[11];
739 tUNK_12 = entry[12];
740 tUNK_13 = entry[13];
741 tUNK_14 = entry[14];
742 break;
743 }
744
745 timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP);
746
747 /* XXX: I don't trust the -1's and +1's... they must come
748 * from somewhere! */
749 timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 |
750 tUNK_18 << 16 |
751 (tUNK_1 + tUNK_19 + 1) << 8 |
752 (tUNK_2 - 1));
753
754 timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
755 if(recordlen > 19) {
756 timing->reg_100228 += (tUNK_19 - 1) << 24;
757 } else {
758 timing->reg_100228 += tUNK_12 << 24;
759 }
760
761 /* XXX: reg_10022c */
762
763 timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
764 tUNK_13 << 8 | tUNK_13);
765
766 /* XXX: +6? */
767 timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
768 if(tUNK_10 > tUNK_11) {
769 timing->reg_100234 += tUNK_10 << 16;
770 } else {
771 timing->reg_100234 += tUNK_11 << 16;
772 }
773
774 /* XXX; reg_100238, reg_10023c */
775 NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
776 timing->reg_100220, timing->reg_100224,
777 timing->reg_100228, timing->reg_10022c);
778 NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
779 timing->reg_100230, timing->reg_100234,
780 timing->reg_100238, timing->reg_10023c);
781 }
782
783 memtimings->nr_timing = entries;
784 memtimings->supported = true;
785}
786
787void
788nouveau_mem_timing_fini(struct drm_device *dev)
789{
790 struct drm_nouveau_private *dev_priv = dev->dev_private;
791 struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
792
793 kfree(mem->timing);
794}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index b1d3f4b26ebd..01437f1753a7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -451,6 +451,7 @@ nouveau_pm_init(struct drm_device *dev)
451 nouveau_volt_init(dev); 451 nouveau_volt_init(dev);
452 nouveau_perf_init(dev); 452 nouveau_perf_init(dev);
453 nouveau_temp_init(dev); 453 nouveau_temp_init(dev);
454 nouveau_mem_timing_init(dev);
454 455
455 NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); 456 NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
456 for (i = 0; i < pm->nr_perflvl; i++) { 457 for (i = 0; i < pm->nr_perflvl; i++) {
@@ -491,9 +492,10 @@ nouveau_pm_fini(struct drm_device *dev)
491 if (pm->cur != &pm->boot) 492 if (pm->cur != &pm->boot)
492 nouveau_pm_perflvl_set(dev, &pm->boot); 493 nouveau_pm_perflvl_set(dev, &pm->boot);
493 494
495 nouveau_mem_timing_fini(dev);
496 nouveau_temp_fini(dev);
494 nouveau_perf_fini(dev); 497 nouveau_perf_fini(dev);
495 nouveau_volt_fini(dev); 498 nouveau_volt_fini(dev);
496 nouveau_temp_fini(dev);
497 499
498 nouveau_hwmon_fini(dev); 500 nouveau_hwmon_fini(dev);
499 nouveau_sysfs_fini(dev); 501 nouveau_sysfs_fini(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 6ad0ca9db88f..7504e3b8c023 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -42,6 +42,10 @@ int nouveau_voltage_gpio_set(struct drm_device *, int voltage);
42void nouveau_perf_init(struct drm_device *); 42void nouveau_perf_init(struct drm_device *);
43void nouveau_perf_fini(struct drm_device *); 43void nouveau_perf_fini(struct drm_device *);
44 44
45/* nouveau_mem.c */
46void nouveau_mem_timing_init(struct drm_device *);
47void nouveau_mem_timing_fini(struct drm_device *);
48
45/* nv04_pm.c */ 49/* nv04_pm.c */
46int nv04_pm_clock_get(struct drm_device *, u32 id); 50int nv04_pm_clock_get(struct drm_device *, u32 id);
47void *nv04_pm_clock_pre(struct drm_device *, u32 id, int khz); 51void *nv04_pm_clock_pre(struct drm_device *, u32 id, int khz);