diff options
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/arm/tcm.txt | 145 |
1 files changed, 145 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 @@ | |||
1 | ARM TCM (Tightly-Coupled Memory) handling in Linux | ||
2 | ---- | ||
3 | Written by Linus Walleij <linus.walleij@stericsson.com> | ||
4 | |||
5 | Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory). | ||
6 | This is usually just a few (4-64) KiB of RAM inside the ARM | ||
7 | processor. | ||
8 | |||
9 | Due to being embedded inside the CPU The TCM has a | ||
10 | Harvard-architecture, so there is an ITCM (instruction TCM) | ||
11 | and a DTCM (data TCM). The DTCM can not contain any | ||
12 | instructions, but the ITCM can actually contain data. | ||
13 | The size of DTCM or ITCM is minimum 4KiB so the typical | ||
14 | minimum configuration is 4KiB ITCM and 4KiB DTCM. | ||
15 | |||
16 | ARM CPU:s have special registers to read out status, physical | ||
17 | location and size of TCM memories. arch/arm/include/asm/cputype.h | ||
18 | defines a CPUID_TCM register that you can read out from the | ||
19 | system control coprocessor. Documentation from ARM can be found | ||
20 | at http://infocenter.arm.com, search for "TCM Status Register" | ||
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. | ||
24 | |||
25 | There is further a TCM region register (search for "TCM Region | ||
26 | Registers" at the ARM site) that can report and modify the location | ||
27 | size of TCM memories at runtime. This is used to read out and modify | ||
28 | TCM location and size. Notice that this is not a MMU table: you | ||
29 | actually move the physical location of the TCM around. At the | ||
30 | place you put it, it will mask any underlying RAM from the | ||
31 | CPU so it is usually wise not to overlap any physical RAM with | ||
32 | the TCM. The TCM memory exists totally outside the MMU and will | ||
33 | override any MMU mappings. | ||
34 | |||
35 | Code executing inside the ITCM does not "see" any MMU mappings | ||
36 | and e.g. register accesses must be made to physical addresses. | ||
37 | |||
38 | TCM 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 | |||
51 | There is an interface for using TCM on the ARM architecture | ||
52 | in <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 | |||
66 | A machine that has TCM memory shall select HAVE_TCM in | ||
67 | arch/arm/Kconfig for itself, and then the | ||
68 | rest of the functionality will depend on the physical | ||
69 | location and size of ITCM and DTCM to be defined in | ||
70 | mach/memory.h for the machine. Code that needs to use | ||
71 | TCM shall #include <asm/tcm.h> If the TCM is not located | ||
72 | at the place given in memory.h it will be moved using | ||
73 | the TCM Region registers. | ||
74 | |||
75 | Functions to go into itcm can be tagged like this: | ||
76 | int __tcmfunc foo(int bar); | ||
77 | |||
78 | Variables to go into dtcm can be tagged like this: | ||
79 | int __tcmdata foo; | ||
80 | |||
81 | Constants can be tagged like this: | ||
82 | int __tcmconst foo; | ||
83 | |||
84 | To put assembler into TCM just use | ||
85 | .section ".tcm.text" or .section ".tcm.data" | ||
86 | respectively. | ||
87 | |||
88 | Example code: | ||
89 | |||
90 | #include <asm/tcm.h> | ||
91 | |||
92 | /* Uninitialized data */ | ||
93 | static u32 __tcmdata tcmvar; | ||
94 | /* Initialized data */ | ||
95 | static u32 __tcmdata tcmassigned = 0x2BADBABEU; | ||
96 | /* Constant */ | ||
97 | static const u32 __tcmconst tcmconst = 0xCAFEBABEU; | ||
98 | |||
99 | static void __tcmlocalfunc tcm_to_tcm(void) | ||
100 | { | ||
101 | int i; | ||
102 | for (i = 0; i < 100; i++) | ||
103 | tcmvar ++; | ||
104 | } | ||
105 | |||
106 | static 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 | |||
116 | static 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 | } | ||