162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008-2009 ST-Ericsson AB 462306a36Sopenharmony_ci * TCM memory handling for ARM systems 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Linus Walleij <linus.walleij@stericsson.com> 762306a36Sopenharmony_ci * Author: Rickard Andersson <rickard.andersson@stericsson.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/stddef.h> 1362306a36Sopenharmony_ci#include <linux/ioport.h> 1462306a36Sopenharmony_ci#include <linux/genalloc.h> 1562306a36Sopenharmony_ci#include <linux/string.h> /* memcpy */ 1662306a36Sopenharmony_ci#include <asm/cputype.h> 1762306a36Sopenharmony_ci#include <asm/mach/map.h> 1862306a36Sopenharmony_ci#include <asm/page.h> 1962306a36Sopenharmony_ci#include <asm/system_info.h> 2062306a36Sopenharmony_ci#include <asm/traps.h> 2162306a36Sopenharmony_ci#include <asm/tcm.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define TCMTR_FORMAT_MASK 0xe0000000U 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct gen_pool *tcm_pool; 2662306a36Sopenharmony_cistatic bool dtcm_present; 2762306a36Sopenharmony_cistatic bool itcm_present; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* TCM section definitions from the linker */ 3062306a36Sopenharmony_ciextern char __itcm_start, __sitcm_text, __eitcm_text; 3162306a36Sopenharmony_ciextern char __dtcm_start, __sdtcm_data, __edtcm_data; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* These will be increased as we run */ 3462306a36Sopenharmony_cistatic u32 dtcm_end = DTCM_OFFSET; 3562306a36Sopenharmony_cistatic u32 itcm_end = ITCM_OFFSET; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * TCM memory resources 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_cistatic struct resource dtcm_res = { 4162306a36Sopenharmony_ci .name = "DTCM RAM", 4262306a36Sopenharmony_ci .start = DTCM_OFFSET, 4362306a36Sopenharmony_ci .end = DTCM_OFFSET, 4462306a36Sopenharmony_ci .flags = IORESOURCE_MEM 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct resource itcm_res = { 4862306a36Sopenharmony_ci .name = "ITCM RAM", 4962306a36Sopenharmony_ci .start = ITCM_OFFSET, 5062306a36Sopenharmony_ci .end = ITCM_OFFSET, 5162306a36Sopenharmony_ci .flags = IORESOURCE_MEM 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct map_desc dtcm_iomap[] __initdata = { 5562306a36Sopenharmony_ci { 5662306a36Sopenharmony_ci .virtual = DTCM_OFFSET, 5762306a36Sopenharmony_ci .pfn = __phys_to_pfn(DTCM_OFFSET), 5862306a36Sopenharmony_ci .length = 0, 5962306a36Sopenharmony_ci .type = MT_MEMORY_RW_DTCM 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct map_desc itcm_iomap[] __initdata = { 6462306a36Sopenharmony_ci { 6562306a36Sopenharmony_ci .virtual = ITCM_OFFSET, 6662306a36Sopenharmony_ci .pfn = __phys_to_pfn(ITCM_OFFSET), 6762306a36Sopenharmony_ci .length = 0, 6862306a36Sopenharmony_ci .type = MT_MEMORY_RWX_ITCM, 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Allocate a chunk of TCM memory 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_civoid *tcm_alloc(size_t len) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci unsigned long vaddr; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!tcm_pool) 8062306a36Sopenharmony_ci return NULL; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci vaddr = gen_pool_alloc(tcm_pool, len); 8362306a36Sopenharmony_ci if (!vaddr) 8462306a36Sopenharmony_ci return NULL; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return (void *) vaddr; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ciEXPORT_SYMBOL(tcm_alloc); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Free a chunk of TCM memory 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_civoid tcm_free(void *addr, size_t len) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci gen_pool_free(tcm_pool, (unsigned long) addr, len); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL(tcm_free); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cibool tcm_dtcm_present(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return dtcm_present; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ciEXPORT_SYMBOL(tcm_dtcm_present); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cibool tcm_itcm_present(void) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci return itcm_present; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ciEXPORT_SYMBOL(tcm_itcm_present); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, 11262306a36Sopenharmony_ci u32 *offset) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128, 11562306a36Sopenharmony_ci 256, 512, 1024, -1, -1, -1, -1 }; 11662306a36Sopenharmony_ci u32 tcm_region; 11762306a36Sopenharmony_ci int tcm_size; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * If there are more than one TCM bank of this type, 12162306a36Sopenharmony_ci * select the TCM bank to operate on in the TCM selection 12262306a36Sopenharmony_ci * register. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci if (banks > 1) 12562306a36Sopenharmony_ci asm("mcr p15, 0, %0, c9, c2, 0" 12662306a36Sopenharmony_ci : /* No output operands */ 12762306a36Sopenharmony_ci : "r" (bank)); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Read the special TCM region register c9, 0 */ 13062306a36Sopenharmony_ci if (!type) 13162306a36Sopenharmony_ci asm("mrc p15, 0, %0, c9, c1, 0" 13262306a36Sopenharmony_ci : "=r" (tcm_region)); 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci asm("mrc p15, 0, %0, c9, c1, 1" 13562306a36Sopenharmony_ci : "=r" (tcm_region)); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f]; 13862306a36Sopenharmony_ci if (tcm_size < 0) { 13962306a36Sopenharmony_ci pr_err("CPU: %sTCM%d of unknown size\n", 14062306a36Sopenharmony_ci type ? "I" : "D", bank); 14162306a36Sopenharmony_ci return -EINVAL; 14262306a36Sopenharmony_ci } else if (tcm_size > 32) { 14362306a36Sopenharmony_ci pr_err("CPU: %sTCM%d larger than 32k found\n", 14462306a36Sopenharmony_ci type ? "I" : "D", bank); 14562306a36Sopenharmony_ci return -EINVAL; 14662306a36Sopenharmony_ci } else { 14762306a36Sopenharmony_ci pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n", 14862306a36Sopenharmony_ci type ? "I" : "D", 14962306a36Sopenharmony_ci bank, 15062306a36Sopenharmony_ci tcm_size, 15162306a36Sopenharmony_ci (tcm_region & 0xfffff000U), 15262306a36Sopenharmony_ci (tcm_region & 1) ? "" : "not "); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Not much fun you can do with a size 0 bank */ 15662306a36Sopenharmony_ci if (tcm_size == 0) 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Force move the TCM bank to where we want it, enable */ 16062306a36Sopenharmony_ci tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!type) 16362306a36Sopenharmony_ci asm("mcr p15, 0, %0, c9, c1, 0" 16462306a36Sopenharmony_ci : /* No output operands */ 16562306a36Sopenharmony_ci : "r" (tcm_region)); 16662306a36Sopenharmony_ci else 16762306a36Sopenharmony_ci asm("mcr p15, 0, %0, c9, c1, 1" 16862306a36Sopenharmony_ci : /* No output operands */ 16962306a36Sopenharmony_ci : "r" (tcm_region)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Increase offset */ 17262306a36Sopenharmony_ci *offset += (tcm_size << 10); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n", 17562306a36Sopenharmony_ci type ? "I" : "D", 17662306a36Sopenharmony_ci bank, 17762306a36Sopenharmony_ci tcm_size, 17862306a36Sopenharmony_ci (tcm_region & 0xfffff000U)); 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * When we are running in the non-secure world and the secure world 18462306a36Sopenharmony_ci * has not explicitly given us access to the TCM we will get an 18562306a36Sopenharmony_ci * undefined error when reading the TCM region register in the 18662306a36Sopenharmony_ci * setup_tcm_bank function (above). 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * There are two variants of this register read that we need to trap, 18962306a36Sopenharmony_ci * the read for the data TCM and the read for the instruction TCM: 19062306a36Sopenharmony_ci * c0370628: ee196f11 mrc 15, 0, r6, cr9, cr1, {0} 19162306a36Sopenharmony_ci * c0370674: ee196f31 mrc 15, 0, r6, cr9, cr1, {1} 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Our undef hook mask explicitly matches all fields of the encoded 19462306a36Sopenharmony_ci * instruction other than the destination register. The mask also 19562306a36Sopenharmony_ci * only allows operand 2 to have the values 0 or 1. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * The undefined hook is defined as __init and __initdata, and therefore 19862306a36Sopenharmony_ci * must be removed before tcm_init returns. 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * In this particular case (MRC with ARM condition code ALways) the 20162306a36Sopenharmony_ci * Thumb-2 and ARM instruction encoding are identical, so this hook 20262306a36Sopenharmony_ci * will work on a Thumb-2 kernel. 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * See A8.8.107, DDI0406C_C ARM Architecture Reference Manual, Encoding 20562306a36Sopenharmony_ci * T1/A1 for the bit-by-bit details. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * mrc p15, 0, XX, c9, c1, 0 20862306a36Sopenharmony_ci * mrc p15, 0, XX, c9, c1, 1 20962306a36Sopenharmony_ci * | | | | | | | +---- opc2 0|1 = 000|001 21062306a36Sopenharmony_ci * | | | | | | +------- CRm 0 = 0001 21162306a36Sopenharmony_ci * | | | | | +----------- CRn 0 = 1001 21262306a36Sopenharmony_ci * | | | | +--------------- Rt ? = ???? 21362306a36Sopenharmony_ci * | | | +------------------- opc1 0 = 000 21462306a36Sopenharmony_ci * | | +----------------------- coproc 15 = 1111 21562306a36Sopenharmony_ci * | +-------------------------- condition ALways = 1110 21662306a36Sopenharmony_ci * +----------------------------- instruction MRC = 1110 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * Encoding this as per A8.8.107 of DDI0406C, Encoding T1/A1, yields: 21962306a36Sopenharmony_ci * 1111 1111 1111 1111 0000 1111 1101 1111 Required Mask 22062306a36Sopenharmony_ci * 1110 1110 0001 1001 ???? 1111 0001 0001 mrc p15, 0, XX, c9, c1, 0 22162306a36Sopenharmony_ci * 1110 1110 0001 1001 ???? 1111 0011 0001 mrc p15, 0, XX, c9, c1, 1 22262306a36Sopenharmony_ci * [ ] [ ] [ ]| [ ] [ ] [ ] [ ]| +--- CRm 22362306a36Sopenharmony_ci * | | | | | | | | +----- SBO 22462306a36Sopenharmony_ci * | | | | | | | +------- opc2 22562306a36Sopenharmony_ci * | | | | | | +----------- coproc 22662306a36Sopenharmony_ci * | | | | | +---------------- Rt 22762306a36Sopenharmony_ci * | | | | +--------------------- CRn 22862306a36Sopenharmony_ci * | | | +------------------------- SBO 22962306a36Sopenharmony_ci * | | +--------------------------- opc1 23062306a36Sopenharmony_ci * | +------------------------------- instruction 23162306a36Sopenharmony_ci * +------------------------------------ condition 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci#define TCM_REGION_READ_MASK 0xffff0fdf 23462306a36Sopenharmony_ci#define TCM_REGION_READ_INSTR 0xee190f11 23562306a36Sopenharmony_ci#define DEST_REG_SHIFT 12 23662306a36Sopenharmony_ci#define DEST_REG_MASK 0xf 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int __init tcm_handler(struct pt_regs *regs, unsigned int instr) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0; 24162306a36Sopenharmony_ci regs->ARM_pc += 4; 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic struct undef_hook tcm_hook __initdata = { 24662306a36Sopenharmony_ci .instr_mask = TCM_REGION_READ_MASK, 24762306a36Sopenharmony_ci .instr_val = TCM_REGION_READ_INSTR, 24862306a36Sopenharmony_ci .cpsr_mask = MODE_MASK, 24962306a36Sopenharmony_ci .cpsr_val = SVC_MODE, 25062306a36Sopenharmony_ci .fn = tcm_handler 25162306a36Sopenharmony_ci}; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* 25462306a36Sopenharmony_ci * This initializes the TCM memory 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_civoid __init tcm_init(void) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci u32 tcm_status; 25962306a36Sopenharmony_ci u8 dtcm_banks; 26062306a36Sopenharmony_ci u8 itcm_banks; 26162306a36Sopenharmony_ci size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data; 26262306a36Sopenharmony_ci size_t itcm_code_sz = &__eitcm_text - &__sitcm_text; 26362306a36Sopenharmony_ci char *start; 26462306a36Sopenharmony_ci char *end; 26562306a36Sopenharmony_ci char *ram; 26662306a36Sopenharmony_ci int ret; 26762306a36Sopenharmony_ci int i; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * Prior to ARMv5 there is no TCM, and trying to read the status 27162306a36Sopenharmony_ci * register will hang the processor. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci if (cpu_architecture() < CPU_ARCH_ARMv5) { 27462306a36Sopenharmony_ci if (dtcm_code_sz || itcm_code_sz) 27562306a36Sopenharmony_ci pr_info("CPU TCM: %u bytes of DTCM and %u bytes of " 27662306a36Sopenharmony_ci "ITCM code compiled in, but no TCM present " 27762306a36Sopenharmony_ci "in pre-v5 CPU\n", dtcm_code_sz, itcm_code_sz); 27862306a36Sopenharmony_ci return; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci tcm_status = read_cpuid_tcmstatus(); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* 28462306a36Sopenharmony_ci * This code only supports v6-compatible TCMTR implementations. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci if (tcm_status & TCMTR_FORMAT_MASK) 28762306a36Sopenharmony_ci return; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci dtcm_banks = (tcm_status >> 16) & 0x03; 29062306a36Sopenharmony_ci itcm_banks = (tcm_status & 0x03); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci register_undef_hook(&tcm_hook); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Values greater than 2 for D/ITCM banks are "reserved" */ 29562306a36Sopenharmony_ci if (dtcm_banks > 2) 29662306a36Sopenharmony_ci dtcm_banks = 0; 29762306a36Sopenharmony_ci if (itcm_banks > 2) 29862306a36Sopenharmony_ci itcm_banks = 0; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Setup DTCM if present */ 30162306a36Sopenharmony_ci if (dtcm_banks > 0) { 30262306a36Sopenharmony_ci for (i = 0; i < dtcm_banks; i++) { 30362306a36Sopenharmony_ci ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci goto unregister; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci /* This means you compiled more code than fits into DTCM */ 30862306a36Sopenharmony_ci if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { 30962306a36Sopenharmony_ci pr_info("CPU DTCM: %u bytes of code compiled to " 31062306a36Sopenharmony_ci "DTCM but only %lu bytes of DTCM present\n", 31162306a36Sopenharmony_ci dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); 31262306a36Sopenharmony_ci goto no_dtcm; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci /* 31562306a36Sopenharmony_ci * This means that the DTCM sizes were 0 or the DTCM banks 31662306a36Sopenharmony_ci * were inaccessible due to TrustZone configuration. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (!(dtcm_end - DTCM_OFFSET)) 31962306a36Sopenharmony_ci goto no_dtcm; 32062306a36Sopenharmony_ci dtcm_res.end = dtcm_end - 1; 32162306a36Sopenharmony_ci request_resource(&iomem_resource, &dtcm_res); 32262306a36Sopenharmony_ci dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; 32362306a36Sopenharmony_ci iotable_init(dtcm_iomap, 1); 32462306a36Sopenharmony_ci /* Copy data from RAM to DTCM */ 32562306a36Sopenharmony_ci start = &__sdtcm_data; 32662306a36Sopenharmony_ci end = &__edtcm_data; 32762306a36Sopenharmony_ci ram = &__dtcm_start; 32862306a36Sopenharmony_ci memcpy(start, ram, dtcm_code_sz); 32962306a36Sopenharmony_ci pr_debug("CPU DTCM: copied data from %p - %p\n", 33062306a36Sopenharmony_ci start, end); 33162306a36Sopenharmony_ci dtcm_present = true; 33262306a36Sopenharmony_ci } else if (dtcm_code_sz) { 33362306a36Sopenharmony_ci pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " 33462306a36Sopenharmony_ci "DTCM banks present in CPU\n", dtcm_code_sz); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cino_dtcm: 33862306a36Sopenharmony_ci /* Setup ITCM if present */ 33962306a36Sopenharmony_ci if (itcm_banks > 0) { 34062306a36Sopenharmony_ci for (i = 0; i < itcm_banks; i++) { 34162306a36Sopenharmony_ci ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci goto unregister; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci /* This means you compiled more code than fits into ITCM */ 34662306a36Sopenharmony_ci if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { 34762306a36Sopenharmony_ci pr_info("CPU ITCM: %u bytes of code compiled to " 34862306a36Sopenharmony_ci "ITCM but only %lu bytes of ITCM present\n", 34962306a36Sopenharmony_ci itcm_code_sz, (itcm_end - ITCM_OFFSET)); 35062306a36Sopenharmony_ci goto unregister; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * This means that the ITCM sizes were 0 or the ITCM banks 35462306a36Sopenharmony_ci * were inaccessible due to TrustZone configuration. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci if (!(itcm_end - ITCM_OFFSET)) 35762306a36Sopenharmony_ci goto unregister; 35862306a36Sopenharmony_ci itcm_res.end = itcm_end - 1; 35962306a36Sopenharmony_ci request_resource(&iomem_resource, &itcm_res); 36062306a36Sopenharmony_ci itcm_iomap[0].length = itcm_end - ITCM_OFFSET; 36162306a36Sopenharmony_ci iotable_init(itcm_iomap, 1); 36262306a36Sopenharmony_ci /* Copy code from RAM to ITCM */ 36362306a36Sopenharmony_ci start = &__sitcm_text; 36462306a36Sopenharmony_ci end = &__eitcm_text; 36562306a36Sopenharmony_ci ram = &__itcm_start; 36662306a36Sopenharmony_ci memcpy(start, ram, itcm_code_sz); 36762306a36Sopenharmony_ci pr_debug("CPU ITCM: copied code from %p - %p\n", 36862306a36Sopenharmony_ci start, end); 36962306a36Sopenharmony_ci itcm_present = true; 37062306a36Sopenharmony_ci } else if (itcm_code_sz) { 37162306a36Sopenharmony_ci pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " 37262306a36Sopenharmony_ci "ITCM banks present in CPU\n", itcm_code_sz); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciunregister: 37662306a36Sopenharmony_ci unregister_undef_hook(&tcm_hook); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * This creates the TCM memory pool and has to be done later, 38162306a36Sopenharmony_ci * during the core_initicalls, since the allocator is not yet 38262306a36Sopenharmony_ci * up and running when the first initialization runs. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic int __init setup_tcm_pool(void) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci u32 dtcm_pool_start = (u32) &__edtcm_data; 38762306a36Sopenharmony_ci u32 itcm_pool_start = (u32) &__eitcm_text; 38862306a36Sopenharmony_ci int ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * Set up malloc pool, 2^2 = 4 bytes granularity since 39262306a36Sopenharmony_ci * the TCM is sometimes just 4 KiB. NB: pages and cache 39362306a36Sopenharmony_ci * line alignments does not matter in TCM! 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci tcm_pool = gen_pool_create(2, -1); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci pr_debug("Setting up TCM memory pool\n"); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Add the rest of DTCM to the TCM pool */ 40062306a36Sopenharmony_ci if (dtcm_present) { 40162306a36Sopenharmony_ci if (dtcm_pool_start < dtcm_end) { 40262306a36Sopenharmony_ci ret = gen_pool_add(tcm_pool, dtcm_pool_start, 40362306a36Sopenharmony_ci dtcm_end - dtcm_pool_start, -1); 40462306a36Sopenharmony_ci if (ret) { 40562306a36Sopenharmony_ci pr_err("CPU DTCM: could not add DTCM " \ 40662306a36Sopenharmony_ci "remainder to pool!\n"); 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \ 41062306a36Sopenharmony_ci "the TCM memory pool\n", 41162306a36Sopenharmony_ci dtcm_end - dtcm_pool_start, 41262306a36Sopenharmony_ci dtcm_pool_start); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* Add the rest of ITCM to the TCM pool */ 41762306a36Sopenharmony_ci if (itcm_present) { 41862306a36Sopenharmony_ci if (itcm_pool_start < itcm_end) { 41962306a36Sopenharmony_ci ret = gen_pool_add(tcm_pool, itcm_pool_start, 42062306a36Sopenharmony_ci itcm_end - itcm_pool_start, -1); 42162306a36Sopenharmony_ci if (ret) { 42262306a36Sopenharmony_ci pr_err("CPU ITCM: could not add ITCM " \ 42362306a36Sopenharmony_ci "remainder to pool!\n"); 42462306a36Sopenharmony_ci return ret; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \ 42762306a36Sopenharmony_ci "the TCM memory pool\n", 42862306a36Sopenharmony_ci itcm_end - itcm_pool_start, 42962306a36Sopenharmony_ci itcm_pool_start); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cicore_initcall(setup_tcm_pool); 436