1
2
3
4
5
6
7
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/stddef.h>
13#include <linux/ioport.h>
14#include <linux/genalloc.h>
15#include <linux/string.h>
16#include <asm/cputype.h>
17#include <asm/mach/map.h>
18#include <asm/memory.h>
19#include <asm/system_info.h>
20#include <asm/traps.h>
21#include <asm/tcm.h>
22
23#define TCMTR_FORMAT_MASK 0xe0000000U
24
25static struct gen_pool *tcm_pool;
26static bool dtcm_present;
27static bool itcm_present;
28
29
30extern char __itcm_start, __sitcm_text, __eitcm_text;
31extern char __dtcm_start, __sdtcm_data, __edtcm_data;
32
33
34static u32 dtcm_end = DTCM_OFFSET;
35static u32 itcm_end = ITCM_OFFSET;
36
37
38
39
40static struct resource dtcm_res = {
41 .name = "DTCM RAM",
42 .start = DTCM_OFFSET,
43 .end = DTCM_OFFSET,
44 .flags = IORESOURCE_MEM
45};
46
47static struct resource itcm_res = {
48 .name = "ITCM RAM",
49 .start = ITCM_OFFSET,
50 .end = ITCM_OFFSET,
51 .flags = IORESOURCE_MEM
52};
53
54static struct map_desc dtcm_iomap[] __initdata = {
55 {
56 .virtual = DTCM_OFFSET,
57 .pfn = __phys_to_pfn(DTCM_OFFSET),
58 .length = 0,
59 .type = MT_MEMORY_RW_DTCM
60 }
61};
62
63static struct map_desc itcm_iomap[] __initdata = {
64 {
65 .virtual = ITCM_OFFSET,
66 .pfn = __phys_to_pfn(ITCM_OFFSET),
67 .length = 0,
68 .type = MT_MEMORY_RWX_ITCM,
69 }
70};
71
72
73
74
75void *tcm_alloc(size_t len)
76{
77 unsigned long vaddr;
78
79 if (!tcm_pool)
80 return NULL;
81
82 vaddr = gen_pool_alloc(tcm_pool, len);
83 if (!vaddr)
84 return NULL;
85
86 return (void *) vaddr;
87}
88EXPORT_SYMBOL(tcm_alloc);
89
90
91
92
93void tcm_free(void *addr, size_t len)
94{
95 gen_pool_free(tcm_pool, (unsigned long) addr, len);
96}
97EXPORT_SYMBOL(tcm_free);
98
99bool tcm_dtcm_present(void)
100{
101 return dtcm_present;
102}
103EXPORT_SYMBOL(tcm_dtcm_present);
104
105bool tcm_itcm_present(void)
106{
107 return itcm_present;
108}
109EXPORT_SYMBOL(tcm_itcm_present);
110
111static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
112 u32 *offset)
113{
114 const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128,
115 256, 512, 1024, -1, -1, -1, -1 };
116 u32 tcm_region;
117 int tcm_size;
118
119
120
121
122
123
124 if (banks > 1)
125 asm("mcr p15, 0, %0, c9, c2, 0"
126 :
127 : "r" (bank));
128
129
130 if (!type)
131 asm("mrc p15, 0, %0, c9, c1, 0"
132 : "=r" (tcm_region));
133 else
134 asm("mrc p15, 0, %0, c9, c1, 1"
135 : "=r" (tcm_region));
136
137 tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f];
138 if (tcm_size < 0) {
139 pr_err("CPU: %sTCM%d of unknown size\n",
140 type ? "I" : "D", bank);
141 return -EINVAL;
142 } else if (tcm_size > 32) {
143 pr_err("CPU: %sTCM%d larger than 32k found\n",
144 type ? "I" : "D", bank);
145 return -EINVAL;
146 } else {
147 pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n",
148 type ? "I" : "D",
149 bank,
150 tcm_size,
151 (tcm_region & 0xfffff000U),
152 (tcm_region & 1) ? "" : "not ");
153 }
154
155
156 if (tcm_size == 0)
157 return 0;
158
159
160 tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1;
161
162 if (!type)
163 asm("mcr p15, 0, %0, c9, c1, 0"
164 :
165 : "r" (tcm_region));
166 else
167 asm("mcr p15, 0, %0, c9, c1, 1"
168 :
169 : "r" (tcm_region));
170
171
172 *offset += (tcm_size << 10);
173
174 pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n",
175 type ? "I" : "D",
176 bank,
177 tcm_size,
178 (tcm_region & 0xfffff000U));
179 return 0;
180}
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233#define TCM_REGION_READ_MASK 0xffff0fdf
234#define TCM_REGION_READ_INSTR 0xee190f11
235#define DEST_REG_SHIFT 12
236#define DEST_REG_MASK 0xf
237
238static int __init tcm_handler(struct pt_regs *regs, unsigned int instr)
239{
240 regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0;
241 regs->ARM_pc += 4;
242 return 0;
243}
244
245static struct undef_hook tcm_hook __initdata = {
246 .instr_mask = TCM_REGION_READ_MASK,
247 .instr_val = TCM_REGION_READ_INSTR,
248 .cpsr_mask = MODE_MASK,
249 .cpsr_val = SVC_MODE,
250 .fn = tcm_handler
251};
252
253
254
255
256void __init tcm_init(void)
257{
258 u32 tcm_status;
259 u8 dtcm_banks;
260 u8 itcm_banks;
261 size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data;
262 size_t itcm_code_sz = &__eitcm_text - &__sitcm_text;
263 char *start;
264 char *end;
265 char *ram;
266 int ret;
267 int i;
268
269
270
271
272
273 if (cpu_architecture() < CPU_ARCH_ARMv5) {
274 if (dtcm_code_sz || itcm_code_sz)
275 pr_info("CPU TCM: %u bytes of DTCM and %u bytes of "
276 "ITCM code compiled in, but no TCM present "
277 "in pre-v5 CPU\n", dtcm_code_sz, itcm_code_sz);
278 return;
279 }
280
281 tcm_status = read_cpuid_tcmstatus();
282
283
284
285
286 if (tcm_status & TCMTR_FORMAT_MASK)
287 return;
288
289 dtcm_banks = (tcm_status >> 16) & 0x03;
290 itcm_banks = (tcm_status & 0x03);
291
292 register_undef_hook(&tcm_hook);
293
294
295 if (dtcm_banks > 2)
296 dtcm_banks = 0;
297 if (itcm_banks > 2)
298 itcm_banks = 0;
299
300
301 if (dtcm_banks > 0) {
302 for (i = 0; i < dtcm_banks; i++) {
303 ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
304 if (ret)
305 goto unregister;
306 }
307
308 if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) {
309 pr_info("CPU DTCM: %u bytes of code compiled to "
310 "DTCM but only %lu bytes of DTCM present\n",
311 dtcm_code_sz, (dtcm_end - DTCM_OFFSET));
312 goto no_dtcm;
313 }
314
315
316
317
318 if (!(dtcm_end - DTCM_OFFSET))
319 goto no_dtcm;
320 dtcm_res.end = dtcm_end - 1;
321 request_resource(&iomem_resource, &dtcm_res);
322 dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
323 iotable_init(dtcm_iomap, 1);
324
325 start = &__sdtcm_data;
326 end = &__edtcm_data;
327 ram = &__dtcm_start;
328 memcpy(start, ram, dtcm_code_sz);
329 pr_debug("CPU DTCM: copied data from %p - %p\n",
330 start, end);
331 dtcm_present = true;
332 } else if (dtcm_code_sz) {
333 pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no "
334 "DTCM banks present in CPU\n", dtcm_code_sz);
335 }
336
337no_dtcm:
338
339 if (itcm_banks > 0) {
340 for (i = 0; i < itcm_banks; i++) {
341 ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
342 if (ret)
343 goto unregister;
344 }
345
346 if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) {
347 pr_info("CPU ITCM: %u bytes of code compiled to "
348 "ITCM but only %lu bytes of ITCM present\n",
349 itcm_code_sz, (itcm_end - ITCM_OFFSET));
350 goto unregister;
351 }
352
353
354
355
356 if (!(itcm_end - ITCM_OFFSET))
357 goto unregister;
358 itcm_res.end = itcm_end - 1;
359 request_resource(&iomem_resource, &itcm_res);
360 itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
361 iotable_init(itcm_iomap, 1);
362
363 start = &__sitcm_text;
364 end = &__eitcm_text;
365 ram = &__itcm_start;
366 memcpy(start, ram, itcm_code_sz);
367 pr_debug("CPU ITCM: copied code from %p - %p\n",
368 start, end);
369 itcm_present = true;
370 } else if (itcm_code_sz) {
371 pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no "
372 "ITCM banks present in CPU\n", itcm_code_sz);
373 }
374
375unregister:
376 unregister_undef_hook(&tcm_hook);
377}
378
379
380
381
382
383
384static int __init setup_tcm_pool(void)
385{
386 u32 dtcm_pool_start = (u32) &__edtcm_data;
387 u32 itcm_pool_start = (u32) &__eitcm_text;
388 int ret;
389
390
391
392
393
394
395 tcm_pool = gen_pool_create(2, -1);
396
397 pr_debug("Setting up TCM memory pool\n");
398
399
400 if (dtcm_present) {
401 if (dtcm_pool_start < dtcm_end) {
402 ret = gen_pool_add(tcm_pool, dtcm_pool_start,
403 dtcm_end - dtcm_pool_start, -1);
404 if (ret) {
405 pr_err("CPU DTCM: could not add DTCM " \
406 "remainder to pool!\n");
407 return ret;
408 }
409 pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \
410 "the TCM memory pool\n",
411 dtcm_end - dtcm_pool_start,
412 dtcm_pool_start);
413 }
414 }
415
416
417 if (itcm_present) {
418 if (itcm_pool_start < itcm_end) {
419 ret = gen_pool_add(tcm_pool, itcm_pool_start,
420 itcm_end - itcm_pool_start, -1);
421 if (ret) {
422 pr_err("CPU ITCM: could not add ITCM " \
423 "remainder to pool!\n");
424 return ret;
425 }
426 pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \
427 "the TCM memory pool\n",
428 itcm_end - itcm_pool_start,
429 itcm_pool_start);
430 }
431 }
432 return 0;
433}
434
435core_initcall(setup_tcm_pool);
436