Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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