diff options
author | Linus Walleij <linus.walleij@stericsson.com> | 2010-07-12 16:51:41 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-07-18 15:29:48 -0400 |
commit | 598509779e5b8037d371df764d7438744a24b61f (patch) | |
tree | fc38aed80a8d64d9afe36b806c6c73aa184f6a2e /arch/arm/kernel | |
parent | cb9d7707cd9be57830f31616233f6a872ca8416d (diff) |
ARM: 6223/1: support multiple TCM banks
CPUs v6 and up support multiple TCM banks, for example an ITCM of
8k is supplied in two 4k banks. This makes the TCM work on the
1176JZF-S devchip.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/tcm.c | 68 |
1 files changed, 46 insertions, 22 deletions
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index 0c62aa2c86ea..f2ead32c1aa0 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c | |||
@@ -92,14 +92,24 @@ void tcm_free(void *addr, size_t len) | |||
92 | } | 92 | } |
93 | EXPORT_SYMBOL(tcm_free); | 93 | EXPORT_SYMBOL(tcm_free); |
94 | 94 | ||
95 | 95 | static void __init setup_tcm_bank(u8 type, u8 bank, u8 banks, | |
96 | static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size) | 96 | u32 offset, u32 expected_size) |
97 | { | 97 | { |
98 | const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128, | 98 | const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128, |
99 | 256, 512, 1024, -1, -1, -1, -1 }; | 99 | 256, 512, 1024, -1, -1, -1, -1 }; |
100 | u32 tcm_region; | 100 | u32 tcm_region; |
101 | int tcm_size; | 101 | int tcm_size; |
102 | 102 | ||
103 | /* | ||
104 | * If there are more than one TCM bank of this type, | ||
105 | * select the TCM bank to operate on in the TCM selection | ||
106 | * register. | ||
107 | */ | ||
108 | if (banks > 1) | ||
109 | asm("mcr p15, 0, %0, c9, c2, 0" | ||
110 | : /* No output operands */ | ||
111 | : "r" (bank)); | ||
112 | |||
103 | /* Read the special TCM region register c9, 0 */ | 113 | /* Read the special TCM region register c9, 0 */ |
104 | if (!type) | 114 | if (!type) |
105 | asm("mrc p15, 0, %0, c9, c1, 0" | 115 | asm("mrc p15, 0, %0, c9, c1, 0" |
@@ -110,21 +120,23 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size) | |||
110 | 120 | ||
111 | tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f]; | 121 | tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f]; |
112 | if (tcm_size < 0) { | 122 | if (tcm_size < 0) { |
113 | pr_err("CPU: %sTCM of unknown size!\n", | 123 | pr_err("CPU: %sTCM%d of unknown size!\n", |
114 | type ? "I" : "D"); | 124 | type ? "I" : "D", bank); |
115 | } else { | 125 | } else { |
116 | pr_info("CPU: found %sTCM %dk @ %08x, %senabled\n", | 126 | pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n", |
117 | type ? "I" : "D", | 127 | type ? "I" : "D", |
128 | bank, | ||
118 | tcm_size, | 129 | tcm_size, |
119 | (tcm_region & 0xfffff000U), | 130 | (tcm_region & 0xfffff000U), |
120 | (tcm_region & 1) ? "" : "not "); | 131 | (tcm_region & 1) ? "" : "not "); |
121 | } | 132 | } |
122 | 133 | ||
123 | if (tcm_size != expected_size) { | 134 | if (tcm_size != (expected_size >> 10)) { |
124 | pr_crit("CPU: %sTCM was detected %dk but expected %dk!\n", | 135 | pr_crit("CPU: %sTCM%d was detected %dk but expected %dk!\n", |
125 | type ? "I" : "D", | 136 | type ? "I" : "D", |
126 | tcm_size, | 137 | bank, |
127 | expected_size); | 138 | tcm_size, |
139 | (expected_size >> 10)); | ||
128 | /* Adjust to the expected size? what can we do... */ | 140 | /* Adjust to the expected size? what can we do... */ |
129 | } | 141 | } |
130 | 142 | ||
@@ -140,26 +152,37 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size) | |||
140 | : /* No output operands */ | 152 | : /* No output operands */ |
141 | : "r" (tcm_region)); | 153 | : "r" (tcm_region)); |
142 | 154 | ||
143 | pr_debug("CPU: moved %sTCM %dk to %08x, enabled\n", | 155 | pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n", |
144 | type ? "I" : "D", | 156 | type ? "I" : "D", |
145 | tcm_size, | 157 | bank, |
146 | (tcm_region & 0xfffff000U)); | 158 | tcm_size, |
159 | (tcm_region & 0xfffff000U)); | ||
147 | } | 160 | } |
148 | 161 | ||
162 | /* We expect to find what is configured for the platform */ | ||
163 | #define DTCM_EXPECTED (DTCM_END - DTCM_OFFSET + 1) | ||
164 | #define ITCM_EXPECTED (ITCM_END - ITCM_OFFSET + 1) | ||
165 | |||
149 | /* | 166 | /* |
150 | * This initializes the TCM memory | 167 | * This initializes the TCM memory |
151 | */ | 168 | */ |
152 | void __init tcm_init(void) | 169 | void __init tcm_init(void) |
153 | { | 170 | { |
154 | u32 tcm_status = read_cpuid_tcmstatus(); | 171 | u32 tcm_status = read_cpuid_tcmstatus(); |
172 | u8 dtcm_banks = (tcm_status >> 16) & 0x03; | ||
173 | u32 dtcm_banksize = DTCM_EXPECTED / dtcm_banks; | ||
174 | u8 itcm_banks = (tcm_status & 0x03); | ||
175 | u32 itcm_banksize = ITCM_EXPECTED / itcm_banks; | ||
155 | char *start; | 176 | char *start; |
156 | char *end; | 177 | char *end; |
157 | char *ram; | 178 | char *ram; |
179 | int i; | ||
158 | 180 | ||
159 | /* Setup DTCM if present */ | 181 | /* Setup DTCM if present */ |
160 | if (tcm_status & (1 << 16)) { | 182 | for (i = 0; i < dtcm_banks; i++) { |
161 | setup_tcm_bank(0, DTCM_OFFSET, | 183 | setup_tcm_bank(0, i, dtcm_banks, |
162 | (DTCM_END - DTCM_OFFSET + 1) >> 10); | 184 | DTCM_OFFSET + (i * dtcm_banksize), |
185 | dtcm_banksize); | ||
163 | request_resource(&iomem_resource, &dtcm_res); | 186 | request_resource(&iomem_resource, &dtcm_res); |
164 | iotable_init(dtcm_iomap, 1); | 187 | iotable_init(dtcm_iomap, 1); |
165 | /* Copy data from RAM to DTCM */ | 188 | /* Copy data from RAM to DTCM */ |
@@ -171,9 +194,10 @@ void __init tcm_init(void) | |||
171 | } | 194 | } |
172 | 195 | ||
173 | /* Setup ITCM if present */ | 196 | /* Setup ITCM if present */ |
174 | if (tcm_status & 1) { | 197 | for (i = 0; i < itcm_banks; i++) { |
175 | setup_tcm_bank(1, ITCM_OFFSET, | 198 | setup_tcm_bank(1, i, itcm_banks, |
176 | (ITCM_END - ITCM_OFFSET + 1) >> 10); | 199 | ITCM_OFFSET + (i * itcm_banksize), |
200 | itcm_banksize); | ||
177 | request_resource(&iomem_resource, &itcm_res); | 201 | request_resource(&iomem_resource, &itcm_res); |
178 | iotable_init(itcm_iomap, 1); | 202 | iotable_init(itcm_iomap, 1); |
179 | /* Copy code from RAM to ITCM */ | 203 | /* Copy code from RAM to ITCM */ |
@@ -207,7 +231,7 @@ static int __init setup_tcm_pool(void) | |||
207 | pr_debug("Setting up TCM memory pool\n"); | 231 | pr_debug("Setting up TCM memory pool\n"); |
208 | 232 | ||
209 | /* Add the rest of DTCM to the TCM pool */ | 233 | /* Add the rest of DTCM to the TCM pool */ |
210 | if (tcm_status & (1 << 16)) { | 234 | if (tcm_status & (0x03 << 16)) { |
211 | if (dtcm_pool_start < DTCM_END) { | 235 | if (dtcm_pool_start < DTCM_END) { |
212 | ret = gen_pool_add(tcm_pool, dtcm_pool_start, | 236 | ret = gen_pool_add(tcm_pool, dtcm_pool_start, |
213 | DTCM_END - dtcm_pool_start + 1, -1); | 237 | DTCM_END - dtcm_pool_start + 1, -1); |
@@ -224,7 +248,7 @@ static int __init setup_tcm_pool(void) | |||
224 | } | 248 | } |
225 | 249 | ||
226 | /* Add the rest of ITCM to the TCM pool */ | 250 | /* Add the rest of ITCM to the TCM pool */ |
227 | if (tcm_status & 1) { | 251 | if (tcm_status & 0x03) { |
228 | if (itcm_pool_start < ITCM_END) { | 252 | if (itcm_pool_start < ITCM_END) { |
229 | ret = gen_pool_add(tcm_pool, itcm_pool_start, | 253 | ret = gen_pool_add(tcm_pool, itcm_pool_start, |
230 | ITCM_END - itcm_pool_start + 1, -1); | 254 | ITCM_END - itcm_pool_start + 1, -1); |