Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 6225/1: make TCM allocation static and common for all archs

This changes the TCM handling so that a fixed area is reserved at
0xfffe0000-0xfffeffff for TCM. This areas is used by XScale but
XScale does not have TCM so the mechanisms are mutually exclusive.

This change is needed to make TCM detection more dynamic while
still being able to compile code into it, and is a must for the
unified ARM goals: the current TCM allocation at different places
in memory for each machine would be a nightmare if you want to
compile a single image for more than one machine with TCM so it
has to be nailed down in one place.

Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Linus Walleij and committed by
Russell King
1dbd30e9 07d2a5c7

+90 -73
+7 -1
Documentation/arm/memory.txt
··· 33 33 34 34 fffe0000 fffeffff XScale cache flush area. This is used 35 35 in proc-xscale.S to flush the whole data 36 - cache. Free for other usage on non-XScale. 36 + cache. (XScale does not have TCM.) 37 + 38 + fffe8000 fffeffff DTCM mapping area for platforms with 39 + DTCM mounted inside the CPU. 40 + 41 + fffe0000 fffe7fff ITCM mapping area for platforms with 42 + ITCM mounted inside the CPU. 37 43 38 44 fff00000 fffdffff Fixmap mapping region. Addresses provided 39 45 by fix_to_virt() will be located here.
+19 -11
Documentation/arm/tcm.txt
··· 19 19 system control coprocessor. Documentation from ARM can be found 20 20 at http://infocenter.arm.com, search for "TCM Status Register" 21 21 to see documents for all CPUs. Reading this register you can 22 - determine if ITCM (bit 0) and/or DTCM (bit 16) is present in the 23 - machine. 22 + determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present 23 + in the machine. 24 24 25 25 There is further a TCM region register (search for "TCM Region 26 26 Registers" at the ARM site) that can report and modify the location ··· 35 35 the MMU, but notice that the TCM if often used in situations where 36 36 the MMU is turned off. To avoid confusion the current Linux 37 37 implementation will map the TCM 1 to 1 from physical to virtual 38 - memory in the location specified by the machine. 38 + memory in the location specified by the kernel. Currently Linux 39 + will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and 40 + on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM. 41 + 42 + Newer versions of the region registers also support dividing these 43 + TCMs in two separate banks, so for example an 8KiB ITCM is divided 44 + into two 4KiB banks with its own control registers. The idea is to 45 + be able to lock and hide one of the banks for use by the secure 46 + world (TrustZone). 39 47 40 48 TCM is used for a few things: 41 49 ··· 73 65 memory. Such a heap is great for things like saving 74 66 device state when shutting off device power domains. 75 67 76 - A machine that has TCM memory shall select HAVE_TCM in 77 - arch/arm/Kconfig for itself, and then the 78 - rest of the functionality will depend on the physical 79 - location and size of ITCM and DTCM to be defined in 80 - mach/memory.h for the machine. Code that needs to use 81 - TCM shall #include <asm/tcm.h> If the TCM is not located 82 - at the place given in memory.h it will be moved using 83 - the TCM Region registers. 68 + A machine that has TCM memory shall select HAVE_TCM from 69 + arch/arm/Kconfig for itself. Code that needs to use TCM shall 70 + #include <asm/tcm.h> 84 71 85 72 Functions to go into itcm can be tagged like this: 86 73 int __tcmfunc foo(int bar); 74 + 75 + Since these are marked to become long_calls and you may want 76 + to have functions called locally inside the TCM without 77 + wasting space, there is also the __tcmlocalfunc prefix that 78 + will make the call relative. 87 79 88 80 Variables to go into dtcm can be tagged like this: 89 81 int __tcmdata foo;
+9
arch/arm/include/asm/memory.h
··· 124 124 #endif /* !CONFIG_MMU */ 125 125 126 126 /* 127 + * We fix the TCM memories max 32 KiB ITCM resp DTCM at these 128 + * locations 129 + */ 130 + #ifdef CONFIG_HAVE_TCM 131 + #define ITCM_OFFSET UL(0xfffe0000) 132 + #define DTCM_OFFSET UL(0xfffe8000) 133 + #endif 134 + 135 + /* 127 136 * Physical vs virtual RAM address space conversion. These are 128 137 * private definitions which should NOT be used outside memory.h 129 138 * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
+48 -43
arch/arm/kernel/tcm.c
··· 18 18 #include <mach/memory.h> 19 19 #include "tcm.h" 20 20 21 - /* Scream and warn about misuse */ 22 - #if !defined(ITCM_OFFSET) || !defined(ITCM_END) || \ 23 - !defined(DTCM_OFFSET) || !defined(DTCM_END) 24 - #error "TCM support selected but offsets not defined!" 25 - #endif 26 - 27 21 static struct gen_pool *tcm_pool; 28 22 29 23 /* TCM section definitions from the linker */ 30 24 extern char __itcm_start, __sitcm_text, __eitcm_text; 31 25 extern char __dtcm_start, __sdtcm_data, __edtcm_data; 26 + 27 + /* These will be increased as we run */ 28 + u32 dtcm_end = DTCM_OFFSET; 29 + u32 itcm_end = ITCM_OFFSET; 32 30 33 31 /* 34 32 * TCM memory resources ··· 34 36 static struct resource dtcm_res = { 35 37 .name = "DTCM RAM", 36 38 .start = DTCM_OFFSET, 37 - .end = DTCM_END, 39 + .end = DTCM_OFFSET, 38 40 .flags = IORESOURCE_MEM 39 41 }; 40 42 41 43 static struct resource itcm_res = { 42 44 .name = "ITCM RAM", 43 45 .start = ITCM_OFFSET, 44 - .end = ITCM_END, 46 + .end = ITCM_OFFSET, 45 47 .flags = IORESOURCE_MEM 46 48 }; 47 49 ··· 49 51 { 50 52 .virtual = DTCM_OFFSET, 51 53 .pfn = __phys_to_pfn(DTCM_OFFSET), 52 - .length = (DTCM_END - DTCM_OFFSET + 1), 54 + .length = 0, 53 55 .type = MT_MEMORY_DTCM 54 56 } 55 57 }; ··· 58 60 { 59 61 .virtual = ITCM_OFFSET, 60 62 .pfn = __phys_to_pfn(ITCM_OFFSET), 61 - .length = (ITCM_END - ITCM_OFFSET + 1), 63 + .length = 0, 62 64 .type = MT_MEMORY_ITCM 63 65 } 64 66 }; ··· 90 92 } 91 93 EXPORT_SYMBOL(tcm_free); 92 94 93 - static void __init setup_tcm_bank(u8 type, u8 bank, u8 banks, 94 - u32 offset, u32 expected_size) 95 + static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, 96 + u32 *offset) 95 97 { 96 98 const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128, 97 99 256, 512, 1024, -1, -1, -1, -1 }; ··· 118 120 119 121 tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f]; 120 122 if (tcm_size < 0) { 121 - pr_err("CPU: %sTCM%d of unknown size!\n", 123 + pr_err("CPU: %sTCM%d of unknown size\n", 122 124 type ? "I" : "D", bank); 125 + return -EINVAL; 126 + } else if (tcm_size > 32) { 127 + pr_err("CPU: %sTCM%d larger than 32k found\n", 128 + type ? "I" : "D", bank); 129 + return -EINVAL; 123 130 } else { 124 131 pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n", 125 132 type ? "I" : "D", ··· 134 131 (tcm_region & 1) ? "" : "not "); 135 132 } 136 133 137 - if (tcm_size != (expected_size >> 10)) { 138 - pr_crit("CPU: %sTCM%d was detected %dk but expected %dk!\n", 139 - type ? "I" : "D", 140 - bank, 141 - tcm_size, 142 - (expected_size >> 10)); 143 - /* Adjust to the expected size? what can we do... */ 144 - } 145 - 146 134 /* Force move the TCM bank to where we want it, enable */ 147 - tcm_region = offset | (tcm_region & 0x00000ffeU) | 1; 135 + tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; 148 136 149 137 if (!type) 150 138 asm("mcr p15, 0, %0, c9, c1, 0" ··· 146 152 : /* No output operands */ 147 153 : "r" (tcm_region)); 148 154 155 + /* Increase offset */ 156 + *offset += (tcm_size << 10); 157 + 149 158 pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n", 150 159 type ? "I" : "D", 151 160 bank, 152 161 tcm_size, 153 162 (tcm_region & 0xfffff000U)); 163 + return 0; 154 164 } 155 - 156 - /* We expect to find what is configured for the platform */ 157 - #define DTCM_EXPECTED (DTCM_END - DTCM_OFFSET + 1) 158 - #define ITCM_EXPECTED (ITCM_END - ITCM_OFFSET + 1) 159 165 160 166 /* 161 167 * This initializes the TCM memory ··· 164 170 { 165 171 u32 tcm_status = read_cpuid_tcmstatus(); 166 172 u8 dtcm_banks = (tcm_status >> 16) & 0x03; 167 - u32 dtcm_banksize = DTCM_EXPECTED / dtcm_banks; 168 173 u8 itcm_banks = (tcm_status & 0x03); 169 - u32 itcm_banksize = ITCM_EXPECTED / itcm_banks; 170 174 char *start; 171 175 char *end; 172 176 char *ram; 177 + int ret; 173 178 int i; 174 179 175 180 /* Setup DTCM if present */ 176 - for (i = 0; i < dtcm_banks; i++) { 177 - setup_tcm_bank(0, i, dtcm_banks, 178 - DTCM_OFFSET + (i * dtcm_banksize), 179 - dtcm_banksize); 181 + if (dtcm_banks > 0) { 182 + for (i = 0; i < dtcm_banks; i++) { 183 + ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end); 184 + if (ret) 185 + return; 186 + } 187 + dtcm_res.end = dtcm_end - 1; 180 188 request_resource(&iomem_resource, &dtcm_res); 189 + dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; 181 190 iotable_init(dtcm_iomap, 1); 182 191 /* Copy data from RAM to DTCM */ 183 192 start = &__sdtcm_data; 184 193 end = &__edtcm_data; 185 194 ram = &__dtcm_start; 195 + /* This means you compiled more code than fits into DTCM */ 196 + BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET)); 186 197 memcpy(start, ram, (end-start)); 187 198 pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); 188 199 } 189 200 190 201 /* Setup ITCM if present */ 191 - for (i = 0; i < itcm_banks; i++) { 192 - setup_tcm_bank(1, i, itcm_banks, 193 - ITCM_OFFSET + (i * itcm_banksize), 194 - itcm_banksize); 202 + if (itcm_banks > 0) { 203 + for (i = 0; i < itcm_banks; i++) { 204 + ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end); 205 + if (ret) 206 + return; 207 + } 208 + itcm_res.end = itcm_end - 1; 195 209 request_resource(&iomem_resource, &itcm_res); 210 + itcm_iomap[0].length = itcm_end - ITCM_OFFSET; 196 211 iotable_init(itcm_iomap, 1); 197 212 /* Copy code from RAM to ITCM */ 198 213 start = &__sitcm_text; 199 214 end = &__eitcm_text; 200 215 ram = &__itcm_start; 216 + /* This means you compiled more code than fits into ITCM */ 217 + BUG_ON((end - start) > (itcm_end - ITCM_OFFSET)); 201 218 memcpy(start, ram, (end-start)); 202 219 pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); 203 220 } ··· 237 232 238 233 /* Add the rest of DTCM to the TCM pool */ 239 234 if (tcm_status & (0x03 << 16)) { 240 - if (dtcm_pool_start < DTCM_END) { 235 + if (dtcm_pool_start < dtcm_end) { 241 236 ret = gen_pool_add(tcm_pool, dtcm_pool_start, 242 - DTCM_END - dtcm_pool_start + 1, -1); 237 + dtcm_end - dtcm_pool_start, -1); 243 238 if (ret) { 244 239 pr_err("CPU DTCM: could not add DTCM " \ 245 240 "remainder to pool!\n"); ··· 247 242 } 248 243 pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \ 249 244 "the TCM memory pool\n", 250 - DTCM_END - dtcm_pool_start + 1, 245 + dtcm_end - dtcm_pool_start, 251 246 dtcm_pool_start); 252 247 } 253 248 } 254 249 255 250 /* Add the rest of ITCM to the TCM pool */ 256 251 if (tcm_status & 0x03) { 257 - if (itcm_pool_start < ITCM_END) { 252 + if (itcm_pool_start < itcm_end) { 258 253 ret = gen_pool_add(tcm_pool, itcm_pool_start, 259 - ITCM_END - itcm_pool_start + 1, -1); 254 + itcm_end - itcm_pool_start, -1); 260 255 if (ret) { 261 256 pr_err("CPU ITCM: could not add ITCM " \ 262 257 "remainder to pool!\n"); ··· 264 259 } 265 260 pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \ 266 261 "the TCM memory pool\n", 267 - ITCM_END - itcm_pool_start + 1, 262 + itcm_end - itcm_pool_start, 268 263 itcm_pool_start); 269 264 } 270 265 }
-8
arch/arm/mach-u300/include/mach/memory.h
··· 35 35 #endif 36 36 37 37 /* 38 - * TCM memory whereabouts 39 - */ 40 - #define ITCM_OFFSET 0xffff2000 41 - #define ITCM_END 0xffff3fff 42 - #define DTCM_OFFSET 0xffff4000 43 - #define DTCM_END 0xffff5fff 44 - 45 - /* 46 38 * We enable a real big DMA buffer if need be. 47 39 */ 48 40 #define CONSISTENT_DMA_SIZE SZ_4M
+7 -10
arch/arm/mm/init.c
··· 529 529 { 530 530 unsigned long reserved_pages, free_pages; 531 531 int i, node; 532 + #ifdef CONFIG_HAVE_TCM 533 + /* These pointers are filled in on TCM detection */ 534 + extern u32 dtcm_end; 535 + extern u32 itcm_end; 536 + #endif 532 537 533 538 #ifndef CONFIG_DISCONTIGMEM 534 539 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; ··· 617 612 printk(KERN_NOTICE "Virtual kernel memory layout:\n" 618 613 " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" 619 614 #ifdef CONFIG_HAVE_TCM 620 - #ifdef DTCM_OFFSET 621 615 " DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n" 622 - #endif 623 - #ifdef ITCM_OFFSET 624 616 " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n" 625 - #endif 626 617 #endif 627 618 " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" 628 619 #ifdef CONFIG_MMU ··· 637 636 MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + 638 637 (PAGE_SIZE)), 639 638 #ifdef CONFIG_HAVE_TCM 640 - #ifdef DTCM_OFFSET 641 - MLK(UL(DTCM_OFFSET), UL(DTCM_END + 1)), 642 - #endif 643 - #ifdef ITCM_OFFSET 644 - MLK(UL(ITCM_OFFSET), UL(ITCM_END + 1)), 645 - #endif 639 + MLK(DTCM_OFFSET, (unsigned long) dtcm_end), 640 + MLK(ITCM_OFFSET, (unsigned long) itcm_end), 646 641 #endif 647 642 MLK(FIXADDR_START, FIXADDR_TOP), 648 643 #ifdef CONFIG_MMU