[U-Boot] [PATCH] keystone2: add high memory test
Vitaly Andrianov
vitalya at ti.com
Wed Jul 8 17:51:39 CEST 2015
Keystone2 SOC physical DDR3 address range is outside the first 4GB and
cannot be entirely accessible without MMU enabled. Only first 2GB of
the physical memory have 32-bits aliased addresses. This patch adds u-boot
shell command that allows to enable/disable MMU and map the 1GB of
36bits physical memory to the first 4GB address range.
Signed-off-by: Vitaly Andrianov <vitalya at ti.com>
---
arch/arm/mach-keystone/Makefile | 3 +-
arch/arm/mach-keystone/highmem.c | 162 +++++++++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-keystone/highmem.c
diff --git a/arch/arm/mach-keystone/Makefile b/arch/arm/mach-keystone/Makefile
index ed030db..56b6457 100644
--- a/arch/arm/mach-keystone/Makefile
+++ b/arch/arm/mach-keystone/Makefile
@@ -1,5 +1,5 @@
#
-# (C) Copyright 2012-2014
+# (C) Copyright 2012-2015
# Texas Instruments Incorporated, <www.ti.com>
#
# SPDX-License-Identifier: GPL-2.0+
@@ -16,3 +16,4 @@ obj-y += cmd_mon.o
obj-y += msmc.o
obj-y += ddr3.o cmd_ddr3.o
obj-y += keystone.o
+obj-y += highmem.o
diff --git a/arch/arm/mach-keystone/highmem.c b/arch/arm/mach-keystone/highmem.c
new file mode 100644
index 0000000..d024e04
--- /dev/null
+++ b/arch/arm/mach-keystone/highmem.c
@@ -0,0 +1,162 @@
+/*
+ * Keystone2: High Memory Test
+ *
+ * (C) Copyright 2013-2015
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+/*
+ * Keysone2 systems which have more then 2GB of DDR2A memory
+ * cannot access that memory without MMU enable. In order to test
+ * the entire memory we need to create MMU translation table,
+ * enable MMU and test the memory in portions. After the test
+ * we need to disable MMU.
+ *
+ * We assume that the memory size >= 2GB and u-boot code is relocated
+ * to the upper GB of the PA address range and the 0x80000000-0xbfffffff
+ * address range is available to use for testing.
+ *
+ * The code will create simple 1 level page table with 4 entries of
+ * 1GB blocks. The block with VA 0x80000000-0xbfffffff will be used
+ * to map different portions of the DDR3a.
+ *
+ */
+
+#include <common.h>
+#include <asm/armv7.h>
+
+static unsigned long long pgd_table[4] __aligned(0x1000);
+static unsigned long sctlr_save;
+static int mmu_enabled;
+
+/* Invalidate TLB */
+void my_v7_inval_tlb(void)
+{
+ /* Invalidate entire unified TLB */
+ asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
+ /* Invalidate entire data TLB */
+ asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0));
+ /* Invalidate entire instruction TLB */
+ asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
+ /* Full system DSB - make sure that the invalidation is complete */
+ CP15DSB;
+ /* Full system ISB - make sure the instruction stream sees it */
+ CP15ISB;
+}
+
+static unsigned long enable_mmu(unsigned long long *ttbr0)
+{
+ unsigned long ret;
+ asm (
+ "stmfd r13!, {r10, r11}\n"
+ /* set ttbr0 */
+ "mov r10, %1\n"
+ "mov r11, #0\n"
+ "mcrr p15, 0, r10, r11, c2\n"
+ /* ttbcr = 0x80000000 */
+ "mov r10, #0\n"
+ "orr r10, r10, #(1 << 31)\n"
+ "mcr p15, 0, r10, c2, c0, 2\n"
+ /* save current SCTLR value */
+ "mrc p15, #0, r10, c1, c0, #0\n"
+ "mov %0, r10\n"
+ /* disable cache */
+ "bic r10, r10,#(1 << 12)\n"
+ "bic r10, r10,#(1 << 2)\n"
+ "mcr p15, #0, r10, c1, c0, #0\n"
+ "isb\n"
+ "dsb\n"
+ "bl invalidate_dcache_all\n"
+ "bl my_v7_inval_tlb\n"
+ /* enable mmu */
+ "mrc p15, #0, r10, c1, c0, #0\n"
+ "orr r10, r10,#1\n"
+ "mcr p15, #0, r10, c1, c0, #0\n"
+ "ldmfd r13!, {r10, r11}\n"
+ : "=r" (ret) : "r" (ttbr0) : "r10", "r11", "cc"
+ );
+
+ return ret;
+}
+
+static void disable_mmu(unsigned long sctlr_old)
+{
+ asm volatile (
+ "mov r10, %0\n"
+ "bic r10, r10,#1\n"
+ "mcr p15, #0, r10, c1, c0, #0\n"
+ : : "r" (sctlr_old) : "r10", "cc"
+ );
+}
+
+
+static void pgd_table_init(void)
+{
+ /*
+ * we create identical mapping for the whole 4GB address range
+ * this table maps 0x0-0xffffffff VA to aliased PA range
+ * 0x0_0000_0000 - 0x0_ffff_ffff;
+ */
+
+ pgd_table[0] = 0x000000000000071dULL;
+ pgd_table[1] = 0x000000004000071dULL;
+ pgd_table[2] = 0x000000008000071dULL;
+ pgd_table[3] = 0x00000000c000071dULL;
+}
+
+int do_highmem_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long pgd2_pa;
+ unsigned long long pgd_val;
+ int j;
+
+ if (argc < 2)
+ goto highmem_cmd_usage;
+
+ if (strcmp(argv[1], "mmuon") == 0) {
+ if (mmu_enabled) {
+ printf("MMU already enabled\n");
+ } else {
+ pgd_table_init();
+ sctlr_save = enable_mmu(pgd_table);
+ mmu_enabled = 1;
+ printf("MMU enabled\n");
+ }
+ } else if (strcmp(argv[1], "mmuoff") == 0) {
+ if (mmu_enabled == 0) {
+ printf("MMU already disabled\n");
+ } else {
+ disable_mmu(sctlr_save);
+ mmu_enabled = 0;
+ printf("MMU disabled\n");
+ }
+ } else if (strcmp(argv[1], "pgd2") == 0) {
+ if (argc == 3) {
+ pgd2_pa = simple_strtoul(argv[2], NULL, 16);
+ pgd_val = pgd2_pa;
+ pgd_val <<= 4;
+ pgd_val |= 0x71dull;
+ pgd_table[2] = pgd_val;
+ my_v7_inval_tlb();
+ }
+ for (j = 0; j < 4; j++)
+ printf("pgd%d - 0x%016llX\n", j, pgd_table[j]);
+ } else {
+ goto highmem_cmd_usage;
+ }
+
+ return 0;
+
+highmem_cmd_usage:
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ highmem, 3, 0, do_highmem_cmd,
+ "highmem test",
+ "highmem <mmuon|mmuoff|pgd2> [<pgd2_pa >> 4> in hex]\n"
+);
+
--
1.9.1
More information about the U-Boot
mailing list