• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3  *		http://www.samsung.com/
4  *
5  * EXYNOS - PPMU support
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/io.h>
15 
16 #include "exynos_ppmu.h"
17 
exynos_ppmu_reset(void __iomem * ppmu_base)18 void exynos_ppmu_reset(void __iomem *ppmu_base)
19 {
20 	__raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, ppmu_base);
21 	__raw_writel(PPMU_ENABLE_CYCLE  |
22 		     PPMU_ENABLE_COUNT0 |
23 		     PPMU_ENABLE_COUNT1 |
24 		     PPMU_ENABLE_COUNT2 |
25 		     PPMU_ENABLE_COUNT3,
26 		     ppmu_base + PPMU_CNTENS);
27 }
28 
exynos_ppmu_setevent(void __iomem * ppmu_base,unsigned int ch,unsigned int evt)29 void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
30 			unsigned int evt)
31 {
32 	__raw_writel(evt, ppmu_base + PPMU_BEVTSEL(ch));
33 }
34 
exynos_ppmu_start(void __iomem * ppmu_base)35 void exynos_ppmu_start(void __iomem *ppmu_base)
36 {
37 	__raw_writel(PPMU_ENABLE, ppmu_base);
38 }
39 
exynos_ppmu_stop(void __iomem * ppmu_base)40 void exynos_ppmu_stop(void __iomem *ppmu_base)
41 {
42 	__raw_writel(PPMU_DISABLE, ppmu_base);
43 }
44 
exynos_ppmu_read(void __iomem * ppmu_base,unsigned int ch)45 unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch)
46 {
47 	unsigned int total;
48 
49 	if (ch == PPMU_PMNCNT3)
50 		total = ((__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
51 			  __raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
52 	else
53 		total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
54 
55 	return total;
56 }
57 
busfreq_mon_reset(struct busfreq_ppmu_data * ppmu_data)58 void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data)
59 {
60 	unsigned int i;
61 
62 	for (i = 0; i < ppmu_data->ppmu_end; i++) {
63 		void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
64 
65 		/* Reset the performance and cycle counters */
66 		exynos_ppmu_reset(ppmu_base);
67 
68 		/* Setup count registers to monitor read/write transactions */
69 		ppmu_data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
70 		exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
71 					ppmu_data->ppmu[i].event[PPMU_PMNCNT3]);
72 
73 		exynos_ppmu_start(ppmu_base);
74 	}
75 }
76 EXPORT_SYMBOL(busfreq_mon_reset);
77 
exynos_read_ppmu(struct busfreq_ppmu_data * ppmu_data)78 void exynos_read_ppmu(struct busfreq_ppmu_data *ppmu_data)
79 {
80 	int i, j;
81 
82 	for (i = 0; i < ppmu_data->ppmu_end; i++) {
83 		void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
84 
85 		exynos_ppmu_stop(ppmu_base);
86 
87 		/* Update local data from PPMU */
88 		ppmu_data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
89 
90 		for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
91 			if (ppmu_data->ppmu[i].event[j] == 0)
92 				ppmu_data->ppmu[i].count[j] = 0;
93 			else
94 				ppmu_data->ppmu[i].count[j] =
95 					exynos_ppmu_read(ppmu_base, j);
96 		}
97 	}
98 
99 	busfreq_mon_reset(ppmu_data);
100 }
101 EXPORT_SYMBOL(exynos_read_ppmu);
102 
exynos_get_busier_ppmu(struct busfreq_ppmu_data * ppmu_data)103 int exynos_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data)
104 {
105 	unsigned int count = 0;
106 	int i, j, busy = 0;
107 
108 	for (i = 0; i < ppmu_data->ppmu_end; i++) {
109 		for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
110 			if (ppmu_data->ppmu[i].count[j] > count) {
111 				count = ppmu_data->ppmu[i].count[j];
112 				busy = i;
113 			}
114 		}
115 	}
116 
117 	return busy;
118 }
119 EXPORT_SYMBOL(exynos_get_busier_ppmu);
120