Commit | Line | Data |
---|---|---|
6fa3eb70 S |
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); |