aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/tcm.txt145
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/include/asm/cputype.h5
-rw-r--r--arch/arm/include/asm/tcm.h31
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/tcm.c246
-rw-r--r--arch/arm/kernel/tcm.h17
-rw-r--r--arch/arm/kernel/vmlinux.lds.S57
-rw-r--r--arch/arm/mach-u300/include/mach/memory.h8
-rw-r--r--arch/arm/mm/init.c8
11 files changed, 525 insertions, 0 deletions
diff --git a/Documentation/arm/tcm.txt b/Documentation/arm/tcm.txt
new file mode 100644
index 000000000000..074f4be6667f
--- /dev/null
+++ b/Documentation/arm/tcm.txt
@@ -0,0 +1,145 @@
1ARM TCM (Tightly-Coupled Memory) handling in Linux
2----
3Written by Linus Walleij <linus.walleij@stericsson.com>
4
5Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory).
6This is usually just a few (4-64) KiB of RAM inside the ARM
7processor.
8
9Due to being embedded inside the CPU The TCM has a
10Harvard-architecture, so there is an ITCM (instruction TCM)
11and a DTCM (data TCM). The DTCM can not contain any
12instructions, but the ITCM can actually contain data.
13The size of DTCM or ITCM is minimum 4KiB so the typical
14minimum configuration is 4KiB ITCM and 4KiB DTCM.
15
16ARM CPU:s have special registers to read out status, physical
17location and size of TCM memories. arch/arm/include/asm/cputype.h
18defines a CPUID_TCM register that you can read out from the
19system control coprocessor. Documentation from ARM can be found
20at http://infocenter.arm.com, search for "TCM Status Register"
21to see documents for all CPUs. Reading this register you can
22determine if ITCM (bit 0) and/or DTCM (bit 16) is present in the
23machine.
24
25There is further a TCM region register (search for "TCM Region
26Registers" at the ARM site) that can report and modify the location
27size of TCM memories at runtime. This is used to read out and modify
28TCM location and size. Notice that this is not a MMU table: you
29actually move the physical location of the TCM around. At the
30place you put it, it will mask any underlying RAM from the
31CPU so it is usually wise not to overlap any physical RAM with
32the TCM. The TCM memory exists totally outside the MMU and will
33override any MMU mappings.
34
35Code executing inside the ITCM does not "see" any MMU mappings
36and e.g. register accesses must be made to physical addresses.
37
38TCM is used for a few things:
39
40- FIQ and other interrupt handlers that need deterministic
41 timing and cannot wait for cache misses.
42
43- Idle loops where all external RAM is set to self-refresh
44 retention mode, so only on-chip RAM is accessible by
45 the CPU and then we hang inside ITCM waiting for an
46 interrupt.
47
48- Other operations which implies shutting off or reconfiguring
49 the external RAM controller.
50
51There is an interface for using TCM on the ARM architecture
52in <asm/tcm.h>. Using this interface it is possible to:
53
54- Define the physical address and size of ITCM and DTCM.
55
56- Tag functions to be compiled into ITCM.
57
58- Tag data and constants to be allocated to DTCM and ITCM.
59
60- Have the remaining TCM RAM added to a special
61 allocation pool with gen_pool_create() and gen_pool_add()
62 and provice tcm_alloc() and tcm_free() for this
63 memory. Such a heap is great for things like saving
64 device state when shutting off device power domains.
65
66A machine that has TCM memory shall select HAVE_TCM in
67arch/arm/Kconfig for itself, and then the
68rest of the functionality will depend on the physical
69location and size of ITCM and DTCM to be defined in
70mach/memory.h for the machine. Code that needs to use
71TCM shall #include <asm/tcm.h> If the TCM is not located
72at the place given in memory.h it will be moved using
73the TCM Region registers.
74
75Functions to go into itcm can be tagged like this:
76int __tcmfunc foo(int bar);
77
78Variables to go into dtcm can be tagged like this:
79int __tcmdata foo;
80
81Constants can be tagged like this:
82int __tcmconst foo;
83
84To put assembler into TCM just use
85.section ".tcm.text" or .section ".tcm.data"
86respectively.
87
88Example code:
89
90#include <asm/tcm.h>
91
92/* Uninitialized data */
93static u32 __tcmdata tcmvar;
94/* Initialized data */
95static u32 __tcmdata tcmassigned = 0x2BADBABEU;
96/* Constant */
97static const u32 __tcmconst tcmconst = 0xCAFEBABEU;
98
99static void __tcmlocalfunc tcm_to_tcm(void)
100{
101 int i;
102 for (i = 0; i < 100; i++)
103 tcmvar ++;
104}
105
106static void __tcmfunc hello_tcm(void)
107{
108 /* Some abstract code that runs in ITCM */
109 int i;
110 for (i = 0; i < 100; i++) {
111 tcmvar ++;
112 }
113 tcm_to_tcm();
114}
115
116static void __init test_tcm(void)
117{
118 u32 *tcmem;
119 int i;
120
121 hello_tcm();
122 printk("Hello TCM executed from ITCM RAM\n");
123
124 printk("TCM variable from testrun: %u @ %p\n", tcmvar, &tcmvar);
125 tcmvar = 0xDEADBEEFU;
126 printk("TCM variable: 0x%x @ %p\n", tcmvar, &tcmvar);
127
128 printk("TCM assigned variable: 0x%x @ %p\n", tcmassigned, &tcmassigned);
129
130 printk("TCM constant: 0x%x @ %p\n", tcmconst, &tcmconst);
131
132 /* Allocate some TCM memory from the pool */
133 tcmem = tcm_alloc(20);
134 if (tcmem) {
135 printk("TCM Allocated 20 bytes of TCM @ %p\n", tcmem);
136 tcmem[0] = 0xDEADBEEFU;
137 tcmem[1] = 0x2BADBABEU;
138 tcmem[2] = 0xCAFEBABEU;
139 tcmem[3] = 0xDEADBEEFU;
140 tcmem[4] = 0x2BADBABEU;
141 for (i = 0; i < 5; i++)
142 printk("TCM tcmem[%d] = %08x\n", i, tcmem[i]);
143 tcm_free(tcmem, 20);
144 }
145}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d778a699f577..1c4119c60040 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -46,6 +46,10 @@ config GENERIC_CLOCKEVENTS_BROADCAST
46 depends on GENERIC_CLOCKEVENTS 46 depends on GENERIC_CLOCKEVENTS
47 default y if SMP && !LOCAL_TIMERS 47 default y if SMP && !LOCAL_TIMERS
48 48
49config HAVE_TCM
50 bool
51 select GENERIC_ALLOCATOR
52
49config NO_IOPORT 53config NO_IOPORT
50 bool 54 bool
51 55
@@ -649,6 +653,7 @@ config ARCH_U300
649 bool "ST-Ericsson U300 Series" 653 bool "ST-Ericsson U300 Series"
650 depends on MMU 654 depends on MMU
651 select CPU_ARM926T 655 select CPU_ARM926T
656 select HAVE_TCM
652 select ARM_AMBA 657 select ARM_AMBA
653 select ARM_VIC 658 select ARM_VIC
654 select GENERIC_TIME 659 select GENERIC_TIME
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index b3e656c6fb78..54a1f1d76b14 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -63,6 +63,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
63 return read_cpuid(CPUID_CACHETYPE); 63 return read_cpuid(CPUID_CACHETYPE);
64} 64}
65 65
66static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void)
67{
68 return read_cpuid(CPUID_TCM);
69}
70
66/* 71/*
67 * Intel's XScale3 core supports some v6 features (supersections, L2) 72 * Intel's XScale3 core supports some v6 features (supersections, L2)
68 * but advertises itself as v5 as it does not support the v6 ISA. For 73 * but advertises itself as v5 as it does not support the v6 ISA. For
diff --git a/arch/arm/include/asm/tcm.h b/arch/arm/include/asm/tcm.h
new file mode 100644
index 000000000000..5929ef5d927a
--- /dev/null
+++ b/arch/arm/include/asm/tcm.h
@@ -0,0 +1,31 @@
1/*
2 *
3 * Copyright (C) 2008-2009 ST-Ericsson AB
4 * License terms: GNU General Public License (GPL) version 2
5 *
6 * Author: Rickard Andersson <rickard.andersson@stericsson.com>
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
8 *
9 */
10#ifndef __ASMARM_TCM_H
11#define __ASMARM_TCM_H
12
13#ifndef CONFIG_HAVE_TCM
14#error "You should not be including tcm.h unless you have a TCM!"
15#endif
16
17#include <linux/compiler.h>
18
19/* Tag variables with this */
20#define __tcmdata __section(.tcm.data)
21/* Tag constants with this */
22#define __tcmconst __section(.tcm.rodata)
23/* Tag functions inside TCM called from outside TCM with this */
24#define __tcmfunc __attribute__((long_call)) __section(.tcm.text) noinline
25/* Tag function inside TCM called from inside TCM with this */
26#define __tcmlocalfunc __section(.tcm.text)
27
28void *tcm_alloc(size_t len);
29void tcm_free(void *addr, size_t len);
30
31#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 3213c9382b17..6808e01aedcd 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
34obj-$(CONFIG_ARM_THUMBEE) += thumbee.o 34obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
35obj-$(CONFIG_KGDB) += kgdb.o 35obj-$(CONFIG_KGDB) += kgdb.o
36obj-$(CONFIG_ARM_UNWIND) += unwind.o 36obj-$(CONFIG_ARM_UNWIND) += unwind.o
37obj-$(CONFIG_HAVE_TCM) += tcm.o
37 38
38obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o 39obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
39AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 40AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index d4d4f77c91b2..c6c57b640b6b 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -45,6 +45,7 @@
45 45
46#include "compat.h" 46#include "compat.h"
47#include "atags.h" 47#include "atags.h"
48#include "tcm.h"
48 49
49#ifndef MEM_SIZE 50#ifndef MEM_SIZE
50#define MEM_SIZE (16*1024*1024) 51#define MEM_SIZE (16*1024*1024)
@@ -749,6 +750,7 @@ void __init setup_arch(char **cmdline_p)
749#endif 750#endif
750 751
751 cpu_init(); 752 cpu_init();
753 tcm_init();
752 754
753 /* 755 /*
754 * Set up various architecture-specific pointers 756 * Set up various architecture-specific pointers
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
new file mode 100644
index 000000000000..e50303868f1b
--- /dev/null
+++ b/arch/arm/kernel/tcm.c
@@ -0,0 +1,246 @@
1/*
2 * Copyright (C) 2008-2009 ST-Ericsson AB
3 * License terms: GNU General Public License (GPL) version 2
4 * TCM memory handling for ARM systems
5 *
6 * Author: Linus Walleij <linus.walleij@stericsson.com>
7 * Author: Rickard Andersson <rickard.andersson@stericsson.com>
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> /* memcpy */
16#include <asm/page.h> /* PAGE_SHIFT */
17#include <asm/cputype.h>
18#include <asm/mach/map.h>
19#include <mach/memory.h>
20#include "tcm.h"
21
22/* Scream and warn about misuse */
23#if !defined(ITCM_OFFSET) || !defined(ITCM_END) || \
24 !defined(DTCM_OFFSET) || !defined(DTCM_END)
25#error "TCM support selected but offsets not defined!"
26#endif
27
28static struct gen_pool *tcm_pool;
29
30/* TCM section definitions from the linker */
31extern char __itcm_start, __sitcm_text, __eitcm_text;
32extern char __dtcm_start, __sdtcm_data, __edtcm_data;
33
34/*
35 * TCM memory resources
36 */
37static struct resource dtcm_res = {
38 .name = "DTCM RAM",
39 .start = DTCM_OFFSET,
40 .end = DTCM_END,
41 .flags = IORESOURCE_MEM
42};
43
44static struct resource itcm_res = {
45 .name = "ITCM RAM",
46 .start = ITCM_OFFSET,
47 .end = ITCM_END,
48 .flags = IORESOURCE_MEM
49};
50
51static struct map_desc dtcm_iomap[] __initdata = {
52 {
53 .virtual = DTCM_OFFSET,
54 .pfn = __phys_to_pfn(DTCM_OFFSET),
55 .length = (DTCM_END - DTCM_OFFSET + 1),
56 .type = MT_UNCACHED
57 }
58};
59
60static struct map_desc itcm_iomap[] __initdata = {
61 {
62 .virtual = ITCM_OFFSET,
63 .pfn = __phys_to_pfn(ITCM_OFFSET),
64 .length = (ITCM_END - ITCM_OFFSET + 1),
65 .type = MT_UNCACHED
66 }
67};
68
69/*
70 * Allocate a chunk of TCM memory
71 */
72void *tcm_alloc(size_t len)
73{
74 unsigned long vaddr;
75
76 if (!tcm_pool)
77 return NULL;
78
79 vaddr = gen_pool_alloc(tcm_pool, len);
80 if (!vaddr)
81 return NULL;
82
83 return (void *) vaddr;
84}
85EXPORT_SYMBOL(tcm_alloc);
86
87/*
88 * Free a chunk of TCM memory
89 */
90void tcm_free(void *addr, size_t len)
91{
92 gen_pool_free(tcm_pool, (unsigned long) addr, len);
93}
94EXPORT_SYMBOL(tcm_free);
95
96
97static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
98{
99 const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128,
100 256, 512, 1024, -1, -1, -1, -1 };
101 u32 tcm_region;
102 int tcm_size;
103
104 /* Read the special TCM region register c9, 0 */
105 if (!type)
106 asm("mrc p15, 0, %0, c9, c1, 0"
107 : "=r" (tcm_region));
108 else
109 asm("mrc p15, 0, %0, c9, c1, 1"
110 : "=r" (tcm_region));
111
112 tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f];
113 if (tcm_size < 0) {
114 pr_err("CPU: %sTCM of unknown size!\n",
115 type ? "I" : "D");
116 } else {
117 pr_info("CPU: found %sTCM %dk @ %08x, %senabled\n",
118 type ? "I" : "D",
119 tcm_size,
120 (tcm_region & 0xfffff000U),
121 (tcm_region & 1) ? "" : "not ");
122 }
123
124 if (tcm_size != expected_size) {
125 pr_crit("CPU: %sTCM was detected %dk but expected %dk!\n",
126 type ? "I" : "D",
127 tcm_size,
128 expected_size);
129 /* Adjust to the expected size? what can we do... */
130 }
131
132 /* Force move the TCM bank to where we want it, enable */
133 tcm_region = offset | (tcm_region & 0x00000ffeU) | 1;
134
135 if (!type)
136 asm("mcr p15, 0, %0, c9, c1, 0"
137 : /* No output operands */
138 : "r" (tcm_region));
139 else
140 asm("mcr p15, 0, %0, c9, c1, 1"
141 : /* No output operands */
142 : "r" (tcm_region));
143
144 pr_debug("CPU: moved %sTCM %dk to %08x, enabled\n",
145 type ? "I" : "D",
146 tcm_size,
147 (tcm_region & 0xfffff000U));
148}
149
150/*
151 * This initializes the TCM memory
152 */
153void __init tcm_init(void)
154{
155 u32 tcm_status = read_cpuid_tcmstatus();
156 char *start;
157 char *end;
158 char *ram;
159
160 /* Setup DTCM if present */
161 if (tcm_status & (1 << 16)) {
162 setup_tcm_bank(0, DTCM_OFFSET,
163 (DTCM_END - DTCM_OFFSET + 1) >> 10);
164 request_resource(&iomem_resource, &dtcm_res);
165 iotable_init(dtcm_iomap, 1);
166 /* Copy data from RAM to DTCM */
167 start = &__sdtcm_data;
168 end = &__edtcm_data;
169 ram = &__dtcm_start;
170 memcpy(start, ram, (end-start));
171 pr_debug("CPU DTCM: copied data from %p - %p\n", start, end);
172 }
173
174 /* Setup ITCM if present */
175 if (tcm_status & 1) {
176 setup_tcm_bank(1, ITCM_OFFSET,
177 (ITCM_END - ITCM_OFFSET + 1) >> 10);
178 request_resource(&iomem_resource, &itcm_res);
179 iotable_init(itcm_iomap, 1);
180 /* Copy code from RAM to ITCM */
181 start = &__sitcm_text;
182 end = &__eitcm_text;
183 ram = &__itcm_start;
184 memcpy(start, ram, (end-start));
185 pr_debug("CPU ITCM: copied code from %p - %p\n", start, end);
186 }
187}
188
189/*
190 * This creates the TCM memory pool and has to be done later,
191 * during the core_initicalls, since the allocator is not yet
192 * up and running when the first initialization runs.
193 */
194static int __init setup_tcm_pool(void)
195{
196 u32 tcm_status = read_cpuid_tcmstatus();
197 u32 dtcm_pool_start = (u32) &__edtcm_data;
198 u32 itcm_pool_start = (u32) &__eitcm_text;
199 int ret;
200
201 /*
202 * Set up malloc pool, 2^2 = 4 bytes granularity since
203 * the TCM is sometimes just 4 KiB. NB: pages and cache
204 * line alignments does not matter in TCM!
205 */
206 tcm_pool = gen_pool_create(2, -1);
207
208 pr_debug("Setting up TCM memory pool\n");
209
210 /* Add the rest of DTCM to the TCM pool */
211 if (tcm_status & (1 << 16)) {
212 if (dtcm_pool_start < DTCM_END) {
213 ret = gen_pool_add(tcm_pool, dtcm_pool_start,
214 DTCM_END - dtcm_pool_start + 1, -1);
215 if (ret) {
216 pr_err("CPU DTCM: could not add DTCM " \
217 "remainder to pool!\n");
218 return ret;
219 }
220 pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \
221 "the TCM memory pool\n",
222 DTCM_END - dtcm_pool_start + 1,
223 dtcm_pool_start);
224 }
225 }
226
227 /* Add the rest of ITCM to the TCM pool */
228 if (tcm_status & 1) {
229 if (itcm_pool_start < ITCM_END) {
230 ret = gen_pool_add(tcm_pool, itcm_pool_start,
231 ITCM_END - itcm_pool_start + 1, -1);
232 if (ret) {
233 pr_err("CPU ITCM: could not add ITCM " \
234 "remainder to pool!\n");
235 return ret;
236 }
237 pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \
238 "the TCM memory pool\n",
239 ITCM_END - itcm_pool_start + 1,
240 itcm_pool_start);
241 }
242 }
243 return 0;
244}
245
246core_initcall(setup_tcm_pool);
diff --git a/arch/arm/kernel/tcm.h b/arch/arm/kernel/tcm.h
new file mode 100644
index 000000000000..8015ad434a40
--- /dev/null
+++ b/arch/arm/kernel/tcm.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2008-2009 ST-Ericsson AB
3 * License terms: GNU General Public License (GPL) version 2
4 * TCM memory handling for ARM systems
5 *
6 * Author: Linus Walleij <linus.walleij@stericsson.com>
7 * Author: Rickard Andersson <rickard.andersson@stericsson.com>
8 */
9
10#ifdef CONFIG_HAVE_TCM
11void __init tcm_init(void);
12#else
13/* No TCM support, just blank inlines to be optimized out */
14inline void tcm_init(void)
15{
16}
17#endif
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 69371028a202..39d3ffb9ff2b 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -198,6 +198,63 @@ SECTIONS
198 } 198 }
199 _edata_loc = __data_loc + SIZEOF(.data); 199 _edata_loc = __data_loc + SIZEOF(.data);
200 200
201#ifdef CONFIG_HAVE_TCM
202 /*
203 * We align everything to a page boundary so we can
204 * free it after init has commenced and TCM contents have
205 * been copied to its destination.
206 */
207 .tcm_start : {
208 . = ALIGN(PAGE_SIZE);
209 __tcm_start = .;
210 __itcm_start = .;
211 }
212
213 /*
214 * Link these to the ITCM RAM
215 * Put VMA to the TCM address and LMA to the common RAM
216 * and we'll upload the contents from RAM to TCM and free
217 * the used RAM after that.
218 */
219 .text_itcm ITCM_OFFSET : AT(__itcm_start)
220 {
221 __sitcm_text = .;
222 *(.tcm.text)
223 *(.tcm.rodata)
224 . = ALIGN(4);
225 __eitcm_text = .;
226 }
227
228 /*
229 * Reset the dot pointer, this is needed to create the
230 * relative __dtcm_start below (to be used as extern in code).
231 */
232 . = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm);
233
234 .dtcm_start : {
235 __dtcm_start = .;
236 }
237
238 /* TODO: add remainder of ITCM as well, that can be used for data! */
239 .data_dtcm DTCM_OFFSET : AT(__dtcm_start)
240 {
241 . = ALIGN(4);
242 __sdtcm_data = .;
243 *(.tcm.data)
244 . = ALIGN(4);
245 __edtcm_data = .;
246 }
247
248 /* Reset the dot pointer or the linker gets confused */
249 . = ADDR(.dtcm_start) + SIZEOF(.data_dtcm);
250
251 /* End marker for freeing TCM copy in linked object */
252 .tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){
253 . = ALIGN(PAGE_SIZE);
254 __tcm_end = .;
255 }
256#endif
257
201 .bss : { 258 .bss : {
202 __bss_start = .; /* BSS */ 259 __bss_start = .; /* BSS */
203 *(.bss) 260 *(.bss)
diff --git a/arch/arm/mach-u300/include/mach/memory.h b/arch/arm/mach-u300/include/mach/memory.h
index bf134bcc129d..ab000df7fc03 100644
--- a/arch/arm/mach-u300/include/mach/memory.h
+++ b/arch/arm/mach-u300/include/mach/memory.h
@@ -35,6 +35,14 @@
35#endif 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/*
38 * We enable a real big DMA buffer if need be. 46 * We enable a real big DMA buffer if need be.
39 */ 47 */
40#define CONSISTENT_DMA_SIZE SZ_4M 48#define CONSISTENT_DMA_SIZE SZ_4M
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index ea36186f32c3..764d5dc9af76 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -613,6 +613,14 @@ void __init mem_init(void)
613 613
614void free_initmem(void) 614void free_initmem(void)
615{ 615{
616#ifdef CONFIG_HAVE_TCM
617 extern char *__tcm_start, *__tcm_end;
618
619 totalram_pages += free_area(__phys_to_pfn(__pa(__tcm_start)),
620 __phys_to_pfn(__pa(__tcm_end)),
621 "TCM link");
622#endif
623
616 if (!machine_is_integrator() && !machine_is_cintegrator()) 624 if (!machine_is_integrator() && !machine_is_cintegrator())
617 totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), 625 totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
618 __phys_to_pfn(__pa(__init_end)), 626 __phys_to_pfn(__pa(__init_end)),