^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2008-2009 ST-Ericsson AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * TCM memory handling for ARM systems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Linus Walleij <linus.walleij@stericsson.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Rickard Andersson <rickard.andersson@stericsson.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/genalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/string.h> /* memcpy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/cputype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/system_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/tcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define TCMTR_FORMAT_MASK 0xe0000000U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static struct gen_pool *tcm_pool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static bool dtcm_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static bool itcm_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* TCM section definitions from the linker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) extern char __itcm_start, __sitcm_text, __eitcm_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) extern char __dtcm_start, __sdtcm_data, __edtcm_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* These will be increased as we run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static u32 dtcm_end = DTCM_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static u32 itcm_end = ITCM_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * TCM memory resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static struct resource dtcm_res = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .name = "DTCM RAM",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .start = DTCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .end = DTCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .flags = IORESOURCE_MEM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static struct resource itcm_res = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .name = "ITCM RAM",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .start = ITCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .end = ITCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .flags = IORESOURCE_MEM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static struct map_desc dtcm_iomap[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .virtual = DTCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .pfn = __phys_to_pfn(DTCM_OFFSET),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .length = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .type = MT_MEMORY_RW_DTCM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static struct map_desc itcm_iomap[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .virtual = ITCM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .pfn = __phys_to_pfn(ITCM_OFFSET),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .length = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .type = MT_MEMORY_RWX_ITCM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * Allocate a chunk of TCM memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void *tcm_alloc(size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned long vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!tcm_pool)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) vaddr = gen_pool_alloc(tcm_pool, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (!vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return (void *) vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) EXPORT_SYMBOL(tcm_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * Free a chunk of TCM memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void tcm_free(void *addr, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) gen_pool_free(tcm_pool, (unsigned long) addr, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) EXPORT_SYMBOL(tcm_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) bool tcm_dtcm_present(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return dtcm_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) EXPORT_SYMBOL(tcm_dtcm_present);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) bool tcm_itcm_present(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return itcm_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) EXPORT_SYMBOL(tcm_itcm_present);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u32 *offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 256, 512, 1024, -1, -1, -1, -1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) u32 tcm_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int tcm_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * If there are more than one TCM bank of this type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * select the TCM bank to operate on in the TCM selection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (banks > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) asm("mcr p15, 0, %0, c9, c2, 0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) : /* No output operands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) : "r" (bank));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Read the special TCM region register c9, 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) asm("mrc p15, 0, %0, c9, c1, 0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) : "=r" (tcm_region));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) asm("mrc p15, 0, %0, c9, c1, 1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) : "=r" (tcm_region));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (tcm_size < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pr_err("CPU: %sTCM%d of unknown size\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) type ? "I" : "D", bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) } else if (tcm_size > 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) pr_err("CPU: %sTCM%d larger than 32k found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) type ? "I" : "D", bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) type ? "I" : "D",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) bank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) tcm_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) (tcm_region & 0xfffff000U),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) (tcm_region & 1) ? "" : "not ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* Not much fun you can do with a size 0 bank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (tcm_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Force move the TCM bank to where we want it, enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (!type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) asm("mcr p15, 0, %0, c9, c1, 0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) : /* No output operands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) : "r" (tcm_region));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) asm("mcr p15, 0, %0, c9, c1, 1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) : /* No output operands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) : "r" (tcm_region));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Increase offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) *offset += (tcm_size << 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) type ? "I" : "D",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) tcm_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) (tcm_region & 0xfffff000U));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * When we are running in the non-secure world and the secure world
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * has not explicitly given us access to the TCM we will get an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * undefined error when reading the TCM region register in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * setup_tcm_bank function (above).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * There are two variants of this register read that we need to trap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * the read for the data TCM and the read for the instruction TCM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * c0370628: ee196f11 mrc 15, 0, r6, cr9, cr1, {0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * c0370674: ee196f31 mrc 15, 0, r6, cr9, cr1, {1}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * Our undef hook mask explicitly matches all fields of the encoded
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * instruction other than the destination register. The mask also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * only allows operand 2 to have the values 0 or 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * The undefined hook is defined as __init and __initdata, and therefore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * must be removed before tcm_init returns.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * In this particular case (MRC with ARM condition code ALways) the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * Thumb-2 and ARM instruction encoding are identical, so this hook
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * will work on a Thumb-2 kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * See A8.8.107, DDI0406C_C ARM Architecture Reference Manual, Encoding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * T1/A1 for the bit-by-bit details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * mrc p15, 0, XX, c9, c1, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * mrc p15, 0, XX, c9, c1, 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * | | | | | | | +---- opc2 0|1 = 000|001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * | | | | | | +------- CRm 0 = 0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * | | | | | +----------- CRn 0 = 1001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * | | | | +--------------- Rt ? = ????
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * | | | +------------------- opc1 0 = 000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * | | +----------------------- coproc 15 = 1111
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * | +-------------------------- condition ALways = 1110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * +----------------------------- instruction MRC = 1110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Encoding this as per A8.8.107 of DDI0406C, Encoding T1/A1, yields:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * 1111 1111 1111 1111 0000 1111 1101 1111 Required Mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * 1110 1110 0001 1001 ???? 1111 0001 0001 mrc p15, 0, XX, c9, c1, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * 1110 1110 0001 1001 ???? 1111 0011 0001 mrc p15, 0, XX, c9, c1, 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * [ ] [ ] [ ]| [ ] [ ] [ ] [ ]| +--- CRm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * | | | | | | | | +----- SBO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * | | | | | | | +------- opc2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * | | | | | | +----------- coproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * | | | | | +---------------- Rt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * | | | | +--------------------- CRn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * | | | +------------------------- SBO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * | | +--------------------------- opc1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * | +------------------------------- instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * +------------------------------------ condition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #define TCM_REGION_READ_MASK 0xffff0fdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) #define TCM_REGION_READ_INSTR 0xee190f11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) #define DEST_REG_SHIFT 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) #define DEST_REG_MASK 0xf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static int __init tcm_handler(struct pt_regs *regs, unsigned int instr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) regs->ARM_pc += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static struct undef_hook tcm_hook __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .instr_mask = TCM_REGION_READ_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .instr_val = TCM_REGION_READ_INSTR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .cpsr_mask = MODE_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .cpsr_val = SVC_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .fn = tcm_handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * This initializes the TCM memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) void __init tcm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) u32 tcm_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) u8 dtcm_banks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u8 itcm_banks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) size_t itcm_code_sz = &__eitcm_text - &__sitcm_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) char *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) char *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) char *ram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * Prior to ARMv5 there is no TCM, and trying to read the status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * register will hang the processor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (cpu_architecture() < CPU_ARCH_ARMv5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (dtcm_code_sz || itcm_code_sz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) pr_info("CPU TCM: %u bytes of DTCM and %u bytes of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) "ITCM code compiled in, but no TCM present "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) "in pre-v5 CPU\n", dtcm_code_sz, itcm_code_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) tcm_status = read_cpuid_tcmstatus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * This code only supports v6-compatible TCMTR implementations.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (tcm_status & TCMTR_FORMAT_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) dtcm_banks = (tcm_status >> 16) & 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) itcm_banks = (tcm_status & 0x03);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) register_undef_hook(&tcm_hook);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /* Values greater than 2 for D/ITCM banks are "reserved" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (dtcm_banks > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dtcm_banks = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (itcm_banks > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) itcm_banks = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* Setup DTCM if present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (dtcm_banks > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) for (i = 0; i < dtcm_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) goto unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* This means you compiled more code than fits into DTCM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) pr_info("CPU DTCM: %u bytes of code compiled to "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) "DTCM but only %lu bytes of DTCM present\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) dtcm_code_sz, (dtcm_end - DTCM_OFFSET));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) goto no_dtcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * This means that the DTCM sizes were 0 or the DTCM banks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * were inaccessible due to TrustZone configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (!(dtcm_end - DTCM_OFFSET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto no_dtcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) dtcm_res.end = dtcm_end - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) request_resource(&iomem_resource, &dtcm_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) iotable_init(dtcm_iomap, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Copy data from RAM to DTCM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) start = &__sdtcm_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) end = &__edtcm_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ram = &__dtcm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) memcpy(start, ram, dtcm_code_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) pr_debug("CPU DTCM: copied data from %p - %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) start, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) dtcm_present = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) } else if (dtcm_code_sz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) "DTCM banks present in CPU\n", dtcm_code_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) no_dtcm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /* Setup ITCM if present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (itcm_banks > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) for (i = 0; i < itcm_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) goto unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* This means you compiled more code than fits into ITCM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) pr_info("CPU ITCM: %u bytes of code compiled to "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) "ITCM but only %lu bytes of ITCM present\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) itcm_code_sz, (itcm_end - ITCM_OFFSET));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) goto unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * This means that the ITCM sizes were 0 or the ITCM banks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * were inaccessible due to TrustZone configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (!(itcm_end - ITCM_OFFSET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) goto unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) itcm_res.end = itcm_end - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) request_resource(&iomem_resource, &itcm_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) iotable_init(itcm_iomap, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* Copy code from RAM to ITCM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) start = &__sitcm_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) end = &__eitcm_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ram = &__itcm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) memcpy(start, ram, itcm_code_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) pr_debug("CPU ITCM: copied code from %p - %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) start, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) itcm_present = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) } else if (itcm_code_sz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) "ITCM banks present in CPU\n", itcm_code_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) unregister_undef_hook(&tcm_hook);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * This creates the TCM memory pool and has to be done later,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * during the core_initicalls, since the allocator is not yet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * up and running when the first initialization runs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) static int __init setup_tcm_pool(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) u32 dtcm_pool_start = (u32) &__edtcm_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) u32 itcm_pool_start = (u32) &__eitcm_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * Set up malloc pool, 2^2 = 4 bytes granularity since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * the TCM is sometimes just 4 KiB. NB: pages and cache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * line alignments does not matter in TCM!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) tcm_pool = gen_pool_create(2, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) pr_debug("Setting up TCM memory pool\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Add the rest of DTCM to the TCM pool */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (dtcm_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (dtcm_pool_start < dtcm_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) ret = gen_pool_add(tcm_pool, dtcm_pool_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) dtcm_end - dtcm_pool_start, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) pr_err("CPU DTCM: could not add DTCM " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) "remainder to pool!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) "the TCM memory pool\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) dtcm_end - dtcm_pool_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) dtcm_pool_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /* Add the rest of ITCM to the TCM pool */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (itcm_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (itcm_pool_start < itcm_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) ret = gen_pool_add(tcm_pool, itcm_pool_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) itcm_end - itcm_pool_start, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pr_err("CPU ITCM: could not add ITCM " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) "remainder to pool!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) "the TCM memory pool\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) itcm_end - itcm_pool_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) itcm_pool_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) core_initcall(setup_tcm_pool);