0001 ==================================================
0002 ARM TCM (Tightly-Coupled Memory) handling in Linux
0003 ==================================================
0004
0005 Written by Linus Walleij <linus.walleij@stericsson.com>
0006
0007 Some ARM SoCs have a so-called TCM (Tightly-Coupled Memory).
0008 This is usually just a few (4-64) KiB of RAM inside the ARM
0009 processor.
0010
0011 Due to being embedded inside the CPU, the TCM has a
0012 Harvard-architecture, so there is an ITCM (instruction TCM)
0013 and a DTCM (data TCM). The DTCM can not contain any
0014 instructions, but the ITCM can actually contain data.
0015 The size of DTCM or ITCM is minimum 4KiB so the typical
0016 minimum configuration is 4KiB ITCM and 4KiB DTCM.
0017
0018 ARM CPUs have special registers to read out status, physical
0019 location and size of TCM memories. arch/arm/include/asm/cputype.h
0020 defines a CPUID_TCM register that you can read out from the
0021 system control coprocessor. Documentation from ARM can be found
0022 at http://infocenter.arm.com, search for "TCM Status Register"
0023 to see documents for all CPUs. Reading this register you can
0024 determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present
0025 in the machine.
0026
0027 There is further a TCM region register (search for "TCM Region
0028 Registers" at the ARM site) that can report and modify the location
0029 size of TCM memories at runtime. This is used to read out and modify
0030 TCM location and size. Notice that this is not a MMU table: you
0031 actually move the physical location of the TCM around. At the
0032 place you put it, it will mask any underlying RAM from the
0033 CPU so it is usually wise not to overlap any physical RAM with
0034 the TCM.
0035
0036 The TCM memory can then be remapped to another address again using
0037 the MMU, but notice that the TCM is often used in situations where
0038 the MMU is turned off. To avoid confusion the current Linux
0039 implementation will map the TCM 1 to 1 from physical to virtual
0040 memory in the location specified by the kernel. Currently Linux
0041 will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and
0042 on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM.
0043
0044 Newer versions of the region registers also support dividing these
0045 TCMs in two separate banks, so for example an 8KiB ITCM is divided
0046 into two 4KiB banks with its own control registers. The idea is to
0047 be able to lock and hide one of the banks for use by the secure
0048 world (TrustZone).
0049
0050 TCM is used for a few things:
0051
0052 - FIQ and other interrupt handlers that need deterministic
0053 timing and cannot wait for cache misses.
0054
0055 - Idle loops where all external RAM is set to self-refresh
0056 retention mode, so only on-chip RAM is accessible by
0057 the CPU and then we hang inside ITCM waiting for an
0058 interrupt.
0059
0060 - Other operations which implies shutting off or reconfiguring
0061 the external RAM controller.
0062
0063 There is an interface for using TCM on the ARM architecture
0064 in <asm/tcm.h>. Using this interface it is possible to:
0065
0066 - Define the physical address and size of ITCM and DTCM.
0067
0068 - Tag functions to be compiled into ITCM.
0069
0070 - Tag data and constants to be allocated to DTCM and ITCM.
0071
0072 - Have the remaining TCM RAM added to a special
0073 allocation pool with gen_pool_create() and gen_pool_add()
0074 and provice tcm_alloc() and tcm_free() for this
0075 memory. Such a heap is great for things like saving
0076 device state when shutting off device power domains.
0077
0078 A machine that has TCM memory shall select HAVE_TCM from
0079 arch/arm/Kconfig for itself. Code that needs to use TCM shall
0080 #include <asm/tcm.h>
0081
0082 Functions to go into itcm can be tagged like this:
0083 int __tcmfunc foo(int bar);
0084
0085 Since these are marked to become long_calls and you may want
0086 to have functions called locally inside the TCM without
0087 wasting space, there is also the __tcmlocalfunc prefix that
0088 will make the call relative.
0089
0090 Variables to go into dtcm can be tagged like this::
0091
0092 int __tcmdata foo;
0093
0094 Constants can be tagged like this::
0095
0096 int __tcmconst foo;
0097
0098 To put assembler into TCM just use::
0099
0100 .section ".tcm.text" or .section ".tcm.data"
0101
0102 respectively.
0103
0104 Example code::
0105
0106 #include <asm/tcm.h>
0107
0108 /* Uninitialized data */
0109 static u32 __tcmdata tcmvar;
0110 /* Initialized data */
0111 static u32 __tcmdata tcmassigned = 0x2BADBABEU;
0112 /* Constant */
0113 static const u32 __tcmconst tcmconst = 0xCAFEBABEU;
0114
0115 static void __tcmlocalfunc tcm_to_tcm(void)
0116 {
0117 int i;
0118 for (i = 0; i < 100; i++)
0119 tcmvar ++;
0120 }
0121
0122 static void __tcmfunc hello_tcm(void)
0123 {
0124 /* Some abstract code that runs in ITCM */
0125 int i;
0126 for (i = 0; i < 100; i++) {
0127 tcmvar ++;
0128 }
0129 tcm_to_tcm();
0130 }
0131
0132 static void __init test_tcm(void)
0133 {
0134 u32 *tcmem;
0135 int i;
0136
0137 hello_tcm();
0138 printk("Hello TCM executed from ITCM RAM\n");
0139
0140 printk("TCM variable from testrun: %u @ %p\n", tcmvar, &tcmvar);
0141 tcmvar = 0xDEADBEEFU;
0142 printk("TCM variable: 0x%x @ %p\n", tcmvar, &tcmvar);
0143
0144 printk("TCM assigned variable: 0x%x @ %p\n", tcmassigned, &tcmassigned);
0145
0146 printk("TCM constant: 0x%x @ %p\n", tcmconst, &tcmconst);
0147
0148 /* Allocate some TCM memory from the pool */
0149 tcmem = tcm_alloc(20);
0150 if (tcmem) {
0151 printk("TCM Allocated 20 bytes of TCM @ %p\n", tcmem);
0152 tcmem[0] = 0xDEADBEEFU;
0153 tcmem[1] = 0x2BADBABEU;
0154 tcmem[2] = 0xCAFEBABEU;
0155 tcmem[3] = 0xDEADBEEFU;
0156 tcmem[4] = 0x2BADBABEU;
0157 for (i = 0; i < 5; i++)
0158 printk("TCM tcmem[%d] = %08x\n", i, tcmem[i]);
0159 tcm_free(tcmem, 20);
0160 }
0161 }