|
@@ -17,6 +17,9 @@
|
|
#include <asm/mach/map.h>
|
|
#include <asm/mach/map.h>
|
|
#include <asm/memory.h>
|
|
#include <asm/memory.h>
|
|
#include <asm/system_info.h>
|
|
#include <asm/system_info.h>
|
|
|
|
+#include <asm/traps.h>
|
|
|
|
+
|
|
|
|
+#define TCMTR_FORMAT_MASK 0xe0000000U
|
|
|
|
|
|
static struct gen_pool *tcm_pool;
|
|
static struct gen_pool *tcm_pool;
|
|
static bool dtcm_present;
|
|
static bool dtcm_present;
|
|
@@ -175,6 +178,77 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * When we are running in the non-secure world and the secure world
|
|
|
|
+ * has not explicitly given us access to the TCM we will get an
|
|
|
|
+ * undefined error when reading the TCM region register in the
|
|
|
|
+ * setup_tcm_bank function (above).
|
|
|
|
+ *
|
|
|
|
+ * There are two variants of this register read that we need to trap,
|
|
|
|
+ * the read for the data TCM and the read for the instruction TCM:
|
|
|
|
+ * c0370628: ee196f11 mrc 15, 0, r6, cr9, cr1, {0}
|
|
|
|
+ * c0370674: ee196f31 mrc 15, 0, r6, cr9, cr1, {1}
|
|
|
|
+ *
|
|
|
|
+ * Our undef hook mask explicitly matches all fields of the encoded
|
|
|
|
+ * instruction other than the destination register. The mask also
|
|
|
|
+ * only allows operand 2 to have the values 0 or 1.
|
|
|
|
+ *
|
|
|
|
+ * The undefined hook is defined as __init and __initdata, and therefore
|
|
|
|
+ * must be removed before tcm_init returns.
|
|
|
|
+ *
|
|
|
|
+ * In this particular case (MRC with ARM condition code ALways) the
|
|
|
|
+ * Thumb-2 and ARM instruction encoding are identical, so this hook
|
|
|
|
+ * will work on a Thumb-2 kernel.
|
|
|
|
+ *
|
|
|
|
+ * See A8.8.107, DDI0406C_C ARM Architecture Reference Manual, Encoding
|
|
|
|
+ * T1/A1 for the bit-by-bit details.
|
|
|
|
+ *
|
|
|
|
+ * mrc p15, 0, XX, c9, c1, 0
|
|
|
|
+ * mrc p15, 0, XX, c9, c1, 1
|
|
|
|
+ * | | | | | | | +---- opc2 0|1 = 000|001
|
|
|
|
+ * | | | | | | +------- CRm 0 = 0001
|
|
|
|
+ * | | | | | +----------- CRn 0 = 1001
|
|
|
|
+ * | | | | +--------------- Rt ? = ????
|
|
|
|
+ * | | | +------------------- opc1 0 = 000
|
|
|
|
+ * | | +----------------------- coproc 15 = 1111
|
|
|
|
+ * | +-------------------------- condition ALways = 1110
|
|
|
|
+ * +----------------------------- instruction MRC = 1110
|
|
|
|
+ *
|
|
|
|
+ * Encoding this as per A8.8.107 of DDI0406C, Encoding T1/A1, yields:
|
|
|
|
+ * 1111 1111 1111 1111 0000 1111 1101 1111 Required Mask
|
|
|
|
+ * 1110 1110 0001 1001 ???? 1111 0001 0001 mrc p15, 0, XX, c9, c1, 0
|
|
|
|
+ * 1110 1110 0001 1001 ???? 1111 0011 0001 mrc p15, 0, XX, c9, c1, 1
|
|
|
|
+ * [ ] [ ] [ ]| [ ] [ ] [ ] [ ]| +--- CRm
|
|
|
|
+ * | | | | | | | | +----- SBO
|
|
|
|
+ * | | | | | | | +------- opc2
|
|
|
|
+ * | | | | | | +----------- coproc
|
|
|
|
+ * | | | | | +---------------- Rt
|
|
|
|
+ * | | | | +--------------------- CRn
|
|
|
|
+ * | | | +------------------------- SBO
|
|
|
|
+ * | | +--------------------------- opc1
|
|
|
|
+ * | +------------------------------- instruction
|
|
|
|
+ * +------------------------------------ condition
|
|
|
|
+ */
|
|
|
|
+#define TCM_REGION_READ_MASK 0xffff0fdf
|
|
|
|
+#define TCM_REGION_READ_INSTR 0xee190f11
|
|
|
|
+#define DEST_REG_SHIFT 12
|
|
|
|
+#define DEST_REG_MASK 0xf
|
|
|
|
+
|
|
|
|
+static int __init tcm_handler(struct pt_regs *regs, unsigned int instr)
|
|
|
|
+{
|
|
|
|
+ regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0;
|
|
|
|
+ regs->ARM_pc += 4;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct undef_hook tcm_hook __initdata = {
|
|
|
|
+ .instr_mask = TCM_REGION_READ_MASK,
|
|
|
|
+ .instr_val = TCM_REGION_READ_INSTR,
|
|
|
|
+ .cpsr_mask = MODE_MASK,
|
|
|
|
+ .cpsr_val = SVC_MODE,
|
|
|
|
+ .fn = tcm_handler
|
|
|
|
+};
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This initializes the TCM memory
|
|
* This initializes the TCM memory
|
|
*/
|
|
*/
|
|
@@ -204,9 +278,18 @@ void __init tcm_init(void)
|
|
}
|
|
}
|
|
|
|
|
|
tcm_status = read_cpuid_tcmstatus();
|
|
tcm_status = read_cpuid_tcmstatus();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * This code only supports v6-compatible TCMTR implementations.
|
|
|
|
+ */
|
|
|
|
+ if (tcm_status & TCMTR_FORMAT_MASK)
|
|
|
|
+ return;
|
|
|
|
+
|
|
dtcm_banks = (tcm_status >> 16) & 0x03;
|
|
dtcm_banks = (tcm_status >> 16) & 0x03;
|
|
itcm_banks = (tcm_status & 0x03);
|
|
itcm_banks = (tcm_status & 0x03);
|
|
|
|
|
|
|
|
+ register_undef_hook(&tcm_hook);
|
|
|
|
+
|
|
/* Values greater than 2 for D/ITCM banks are "reserved" */
|
|
/* Values greater than 2 for D/ITCM banks are "reserved" */
|
|
if (dtcm_banks > 2)
|
|
if (dtcm_banks > 2)
|
|
dtcm_banks = 0;
|
|
dtcm_banks = 0;
|
|
@@ -218,7 +301,7 @@ void __init tcm_init(void)
|
|
for (i = 0; i < dtcm_banks; i++) {
|
|
for (i = 0; i < dtcm_banks; i++) {
|
|
ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
|
|
ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
|
|
if (ret)
|
|
if (ret)
|
|
- return;
|
|
|
|
|
|
+ goto unregister;
|
|
}
|
|
}
|
|
/* This means you compiled more code than fits into DTCM */
|
|
/* This means you compiled more code than fits into DTCM */
|
|
if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) {
|
|
if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) {
|
|
@@ -227,6 +310,12 @@ void __init tcm_init(void)
|
|
dtcm_code_sz, (dtcm_end - DTCM_OFFSET));
|
|
dtcm_code_sz, (dtcm_end - DTCM_OFFSET));
|
|
goto no_dtcm;
|
|
goto no_dtcm;
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
|
|
+ * This means that the DTCM sizes were 0 or the DTCM banks
|
|
|
|
+ * were inaccessible due to TrustZone configuration.
|
|
|
|
+ */
|
|
|
|
+ if (!(dtcm_end - DTCM_OFFSET))
|
|
|
|
+ goto no_dtcm;
|
|
dtcm_res.end = dtcm_end - 1;
|
|
dtcm_res.end = dtcm_end - 1;
|
|
request_resource(&iomem_resource, &dtcm_res);
|
|
request_resource(&iomem_resource, &dtcm_res);
|
|
dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
|
|
dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
|
|
@@ -250,15 +339,21 @@ no_dtcm:
|
|
for (i = 0; i < itcm_banks; i++) {
|
|
for (i = 0; i < itcm_banks; i++) {
|
|
ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
|
|
ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
|
|
if (ret)
|
|
if (ret)
|
|
- return;
|
|
|
|
|
|
+ goto unregister;
|
|
}
|
|
}
|
|
/* This means you compiled more code than fits into ITCM */
|
|
/* This means you compiled more code than fits into ITCM */
|
|
if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) {
|
|
if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) {
|
|
pr_info("CPU ITCM: %u bytes of code compiled to "
|
|
pr_info("CPU ITCM: %u bytes of code compiled to "
|
|
"ITCM but only %lu bytes of ITCM present\n",
|
|
"ITCM but only %lu bytes of ITCM present\n",
|
|
itcm_code_sz, (itcm_end - ITCM_OFFSET));
|
|
itcm_code_sz, (itcm_end - ITCM_OFFSET));
|
|
- return;
|
|
|
|
|
|
+ goto unregister;
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
|
|
+ * This means that the ITCM sizes were 0 or the ITCM banks
|
|
|
|
+ * were inaccessible due to TrustZone configuration.
|
|
|
|
+ */
|
|
|
|
+ if (!(itcm_end - ITCM_OFFSET))
|
|
|
|
+ goto unregister;
|
|
itcm_res.end = itcm_end - 1;
|
|
itcm_res.end = itcm_end - 1;
|
|
request_resource(&iomem_resource, &itcm_res);
|
|
request_resource(&iomem_resource, &itcm_res);
|
|
itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
|
|
itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
|
|
@@ -275,6 +370,9 @@ no_dtcm:
|
|
pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no "
|
|
pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no "
|
|
"ITCM banks present in CPU\n", itcm_code_sz);
|
|
"ITCM banks present in CPU\n", itcm_code_sz);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+unregister:
|
|
|
|
+ unregister_undef_hook(&tcm_hook);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|