aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/exynos
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2014-03-21 13:31:43 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2014-05-24 04:56:39 -0400
commitba778b374d55945a190f01f7a741c9657ae5f519 (patch)
tree85a7bfbd4428aee6b5dfc850c23dc60f4583c030 /drivers/devfreq/exynos
parentae29fa1d50bead8f1971f30aa9a73bfbff984824 (diff)
PM / devfreq: exynos4: use common PPMU code
This patch converts exynos4_bus driver to use common PPMU code (exynos_ppmu.c) instead of individual functions related to PPC because PPMU is integrated module with both PPC and Bus event generator. When using PPMU to get bus performance read/write event exynos4_bus driver deson't need to consider memory type. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> [bzolnier: splitted out changes from the bigger patch] Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq/exynos')
-rw-r--r--drivers/devfreq/exynos/Makefile2
-rw-r--r--drivers/devfreq/exynos/exynos4_bus.c164
2 files changed, 62 insertions, 104 deletions
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
index bfaaf5b0d61d..49bc9175f923 100644
--- a/drivers/devfreq/exynos/Makefile
+++ b/drivers/devfreq/exynos/Makefile
@@ -1,3 +1,3 @@
1# Exynos DEVFREQ Drivers 1# Exynos DEVFREQ Drivers
2obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o 2obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos_ppmu.o exynos4_bus.o
3obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o 3obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o
diff --git a/drivers/devfreq/exynos/exynos4_bus.c b/drivers/devfreq/exynos/exynos4_bus.c
index 5a48d162b228..228c658c0e8c 100644
--- a/drivers/devfreq/exynos/exynos4_bus.c
+++ b/drivers/devfreq/exynos/exynos4_bus.c
@@ -25,15 +25,16 @@
25#include <linux/regulator/consumer.h> 25#include <linux/regulator/consumer.h>
26#include <linux/module.h> 26#include <linux/module.h>
27 27
28#include <mach/map.h>
29
30#include "exynos_ppmu.h"
31#include "exynos4_bus.h"
32
28/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */ 33/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */
29#ifdef CONFIG_EXYNOS_ASV 34#ifdef CONFIG_EXYNOS_ASV
30extern unsigned int exynos_result_of_asv; 35extern unsigned int exynos_result_of_asv;
31#endif 36#endif
32 37
33#include <mach/map.h>
34
35#include "exynos4_bus.h"
36
37#define MAX_SAFEVOLT 1200000 /* 1.2V */ 38#define MAX_SAFEVOLT 1200000 /* 1.2V */
38 39
39enum exynos4_busf_type { 40enum exynos4_busf_type {
@@ -44,22 +45,6 @@ enum exynos4_busf_type {
44/* Assume that the bus is saturated if the utilization is 40% */ 45/* Assume that the bus is saturated if the utilization is 40% */
45#define BUS_SATURATION_RATIO 40 46#define BUS_SATURATION_RATIO 40
46 47
47enum ppmu_counter {
48 PPMU_PMNCNT0 = 0,
49 PPMU_PMCCNT1,
50 PPMU_PMNCNT2,
51 PPMU_PMNCNT3,
52 PPMU_PMNCNT_MAX,
53};
54struct exynos4_ppmu {
55 void __iomem *hw_base;
56 unsigned int ccnt;
57 unsigned int event;
58 unsigned int count[PPMU_PMNCNT_MAX];
59 bool ccnt_overflow;
60 bool count_overflow[PPMU_PMNCNT_MAX];
61};
62
63enum busclk_level_idx { 48enum busclk_level_idx {
64 LV_0 = 0, 49 LV_0 = 0,
65 LV_1, 50 LV_1,
@@ -68,6 +53,13 @@ enum busclk_level_idx {
68 LV_4, 53 LV_4,
69 _LV_END 54 _LV_END
70}; 55};
56
57enum exynos_ppmu_idx {
58 PPMU_DMC0,
59 PPMU_DMC1,
60 PPMU_END,
61};
62
71#define EX4210_LV_MAX LV_2 63#define EX4210_LV_MAX LV_2
72#define EX4x12_LV_MAX LV_4 64#define EX4x12_LV_MAX LV_4
73#define EX4210_LV_NUM (LV_2 + 1) 65#define EX4210_LV_NUM (LV_2 + 1)
@@ -91,7 +83,7 @@ struct busfreq_data {
91 struct regulator *vdd_int; 83 struct regulator *vdd_int;
92 struct regulator *vdd_mif; /* Exynos4412/4212 only */ 84 struct regulator *vdd_mif; /* Exynos4412/4212 only */
93 struct busfreq_opp_info curr_oppinfo; 85 struct busfreq_opp_info curr_oppinfo;
94 struct exynos4_ppmu dmc[2]; 86 struct exynos_ppmu ppmu[PPMU_END];
95 87
96 struct notifier_block pm_notifier; 88 struct notifier_block pm_notifier;
97 struct mutex lock; 89 struct mutex lock;
@@ -101,12 +93,6 @@ struct busfreq_data {
101 unsigned int top_divtable[_LV_END]; 93 unsigned int top_divtable[_LV_END];
102}; 94};
103 95
104struct bus_opp_table {
105 unsigned int idx;
106 unsigned long clk;
107 unsigned long volt;
108};
109
110/* 4210 controls clock of mif and voltage of int */ 96/* 4210 controls clock of mif and voltage of int */
111static struct bus_opp_table exynos4210_busclk_table[] = { 97static struct bus_opp_table exynos4210_busclk_table[] = {
112 {LV_0, 400000, 1150000}, 98 {LV_0, 400000, 1150000},
@@ -524,27 +510,22 @@ static int exynos4x12_set_busclk(struct busfreq_data *data,
524 return 0; 510 return 0;
525} 511}
526 512
527
528static void busfreq_mon_reset(struct busfreq_data *data) 513static void busfreq_mon_reset(struct busfreq_data *data)
529{ 514{
530 unsigned int i; 515 unsigned int i;
531 516
532 for (i = 0; i < 2; i++) { 517 for (i = 0; i < PPMU_END; i++) {
533 void __iomem *ppmu_base = data->dmc[i].hw_base; 518 void __iomem *ppmu_base = data->ppmu[i].hw_base;
534 519
535 /* Reset PPMU */ 520 /* Reset the performance and cycle counters */
536 __raw_writel(0x8000000f, ppmu_base + 0xf010); 521 exynos_ppmu_reset(ppmu_base);
537 __raw_writel(0x8000000f, ppmu_base + 0xf050);
538 __raw_writel(0x6, ppmu_base + 0xf000);
539 __raw_writel(0x0, ppmu_base + 0xf100);
540 522
541 /* Set PPMU Event */ 523 /* Setup count registers to monitor read/write transactions */
542 data->dmc[i].event = 0x6; 524 data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
543 __raw_writel(((data->dmc[i].event << 12) | 0x1), 525 exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
544 ppmu_base + 0xfc); 526 data->ppmu[i].event[PPMU_PMNCNT3]);
545 527
546 /* Start PPMU */ 528 exynos_ppmu_start(ppmu_base);
547 __raw_writel(0x1, ppmu_base + 0xf000);
548 } 529 }
549} 530}
550 531
@@ -552,23 +533,20 @@ static void exynos4_read_ppmu(struct busfreq_data *data)
552{ 533{
553 int i, j; 534 int i, j;
554 535
555 for (i = 0; i < 2; i++) { 536 for (i = 0; i < PPMU_END; i++) {
556 void __iomem *ppmu_base = data->dmc[i].hw_base; 537 void __iomem *ppmu_base = data->ppmu[i].hw_base;
557 u32 overflow;
558 538
559 /* Stop PPMU */ 539 exynos_ppmu_stop(ppmu_base);
560 __raw_writel(0x0, ppmu_base + 0xf000);
561 540
562 /* Update local data from PPMU */ 541 /* Update local data from PPMU */
563 overflow = __raw_readl(ppmu_base + 0xf050); 542 data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
564 543
565 data->dmc[i].ccnt = __raw_readl(ppmu_base + 0xf100); 544 for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
566 data->dmc[i].ccnt_overflow = overflow & (1 << 31); 545 if (data->ppmu[i].event[j] == 0)
567 546 data->ppmu[i].count[j] = 0;
568 for (j = 0; j < PPMU_PMNCNT_MAX; j++) { 547 else
569 data->dmc[i].count[j] = __raw_readl( 548 data->ppmu[i].count[j] =
570 ppmu_base + (0xf110 + (0x10 * j))); 549 exynos_ppmu_read(ppmu_base, j);
571 data->dmc[i].count_overflow[j] = overflow & (1 << j);
572 } 550 }
573 } 551 }
574 552
@@ -698,66 +676,42 @@ out:
698 return err; 676 return err;
699} 677}
700 678
701static int exynos4_get_busier_dmc(struct busfreq_data *data) 679static int exynos4_get_busier_ppmu(struct busfreq_data *data)
702{ 680{
703 u64 p0 = data->dmc[0].count[0]; 681 int i, j;
704 u64 p1 = data->dmc[1].count[0]; 682 int busy = 0;
705 683 unsigned int temp = 0;
706 p0 *= data->dmc[1].ccnt; 684
707 p1 *= data->dmc[0].ccnt; 685 for (i = 0; i < PPMU_END; i++) {
708 686 for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
709 if (data->dmc[1].ccnt == 0) 687 if (data->ppmu[i].count[j] > temp) {
710 return 0; 688 temp = data->ppmu[i].count[j];
689 busy = i;
690 }
691 }
692 }
711 693
712 if (p0 > p1) 694 return busy;
713 return 0;
714 return 1;
715} 695}
716 696
717static int exynos4_bus_get_dev_status(struct device *dev, 697static int exynos4_bus_get_dev_status(struct device *dev,
718 struct devfreq_dev_status *stat) 698 struct devfreq_dev_status *stat)
719{ 699{
720 struct busfreq_data *data = dev_get_drvdata(dev); 700 struct busfreq_data *data = dev_get_drvdata(dev);
721 int busier_dmc; 701 int busier;
722 int cycles_x2 = 2; /* 2 x cycles */
723 void __iomem *addr;
724 u32 timing;
725 u32 memctrl;
726 702
727 exynos4_read_ppmu(data); 703 exynos4_read_ppmu(data);
728 busier_dmc = exynos4_get_busier_dmc(data); 704 busier = exynos4_get_busier_ppmu(data);
729 stat->current_frequency = data->curr_oppinfo.rate; 705 stat->current_frequency = data->curr_oppinfo.rate;
730 706
731 if (busier_dmc)
732 addr = S5P_VA_DMC1;
733 else
734 addr = S5P_VA_DMC0;
735
736 memctrl = __raw_readl(addr + 0x04); /* one of DDR2/3/LPDDR2 */
737 timing = __raw_readl(addr + 0x38); /* CL or WL/RL values */
738
739 switch ((memctrl >> 8) & 0xf) {
740 case 0x4: /* DDR2 */
741 cycles_x2 = ((timing >> 16) & 0xf) * 2;
742 break;
743 case 0x5: /* LPDDR2 */
744 case 0x6: /* DDR3 */
745 cycles_x2 = ((timing >> 8) & 0xf) + ((timing >> 0) & 0xf);
746 break;
747 default:
748 pr_err("%s: Unknown Memory Type(%d).\n", __func__,
749 (memctrl >> 8) & 0xf);
750 return -EINVAL;
751 }
752
753 /* Number of cycles spent on memory access */ 707 /* Number of cycles spent on memory access */
754 stat->busy_time = data->dmc[busier_dmc].count[0] / 2 * (cycles_x2 + 2); 708 stat->busy_time = data->ppmu[busier].count[PPMU_PMNCNT3];
755 stat->busy_time *= 100 / BUS_SATURATION_RATIO; 709 stat->busy_time *= 100 / BUS_SATURATION_RATIO;
756 stat->total_time = data->dmc[busier_dmc].ccnt; 710 stat->total_time = data->ppmu[busier].ccnt;
757 711
758 /* If the counters have overflown, retry */ 712 /* If the counters have overflown, retry */
759 if (data->dmc[busier_dmc].ccnt_overflow || 713 if (data->ppmu[busier].ccnt_overflow ||
760 data->dmc[busier_dmc].count_overflow[0]) 714 data->ppmu[busier].count_overflow[0])
761 return -EAGAIN; 715 return -EAGAIN;
762 716
763 return 0; 717 return 0;
@@ -1023,8 +977,8 @@ static int exynos4_busfreq_probe(struct platform_device *pdev)
1023 } 977 }
1024 978
1025 data->type = pdev->id_entry->driver_data; 979 data->type = pdev->id_entry->driver_data;
1026 data->dmc[0].hw_base = S5P_VA_DMC0; 980 data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0;
1027 data->dmc[1].hw_base = S5P_VA_DMC1; 981 data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1;
1028 data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event; 982 data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event;
1029 data->dev = dev; 983 data->dev = dev;
1030 mutex_init(&data->lock); 984 mutex_init(&data->lock);
@@ -1074,13 +1028,17 @@ static int exynos4_busfreq_probe(struct platform_device *pdev)
1074 1028
1075 platform_set_drvdata(pdev, data); 1029 platform_set_drvdata(pdev, data);
1076 1030
1077 busfreq_mon_reset(data);
1078
1079 data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, 1031 data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
1080 "simple_ondemand", NULL); 1032 "simple_ondemand", NULL);
1081 if (IS_ERR(data->devfreq)) 1033 if (IS_ERR(data->devfreq))
1082 return PTR_ERR(data->devfreq); 1034 return PTR_ERR(data->devfreq);
1083 1035
1036 /*
1037 * Start PPMU (Performance Profiling Monitoring Unit) to check
1038 * utilization of each IP in the Exynos4 SoC.
1039 */
1040 busfreq_mon_reset(data);
1041
1084 /* Register opp_notifier for Exynos4 busfreq */ 1042 /* Register opp_notifier for Exynos4 busfreq */
1085 err = devfreq_register_opp_notifier(dev, data->devfreq); 1043 err = devfreq_register_opp_notifier(dev, data->devfreq);
1086 if (err < 0) { 1044 if (err < 0) {