import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / mt_l2c.c
1 #include <linux/module.h>
2 #include <linux/interrupt.h>
3 #include <linux/cpu.h>
4 #include <linux/smp.h>
5 #include "mach/mt_reg_base.h"
6 #include "mach/sync_write.h"
7 #include "asm/cacheflush.h"
8
9 /* config L2 to its size */
10 extern int config_L2(int size);
11 extern void __inner_flush_dcache_all(void);
12 extern void __inner_flush_dcache_L1(void);
13 extern void __inner_flush_dcache_L2(void);
14 extern void __disable_cache(void);
15 extern void __enable_cache(void);
16 void inner_dcache_flush_all(void);
17 void inner_dcache_flush_L1(void);
18 void inner_dcache_flush_L2(void);
19 #define L2C_SIZE_CFG_OFF 5
20 #define L2C_DCM_CFG_OFF 8
21 #define INFRA_DCM_CFG_OFF 9
22
23 static DEFINE_SPINLOCK(cache_cfg_lock);
24 static DEFINE_SPINLOCK(cache_cfg1_lock);
25 /* config L2 cache and sram to its size */
26 int config_L2_size(int size)
27 {
28 volatile unsigned int cache_cfg, ret = 1;
29 /* set L2C size to 128KB */
30 spin_lock(&cache_cfg_lock);
31 cache_cfg = readl(IOMEM(MCUSYS_CFGREG_BASE));
32 if (size == SZ_256K) {
33 cache_cfg &= (~0x7) << L2C_SIZE_CFG_OFF;
34 cache_cfg |= 0x1 << L2C_SIZE_CFG_OFF;
35 mt65xx_reg_sync_writel(cache_cfg, MCUSYS_CFGREG_BASE);
36 } else if (size == SZ_512K) {
37 cache_cfg &= (~0x7) << L2C_SIZE_CFG_OFF;
38 cache_cfg |= 0x3 << L2C_SIZE_CFG_OFF;
39 mt65xx_reg_sync_writel(cache_cfg, MCUSYS_CFGREG_BASE);
40 } else {
41 ret = -1;
42 }
43 spin_unlock(&cache_cfg_lock);
44 return ret;
45 }
46
47 int get_l2c_size(void)
48 {
49 volatile unsigned int cache_cfg;
50 int size;
51 cache_cfg = readl(IOMEM(MCUSYS_CFGREG_BASE));
52 cache_cfg = cache_cfg >> L2C_SIZE_CFG_OFF;
53 cache_cfg = cache_cfg & 0x7;
54 if (cache_cfg == 0)
55 size = SZ_128K;
56 else if (cache_cfg == 1)
57 size = SZ_256K;
58 else if (cache_cfg == 3)
59 size = SZ_512K;
60 else if (cache_cfg == 7)
61 size = SZ_1M;
62 else
63 size = -1;
64 return size;
65 }
66
67 atomic_t L1_flush_done = ATOMIC_INIT(0);
68 extern int __is_dcache_enable(void);
69 extern int cr_alignment;
70
71 void atomic_flush(void)
72 {
73 __disable_cache();
74 inner_dcache_flush_L1();
75
76 atomic_inc(&L1_flush_done);
77 //update cr_alignment for other kernel function usage
78 cr_alignment = cr_alignment & ~(0x4); //C1_CBIT
79 }
80
81 int config_L2(int size)
82 {
83 int cur_size = get_l2c_size();
84 if (size != SZ_256K && size != SZ_512K) {
85 printk("inlvalid input size %x\n", size);
86 return -1;
87 }
88 if (in_interrupt()) {
89 printk(KERN_ERR "Cannot use %s in interrupt/softirq context\n",
90 __func__);
91 return -1;
92 }
93 if (size == cur_size) {
94 printk("Config L2 size %x is equal to current L2 size %x\n",
95 size, cur_size);
96 return 0;
97 }
98
99 atomic_set(&L1_flush_done, 0);
100 get_online_cpus();
101 //printk("[Config L2] Config L2 start, on line cpu = %d\n",num_online_cpus());
102
103 /* disable cache and flush L1 */
104 on_each_cpu((smp_call_func_t)atomic_flush, NULL, true);
105 //while(atomic_read(&L1_flush_done) != num_online_cpus());
106 //printk("[Config L2] L1 flush done\n");
107
108 /* flush L2 */
109 inner_dcache_flush_L2();
110 //printk("[Config L2] L2 flush done\n");
111
112 /* change L2 size */
113 config_L2_size(size);
114 //printk("[Config L2] Change L2 flush size done(size = %d)\n",size);
115
116 /* enable cache */
117 atomic_set(&L1_flush_done, 0);
118 on_each_cpu((smp_call_func_t)__enable_cache, NULL, true);
119
120 //update cr_alignment for other kernel function usage
121 cr_alignment = cr_alignment | (0x4); //C1_CBIT
122 put_online_cpus();
123 printk("Config L2 size %x done\n", size);
124 return 0;
125 }
126
127 #include <linux/device.h>
128 #include <linux/platform_device.h>
129 static struct device_driver mt_l2c_drv = {
130 .name = "l2c",
131 .bus = &platform_bus_type,
132 .owner = THIS_MODULE,
133 };
134
135 int mt_l2c_get_status(void)
136 {
137 unsigned int size, cache_cfg;
138 cache_cfg = readl(IOMEM(MCUSYS_CFGREG_BASE));
139 cache_cfg = cache_cfg >> L2C_SIZE_CFG_OFF;
140 cache_cfg &= 0x7;
141 if (cache_cfg == 1) {
142 //size = SZ_256K;
143 size = 256;
144 } else if (cache_cfg == 3) {
145 //size = SZ_512K;
146 size = 512;
147 } else {
148 size = -1;
149 printk("Wrong cache_cfg = %x, size = %d\n", cache_cfg, size);
150 }
151 return size;
152 }
153
154 /*
155 * cur_l2c_show: To show cur_l2c size.
156 */
157 static ssize_t cur_l2c_show(struct device_driver *driver, char *buf)
158 {
159 unsigned int size;
160
161 size = mt_l2c_get_status();
162 return snprintf(buf, PAGE_SIZE, "%d\n", size);
163 }
164
165 /*
166 * cur_l2c_store: To set cur_l2c size.
167 */
168 static ssize_t cur_l2c_store(struct device_driver *driver, const char *buf,
169 size_t count)
170 {
171 char *p = (char *)buf;
172 int size, ret;
173
174 size = simple_strtoul(p, &p, 10);
175 if (size == 256) {
176 size = SZ_256K;
177 } else if (size == 512) {
178 size = SZ_512K;
179 } else {
180 printk("invalid size value: %d\n", size);
181 return count;
182 }
183
184 ret = config_L2(size);
185 if (ret < 0)
186 printk("Config L2 error ret:%d size value: %d\n", ret, size);
187 return count;
188 }
189
190 DRIVER_ATTR(current_l2c, 0644, cur_l2c_show, cur_l2c_store);
191 /*
192 * mt_l2c_init: initialize l2c driver.
193 * Always return 0.
194 */
195 int mt_l2c_init(void)
196 {
197 int ret;
198
199 ret = driver_register(&mt_l2c_drv);
200 if (ret) {
201 printk("fail to register mt_l2c_drv\n");
202 }
203
204 ret = driver_create_file(&mt_l2c_drv, &driver_attr_current_l2c);
205 if (ret) {
206 printk("fail to create mt_l2c sysfs files\n");
207 }
208 return 0;
209 }
210
211 arch_initcall(mt_l2c_init);
212
213 /* To disable/enable auto invalidate cache API
214 @ disable == 1 to disable auto invalidate cache
215 @ disable == 0 to enable auto invalidate cache
216 return 0 -> success, -1 -> fail
217 */
218 int auto_inv_cache(unsigned int disable)
219 {
220 volatile unsigned int cache_cfg, cache_cfg_new;
221 spin_lock(&cache_cfg1_lock);
222 if(disable) {
223 /* set cache auto disable */
224 cache_cfg = readl(IOMEM(MCUSYS_CFGREG_BASE));
225 cache_cfg |= 0x1F;
226 writel(cache_cfg, IOMEM(MCUSYS_CFGREG_BASE));
227 } else if (disable == 0){
228 /* set cache auto enable */
229 cache_cfg = readl(IOMEM(MCUSYS_CFGREG_BASE));
230 cache_cfg &= ~0x1F;
231 writel(cache_cfg, IOMEM(MCUSYS_CFGREG_BASE));
232 } else {
233 printk("Caller give a wrong arg:%d\n", disable);
234 spin_unlock(&cache_cfg1_lock);
235 return -1;
236 }
237 cache_cfg_new = readl(IOMEM(MCUSYS_CFGREG_BASE));
238 spin_unlock(&cache_cfg1_lock);
239 if((cache_cfg_new & 0x1F) != (cache_cfg & 0x1F))
240 return 0;
241 else
242 return -1;
243 }
244
245 EXPORT_SYMBOL(config_L2);