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