upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / asv.c
1 /* linux/arch/arm/mach-s5pv310/asv.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5PV310 - ASV(Adaptive Supply Voltage) Test driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/init.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/err.h>
17 #include <linux/clk.h>
18 #include <linux/io.h>
19
20 #include <mach/map.h>
21 #include <mach/regs-iem.h>
22 #include <mach/regs-pmu.h>
23 #include <mach/regs-clock.h>
24
25 #include <asm/mach-types.h>
26
27 #define LOOP_CNT        10
28
29 int exynos4_asv_group;
30
31 static int __init iem_clock_init(void)
32 {
33         struct clk *clk_hpm;
34         struct clk *clk_copy;
35         struct clk *clk_parent;
36
37         /* PWI clock setting */
38         clk_copy = clk_get(NULL, "sclk_pwi");
39         if (IS_ERR(clk_copy)) {
40                 printk(KERN_ERR"ASV : SCLK_PWI clock get error\n");
41                 return -EINVAL;
42         } else {
43                 clk_parent = clk_get(NULL, "xusbxti");
44                 if (IS_ERR(clk_parent)) {
45                         printk(KERN_ERR"ASV : MOUT_APLL clock get error\n");
46                         return -EINVAL;
47                 }
48                 clk_set_parent(clk_copy, clk_parent);
49
50                 clk_put(clk_parent);
51         }
52         clk_set_rate(clk_copy, 4800000);
53
54         clk_put(clk_copy);
55
56         /* HPM clock setting */
57         clk_copy = clk_get(NULL, "dout_copy");
58         if (IS_ERR(clk_copy)) {
59                 printk(KERN_ERR"ASV : DOUT_COPY clock get error\n");
60                 return -EINVAL;
61         } else {
62                 clk_parent = clk_get(NULL, "mout_mpll");
63                 if (IS_ERR(clk_parent)) {
64                         printk(KERN_ERR"ASV : MOUT_APLL clock get error\n");
65                         return -EINVAL;
66                 }
67                 clk_set_parent(clk_copy, clk_parent);
68
69                 clk_put(clk_parent);
70         }
71
72         clk_set_rate(clk_copy, (400 * 1000 * 1000));
73
74         clk_put(clk_copy);
75
76         clk_hpm = clk_get(NULL, "sclk_hpm");
77         if (IS_ERR(clk_hpm))
78                 return -EINVAL;
79
80         clk_set_rate(clk_hpm, (200 * 1000 * 1000));
81
82         clk_put(clk_hpm);
83
84         return 0;
85 }
86
87 void __init iem_clock_set(void)
88 {
89         /* APLL_CON0 level register */
90         __raw_writel(0x80FA0601, S5P_APLL_CON0L8);
91         __raw_writel(0x80C80601, S5P_APLL_CON0L7);
92         __raw_writel(0x80C80602, S5P_APLL_CON0L6);
93         __raw_writel(0x80C80604, S5P_APLL_CON0L5);
94         __raw_writel(0x80C80601, S5P_APLL_CON0L4);
95         __raw_writel(0x80C80601, S5P_APLL_CON0L3);
96         __raw_writel(0x80C80601, S5P_APLL_CON0L2);
97         __raw_writel(0x80C80601, S5P_APLL_CON0L1);
98
99         /* IEM Divider register */
100         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L8);
101         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L7);
102         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L6);
103         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L5);
104         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L4);
105         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L3);
106         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L2);
107         __raw_writel(0x00500000, S5P_CLKDIV_IEM_L1);
108 }
109
110 #define IDS_OFFSET      24
111 #define IDS_MASK        0xFF
112
113 #define IDS_LEVEL_MAX_0         4
114 #define IDS_LEVEL_MAX_1         8
115 #define IDS_LEVEL_MAX_2         12
116 #define IDS_LEVEL_MAX_3         17
117 #define IDS_LEVEL_MAX_4         27
118 #define IDS_LEVEL_MAX_5         45
119 #define IDS_LEVEL_MAX_6         55
120
121 #define HPM_LEVEL_MAX_0         8
122 #define HPM_LEVEL_MAX_1         11
123 #define HPM_LEVEL_MAX_2         14
124 #define HPM_LEVEL_MAX_3         18
125 #define HPM_LEVEL_MAX_4         21
126 #define HPM_LEVEL_MAX_5         23
127 #define HPM_LEVEL_MAX_6         25
128
129 #define ASV_MAX_GROUP                   8
130
131 enum find_asv {
132         HPM_GROUP,
133         IDS_GROUP,
134 };
135
136 static int __init s5pv310_find_group(unsigned int value, enum find_asv grp)
137 {
138         unsigned int ret;
139
140         if (grp == HPM_GROUP) {
141                 if (value <= HPM_LEVEL_MAX_0)
142                         ret = 0;
143                 else if (value <= HPM_LEVEL_MAX_1)
144                         ret = 1;
145                 else if (value <= HPM_LEVEL_MAX_2)
146                         ret = 2;
147                 else if (value <= HPM_LEVEL_MAX_3)
148                         ret = 3;
149                 else if (value <= HPM_LEVEL_MAX_4)
150                         ret = 4;
151                 else if (value <= HPM_LEVEL_MAX_5)
152                         ret = 5;
153                 else
154                         ret = 6;
155         } else {
156                 if (value <= IDS_LEVEL_MAX_0)
157                         ret = 0;
158                 else if (value <= IDS_LEVEL_MAX_1)
159                         ret = 1;
160                 else if (value <= IDS_LEVEL_MAX_2)
161                         ret = 2;
162                 else if (value <= IDS_LEVEL_MAX_3)
163                         ret = 3;
164                 else if (value <= IDS_LEVEL_MAX_4)
165                         ret = 4;
166                 else if (value <= IDS_LEVEL_MAX_5)
167                         ret = 5;
168                 else
169                         ret = 6;
170         }
171
172         return ret;
173 }
174
175 static int __init s5pv310_asv_init(void)
176 {
177         unsigned int i;
178         unsigned long hpm_delay = 0;
179         unsigned int tmp;
180         unsigned int ids_arm;
181         unsigned int result_group = 0;
182         static void __iomem * iem_base;
183         struct clk *clk = clk_get(NULL, "chipid");
184
185         if (IS_ERR_OR_NULL(clk))
186                 clk = NULL;
187         if (clk)
188                 clk_enable(clk);
189
190         if(machine_is_smdkv310())
191                 goto out;
192
193         tmp = __raw_readl(S5P_VA_CHIPID + 0x4);
194
195         if (clk) {
196                 clk_disable(clk);
197                 clk_put(clk);
198         }
199
200         ids_arm = ((tmp >> IDS_OFFSET) & IDS_MASK);
201
202         iem_base = ioremap(S5PV310_PA_IEM, (128 * 1024));
203
204         if (iem_base == NULL) {
205                 printk(KERN_ERR "faile to ioremap\n");
206                 goto out;
207         }
208
209         if (iem_clock_init()) {
210                 printk(KERN_ERR "ASV driver clock_init fail\n");
211                 goto out;
212         } else {
213                 /* HPM enable  */
214                 tmp = __raw_readl(iem_base + S5PV310_APC_CONTROL);
215                 tmp |= APC_HPM_EN;
216                 __raw_writel(tmp, (iem_base + S5PV310_APC_CONTROL));
217
218                 iem_clock_set();
219
220                 /* IEM enable */
221                 tmp = __raw_readl(iem_base + S5PV310_IECDPCCR);
222                 tmp |= IEC_EN;
223                 __raw_writel(tmp, (iem_base + S5PV310_IECDPCCR));
224         }
225
226         for ( i=0 ; i < LOOP_CNT ; i++ ){
227                 tmp = __raw_readb(iem_base + S5PV310_APC_DBG_DLYCODE);
228                 hpm_delay += tmp;
229         }
230
231         hpm_delay /= LOOP_CNT;
232
233         result_group = s5pv310_find_group(hpm_delay, HPM_GROUP);
234
235         if (result_group > s5pv310_find_group(ids_arm,IDS_GROUP))
236                 result_group = s5pv310_find_group(ids_arm,IDS_GROUP);
237
238         exynos4_asv_group = result_group;
239
240         printk(KERN_INFO "ASV Group for This Exynos4210 is %d\n",result_group);
241
242         return 0;
243
244 out:
245         exynos4_asv_group = 0;
246         printk(KERN_INFO "ASV Group for This Exynos4210 is %d\n",result_group);
247
248         return -EINVAL;
249
250 }
251 core_initcall(s5pv310_asv_init);