diff options
Diffstat (limited to 'Documentation/arm/tcm.rst')
-rw-r--r-- | Documentation/arm/tcm.rst | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/Documentation/arm/tcm.rst b/Documentation/arm/tcm.rst new file mode 100644 index 000000000000..effd9c7bc968 --- /dev/null +++ b/Documentation/arm/tcm.rst | |||
@@ -0,0 +1,161 @@ | |||
1 | ================================================== | ||
2 | ARM TCM (Tightly-Coupled Memory) handling in Linux | ||
3 | ================================================== | ||
4 | |||
5 | Written by Linus Walleij <linus.walleij@stericsson.com> | ||
6 | |||
7 | Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory). | ||
8 | This is usually just a few (4-64) KiB of RAM inside the ARM | ||
9 | processor. | ||
10 | |||
11 | Due to being embedded inside the CPU The TCM has a | ||
12 | Harvard-architecture, so there is an ITCM (instruction TCM) | ||
13 | and a DTCM (data TCM). The DTCM can not contain any | ||
14 | instructions, but the ITCM can actually contain data. | ||
15 | The size of DTCM or ITCM is minimum 4KiB so the typical | ||
16 | minimum configuration is 4KiB ITCM and 4KiB DTCM. | ||
17 | |||
18 | ARM CPU:s have special registers to read out status, physical | ||
19 | location and size of TCM memories. arch/arm/include/asm/cputype.h | ||
20 | defines a CPUID_TCM register that you can read out from the | ||
21 | system control coprocessor. Documentation from ARM can be found | ||
22 | at http://infocenter.arm.com, search for "TCM Status Register" | ||
23 | to see documents for all CPUs. Reading this register you can | ||
24 | determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present | ||
25 | in the machine. | ||
26 | |||
27 | There is further a TCM region register (search for "TCM Region | ||
28 | Registers" at the ARM site) that can report and modify the location | ||
29 | size of TCM memories at runtime. This is used to read out and modify | ||
30 | TCM location and size. Notice that this is not a MMU table: you | ||
31 | actually move the physical location of the TCM around. At the | ||
32 | place you put it, it will mask any underlying RAM from the | ||
33 | CPU so it is usually wise not to overlap any physical RAM with | ||
34 | the TCM. | ||
35 | |||
36 | The TCM memory can then be remapped to another address again using | ||
37 | the MMU, but notice that the TCM if often used in situations where | ||
38 | the MMU is turned off. To avoid confusion the current Linux | ||
39 | implementation will map the TCM 1 to 1 from physical to virtual | ||
40 | memory in the location specified by the kernel. Currently Linux | ||
41 | will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and | ||
42 | on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM. | ||
43 | |||
44 | Newer versions of the region registers also support dividing these | ||
45 | TCMs in two separate banks, so for example an 8KiB ITCM is divided | ||
46 | into two 4KiB banks with its own control registers. The idea is to | ||
47 | be able to lock and hide one of the banks for use by the secure | ||
48 | world (TrustZone). | ||
49 | |||
50 | TCM is used for a few things: | ||
51 | |||
52 | - FIQ and other interrupt handlers that need deterministic | ||
53 | timing and cannot wait for cache misses. | ||
54 | |||
55 | - Idle loops where all external RAM is set to self-refresh | ||
56 | retention mode, so only on-chip RAM is accessible by | ||
57 | the CPU and then we hang inside ITCM waiting for an | ||
58 | interrupt. | ||
59 | |||
60 | - Other operations which implies shutting off or reconfiguring | ||
61 | the external RAM controller. | ||
62 | |||
63 | There is an interface for using TCM on the ARM architecture | ||
64 | in <asm/tcm.h>. Using this interface it is possible to: | ||
65 | |||
66 | - Define the physical address and size of ITCM and DTCM. | ||
67 | |||
68 | - Tag functions to be compiled into ITCM. | ||
69 | |||
70 | - Tag data and constants to be allocated to DTCM and ITCM. | ||
71 | |||
72 | - Have the remaining TCM RAM added to a special | ||
73 | allocation pool with gen_pool_create() and gen_pool_add() | ||
74 | and provice tcm_alloc() and tcm_free() for this | ||
75 | memory. Such a heap is great for things like saving | ||
76 | device state when shutting off device power domains. | ||
77 | |||
78 | A machine that has TCM memory shall select HAVE_TCM from | ||
79 | arch/arm/Kconfig for itself. Code that needs to use TCM shall | ||
80 | #include <asm/tcm.h> | ||
81 | |||
82 | Functions to go into itcm can be tagged like this: | ||
83 | int __tcmfunc foo(int bar); | ||
84 | |||
85 | Since these are marked to become long_calls and you may want | ||
86 | to have functions called locally inside the TCM without | ||
87 | wasting space, there is also the __tcmlocalfunc prefix that | ||
88 | will make the call relative. | ||
89 | |||
90 | Variables to go into dtcm can be tagged like this:: | ||
91 | |||
92 | int __tcmdata foo; | ||
93 | |||
94 | Constants can be tagged like this:: | ||
95 | |||
96 | int __tcmconst foo; | ||
97 | |||
98 | To put assembler into TCM just use:: | ||
99 | |||
100 | .section ".tcm.text" or .section ".tcm.data" | ||
101 | |||
102 | respectively. | ||
103 | |||
104 | Example code:: | ||
105 | |||
106 | #include <asm/tcm.h> | ||
107 | |||
108 | /* Uninitialized data */ | ||
109 | static u32 __tcmdata tcmvar; | ||
110 | /* Initialized data */ | ||
111 | static u32 __tcmdata tcmassigned = 0x2BADBABEU; | ||
112 | /* Constant */ | ||
113 | static const u32 __tcmconst tcmconst = 0xCAFEBABEU; | ||
114 | |||
115 | static void __tcmlocalfunc tcm_to_tcm(void) | ||
116 | { | ||
117 | int i; | ||
118 | for (i = 0; i < 100; i++) | ||
119 | tcmvar ++; | ||
120 | } | ||
121 | |||
122 | static void __tcmfunc hello_tcm(void) | ||
123 | { | ||
124 | /* Some abstract code that runs in ITCM */ | ||
125 | int i; | ||
126 | for (i = 0; i < 100; i++) { | ||
127 | tcmvar ++; | ||
128 | } | ||
129 | tcm_to_tcm(); | ||
130 | } | ||
131 | |||
132 | static void __init test_tcm(void) | ||
133 | { | ||
134 | u32 *tcmem; | ||
135 | int i; | ||
136 | |||
137 | hello_tcm(); | ||
138 | printk("Hello TCM executed from ITCM RAM\n"); | ||
139 | |||
140 | printk("TCM variable from testrun: %u @ %p\n", tcmvar, &tcmvar); | ||
141 | tcmvar = 0xDEADBEEFU; | ||
142 | printk("TCM variable: 0x%x @ %p\n", tcmvar, &tcmvar); | ||
143 | |||
144 | printk("TCM assigned variable: 0x%x @ %p\n", tcmassigned, &tcmassigned); | ||
145 | |||
146 | printk("TCM constant: 0x%x @ %p\n", tcmconst, &tcmconst); | ||
147 | |||
148 | /* Allocate some TCM memory from the pool */ | ||
149 | tcmem = tcm_alloc(20); | ||
150 | if (tcmem) { | ||
151 | printk("TCM Allocated 20 bytes of TCM @ %p\n", tcmem); | ||
152 | tcmem[0] = 0xDEADBEEFU; | ||
153 | tcmem[1] = 0x2BADBABEU; | ||
154 | tcmem[2] = 0xCAFEBABEU; | ||
155 | tcmem[3] = 0xDEADBEEFU; | ||
156 | tcmem[4] = 0x2BADBABEU; | ||
157 | for (i = 0; i < 5; i++) | ||
158 | printk("TCM tcmem[%d] = %08x\n", i, tcmem[i]); | ||
159 | tcm_free(tcmem, 20); | ||
160 | } | ||
161 | } | ||