armv8: fsl-layerscape: Make DDR non secure in MMU tables
authorYork Sun <yorksun@freescale.com>
Fri, 4 Dec 2015 19:57:08 +0000 (11:57 -0800)
committerYork Sun <yorksun@freescale.com>
Tue, 15 Dec 2015 00:57:33 +0000 (08:57 +0800)
DDR has been set as secure in MMU tables. Non-secure master such
as SDHC DMA cannot access data correctly. Mixing secure and non-
secure MMU entries requirs the MMU tables themselves in secure
memory. This patch moves MMU tables into a secure DDR area.

Early MMU tables are changed to set DDR as non-secure. A new
table is added into final MMU tables so secure memory can have
2MB granuality.

gd->secure_ram tracks the location of this secure memory. For
ARMv8 SoCs, the RAM base is not zero and RAM is divided into several
banks. gd->secure_ram needs to be maintained before using. This
maintenance is board-specific, depending on the SoC and memory
bank of the secure memory falls into.

Signed-off-by: York Sun <yorksun@freescale.com>
arch/arm/cpu/armv8/fsl-layerscape/cpu.c
arch/arm/include/asm/arch-fsl-layerscape/config.h
arch/arm/include/asm/arch-fsl-layerscape/cpu.h
board/freescale/ls1043aqds/ddr.c
board/freescale/ls1043ardb/ddr.c
board/freescale/ls2080a/ddr.c
board/freescale/ls2080aqds/ddr.c
board/freescale/ls2080ardb/ddr.c

index 8847fc0287ac36bd2f0d90d8ba5b385a8b5fc016..87ccaf166f9a426b5acaf3bbdf39592bd3504d4c 100644 (file)
@@ -206,11 +206,65 @@ static inline void early_mmu_setup(void)
        set_sctlr(get_sctlr() | CR_M);
 }
 
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+/*
+ * Called from final mmu setup. The phys_addr is new, non-existing
+ * address. A new sub table is created @level2_table_secure to cover
+ * size of CONFIG_SYS_MEM_RESERVE_SECURE memory.
+ */
+static inline int final_secure_ddr(u64 *level0_table,
+                                  u64 *level2_table_secure,
+                                  phys_addr_t phys_addr)
+{
+       int ret = -EINVAL;
+       struct table_info table = {};
+       struct sys_mmu_table ddr_entry = {
+               0, 0, BLOCK_SIZE_L1, MT_NORMAL,
+               PMD_SECT_OUTER_SHARE | PMD_SECT_NS
+       };
+       u64 index;
+
+       /* Need to create a new table */
+       ddr_entry.virt_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1);
+       ddr_entry.phys_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1);
+       ret = find_table(&ddr_entry, &table, level0_table);
+       if (ret)
+               return ret;
+       index = (ddr_entry.virt_addr - table.table_base) >> SECTION_SHIFT_L1;
+       set_pgtable_table(table.ptr, index, level2_table_secure);
+       table.ptr = level2_table_secure;
+       table.table_base = ddr_entry.virt_addr;
+       table.entry_size = BLOCK_SIZE_L2;
+       ret = set_block_entry(&ddr_entry, &table);
+       if (ret) {
+               printf("MMU error: could not fill non-secure ddr block entries\n");
+               return ret;
+       }
+       ddr_entry.virt_addr = phys_addr;
+       ddr_entry.phys_addr = phys_addr;
+       ddr_entry.size = CONFIG_SYS_MEM_RESERVE_SECURE;
+       ddr_entry.attribute = PMD_SECT_OUTER_SHARE;
+       ret = find_table(&ddr_entry, &table, level0_table);
+       if (ret) {
+               printf("MMU error: could not find secure ddr table\n");
+               return ret;
+       }
+       ret = set_block_entry(&ddr_entry, &table);
+       if (ret)
+               printf("MMU error: could not set secure ddr block entry\n");
+
+       return ret;
+}
+#endif
+
 /*
  * The final tables look similar to early tables, but different in detail.
  * These tables are in DRAM. Sub tables are added to enable cache for
  * QBMan and OCRAM.
  *
+ * Put the MMU table in secure memory if gd->secure_ram is valid.
+ * OCRAM will be not used for this purpose so gd->secure_ram can't be 0.
+ *
  * Level 1 table 0 contains 512 entries for each 1GB from 0 to 512GB.
  * Level 1 table 1 contains 512 entries for each 1GB from 512GB to 1TB.
  * Level 2 table 0 contains 512 entries for each 2MB from 0 to 1GB.
@@ -223,18 +277,40 @@ static inline void early_mmu_setup(void)
  */
 static inline void final_mmu_setup(void)
 {
-       unsigned int el, i;
+       unsigned int el = current_el();
+       unsigned int i;
        u64 *level0_table = (u64 *)gd->arch.tlb_addr;
-       u64 *level1_table0 = (u64 *)(gd->arch.tlb_addr + 0x1000);
-       u64 *level1_table1 = (u64 *)(gd->arch.tlb_addr + 0x2000);
-       u64 *level2_table0 = (u64 *)(gd->arch.tlb_addr + 0x3000);
-#ifdef CONFIG_FSL_LSCH3
-       u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000);
-#elif defined(CONFIG_FSL_LSCH2)
-       u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000);
-       u64 *level2_table2 = (u64 *)(gd->arch.tlb_addr + 0x5000);
+       u64 *level1_table0;
+       u64 *level1_table1;
+       u64 *level2_table0;
+       u64 *level2_table1;
+#ifdef CONFIG_FSL_LSCH2
+       u64 *level2_table2;
 #endif
-       struct table_info table = {level0_table, 0, BLOCK_SIZE_L0};
+       struct table_info table = {NULL, 0, BLOCK_SIZE_L0};
+
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+       u64 *level2_table_secure;
+
+       if (el == 3) {
+               /*
+                * Only use gd->secure_ram if the address is recalculated
+                * Align to 4KB for MMU table
+                */
+               if (gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED)
+                       level0_table = (u64 *)(gd->secure_ram & ~0xfff);
+               else
+                       printf("MMU warning: gd->secure_ram is not maintained, disabled.\n");
+       }
+#endif
+       level1_table0 = level0_table + 512;
+       level1_table1 = level1_table0 + 512;
+       level2_table0 = level1_table1 + 512;
+       level2_table1 = level2_table0 + 512;
+#ifdef CONFIG_FSL_LSCH2
+       level2_table2 = level2_table1 + 512;
+#endif
+       table.ptr = level0_table;
 
        /* Invalidate all table entries */
        memset(level0_table, 0, PGTABLE_SIZE);
@@ -269,17 +345,34 @@ static inline void final_mmu_setup(void)
                               &final_mmu_table[i]);
                }
        }
+       /* Set the secure memory to secure in MMU */
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+       if (el == 3 && gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED) {
+#ifdef CONFIG_FSL_LSCH3
+               level2_table_secure = level2_table1 + 512;
+#elif defined(CONFIG_FSL_LSCH2)
+               level2_table_secure = level2_table2 + 512;
+#endif
+               if (!final_secure_ddr(level0_table,
+                                     level2_table_secure,
+                                     gd->secure_ram & ~0x3)) {
+                       gd->secure_ram |= MEM_RESERVE_SECURE_SECURED;
+                       debug("Now MMU table is in secured memory at 0x%llx\n",
+                             gd->secure_ram & ~0x3);
+               } else {
+                       printf("MMU warning: Failed to secure DDR\n");
+               }
+       }
+#endif
 
        /* flush new MMU table */
-       flush_dcache_range(gd->arch.tlb_addr,
-                          gd->arch.tlb_addr + gd->arch.tlb_size);
+       flush_dcache_range((ulong)level0_table,
+                          (ulong)level0_table + gd->arch.tlb_size);
 
 #ifdef CONFIG_SYS_DPAA_FMAN
        flush_dcache_all();
 #endif
        /* point TTBR to the new table */
-       el = current_el();
-
        set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR_FINAL,
                          MEMORY_ATTRIBUTES);
        /*
index 7217a87502ea95b34c220512e18ed9a4f228e338..b39281260d9c0903b431b916438cb0d21f55e4e9 100644 (file)
 #define CONFIG_SYS_FSL_DDR             /* Freescale DDR driver */
 #define CONFIG_SYS_FSL_DDR_VER         FSL_DDR_VER_5_0
 
+/*
+ * Reserve secure memory
+ * To be aligned with MMU block size
+ */
+#define CONFIG_SYS_MEM_RESERVE_SECURE  (2048 * 1024)   /* 2MB */
+
 #if defined(CONFIG_LS2080A) || defined(CONFIG_LS2085A)
 #define CONFIG_MAX_CPUS                                16
 #define CONFIG_SYS_FSL_IFC_BANK_COUNT          8
index 454409488a751a3db4144fdaf0b60ab54dc09a0b..e030430786ee29301c9be96010cd602d3862a7e2 100644 (file)
@@ -129,7 +129,8 @@ static const struct sys_mmu_table early_mmu_table[] = {
        { CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FSL_IFC_BASE1,
          CONFIG_SYS_FSL_IFC_SIZE1, MT_DEVICE_NGNRNE, PMD_SECT_NON_SHARE },
        { CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
-         CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+         CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL,
+         PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
        /* Map IFC region #2 up to CONFIG_SYS_FLASH_BASE for NAND boot */
        { CONFIG_SYS_FSL_IFC_BASE2, CONFIG_SYS_FSL_IFC_BASE2,
          CONFIG_SYS_FLASH_BASE - CONFIG_SYS_FSL_IFC_BASE2,
@@ -138,7 +139,8 @@ static const struct sys_mmu_table early_mmu_table[] = {
          CONFIG_SYS_FSL_DCSR_SIZE, MT_DEVICE_NGNRNE,
          PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
        { CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
-         CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+         CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL,
+         PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
 #elif defined(CONFIG_FSL_LSCH2)
        { CONFIG_SYS_FSL_CCSR_BASE, CONFIG_SYS_FSL_CCSR_BASE,
          CONFIG_SYS_FSL_CCSR_SIZE, MT_DEVICE_NGNRNE,
@@ -165,7 +167,8 @@ static const struct sys_mmu_table final_mmu_table[] = {
        { CONFIG_SYS_FSL_OCRAM_BASE, CONFIG_SYS_FSL_OCRAM_BASE,
          CONFIG_SYS_FSL_OCRAM_SIZE, MT_NORMAL, PMD_SECT_NON_SHARE },
        { CONFIG_SYS_FSL_DRAM_BASE1, CONFIG_SYS_FSL_DRAM_BASE1,
-         CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+         CONFIG_SYS_FSL_DRAM_SIZE1, MT_NORMAL,
+         PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
        { CONFIG_SYS_FSL_QSPI_BASE2, CONFIG_SYS_FSL_QSPI_BASE2,
          CONFIG_SYS_FSL_QSPI_SIZE2, MT_DEVICE_NGNRNE,
          PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
@@ -183,7 +186,7 @@ static const struct sys_mmu_table final_mmu_table[] = {
        /* For QBMAN portal, only the first 64MB is cache-enabled */
        { CONFIG_SYS_FSL_QBMAN_BASE, CONFIG_SYS_FSL_QBMAN_BASE,
          CONFIG_SYS_FSL_QBMAN_SIZE_1, MT_NORMAL,
-         PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
+         PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN | PMD_SECT_NS },
        { CONFIG_SYS_FSL_QBMAN_BASE + CONFIG_SYS_FSL_QBMAN_SIZE_1,
          CONFIG_SYS_FSL_QBMAN_BASE + CONFIG_SYS_FSL_QBMAN_SIZE_1,
          CONFIG_SYS_FSL_QBMAN_SIZE - CONFIG_SYS_FSL_QBMAN_SIZE_1,
@@ -212,7 +215,8 @@ static const struct sys_mmu_table final_mmu_table[] = {
          CONFIG_SYS_FSL_PEBUF_SIZE, MT_DEVICE_NGNRNE,
          PMD_SECT_NON_SHARE | PMD_SECT_PXN | PMD_SECT_UXN },
        { CONFIG_SYS_FSL_DRAM_BASE2, CONFIG_SYS_FSL_DRAM_BASE2,
-         CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL, PMD_SECT_OUTER_SHARE },
+         CONFIG_SYS_FSL_DRAM_SIZE2, MT_NORMAL,
+         PMD_SECT_OUTER_SHARE | PMD_SECT_NS },
 #elif defined(CONFIG_FSL_LSCH2)
        { CONFIG_SYS_FSL_BOOTROM_BASE, CONFIG_SYS_FSL_BOOTROM_BASE,
          CONFIG_SYS_FSL_BOOTROM_SIZE, MT_DEVICE_NGNRNE,
index 705e3843f4f163656612da27ed5cd94dffdbb954..42d906824ae5423196eca8ca6e3e309446c99284 100644 (file)
@@ -126,6 +126,15 @@ phys_size_t initdram(int board_type)
 
 void dram_init_banksize(void)
 {
+       /*
+        * gd->secure_ram tracks the location of secure memory.
+        * It was set as if the memory starts from 0.
+        * The address needs to add the offset of its bank.
+        */
        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
        gd->bd->bi_dram[0].size = gd->ram_size;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+       gd->secure_ram = gd->bd->bi_dram[0].start + gd->secure_ram;
+       gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
 }
index 249d0565fc5ce3f1a0add741dda644adcdb7c8af..11bc0f24d9abe933f13ed335e4dc6a1d80c34008 100644 (file)
@@ -186,13 +186,28 @@ phys_size_t initdram(int board_type)
 
 void dram_init_banksize(void)
 {
+       /*
+        * gd->secure_ram tracks the location of secure memory.
+        * It was set as if the memory starts from 0.
+        * The address needs to add the offset of its bank.
+        */
        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
        if (gd->ram_size > CONFIG_SYS_DDR_BLOCK1_SIZE) {
                gd->bd->bi_dram[0].size = CONFIG_SYS_DDR_BLOCK1_SIZE;
                gd->bd->bi_dram[1].start = CONFIG_SYS_DDR_BLOCK2_BASE;
                gd->bd->bi_dram[1].size = gd->ram_size -
                                          CONFIG_SYS_DDR_BLOCK1_SIZE;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[1].start +
+                                gd->secure_ram -
+                                CONFIG_SYS_DDR_BLOCK1_SIZE;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        } else {
                gd->bd->bi_dram[0].size = gd->ram_size;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[0].start + gd->secure_ram;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        }
 }
index 47d73ef75aaae951e448911fa2f92631e9275a6c..56c5d96e99d5914e14078d3aedfb8f5ba97ef828 100644 (file)
@@ -175,14 +175,29 @@ void dram_init_banksize(void)
        phys_size_t dp_ddr_size;
 #endif
 
+       /*
+        * gd->secure_ram tracks the location of secure memory.
+        * It was set as if the memory starts from 0.
+        * The address needs to add the offset of its bank.
+        */
        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
        if (gd->ram_size > CONFIG_SYS_LS2_DDR_BLOCK1_SIZE) {
                gd->bd->bi_dram[0].size = CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
                gd->bd->bi_dram[1].start = CONFIG_SYS_DDR_BLOCK2_BASE;
                gd->bd->bi_dram[1].size = gd->ram_size -
                                          CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[1].start +
+                                gd->secure_ram -
+                                CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        } else {
                gd->bd->bi_dram[0].size = gd->ram_size;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[0].start + gd->secure_ram;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        }
 
 #ifdef CONFIG_SYS_DP_DDR_BASE_PHY
index 7e67ee033567058d408c152654994acdc1540b92..9fb5e112db00d0ff70f24448a718a26b83aadfd2 100644 (file)
@@ -175,14 +175,29 @@ void dram_init_banksize(void)
        phys_size_t dp_ddr_size;
 #endif
 
+       /*
+        * gd->secure_ram tracks the location of secure memory.
+        * It was set as if the memory starts from 0.
+        * The address needs to add the offset of its bank.
+        */
        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
        if (gd->ram_size > CONFIG_SYS_LS2_DDR_BLOCK1_SIZE) {
                gd->bd->bi_dram[0].size = CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
                gd->bd->bi_dram[1].start = CONFIG_SYS_DDR_BLOCK2_BASE;
                gd->bd->bi_dram[1].size = gd->ram_size -
                                          CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[1].start +
+                                gd->secure_ram -
+                                CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        } else {
                gd->bd->bi_dram[0].size = gd->ram_size;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[0].start + gd->secure_ram;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        }
 
 #ifdef CONFIG_SYS_DP_DDR_BASE_PHY
index 76f3b59e4e9d04fb7154af25872cf19b7dbfb7ec..6c191738ec4a013c8bad341b93ffc547dead0780 100644 (file)
@@ -175,14 +175,29 @@ void dram_init_banksize(void)
        phys_size_t dp_ddr_size;
 #endif
 
+       /*
+        * gd->secure_ram tracks the location of secure memory.
+        * It was set as if the memory starts from 0.
+        * The address needs to add the offset of its bank.
+        */
        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
        if (gd->ram_size > CONFIG_SYS_LS2_DDR_BLOCK1_SIZE) {
                gd->bd->bi_dram[0].size = CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
                gd->bd->bi_dram[1].start = CONFIG_SYS_DDR_BLOCK2_BASE;
                gd->bd->bi_dram[1].size = gd->ram_size -
                                          CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[1].start +
+                                gd->secure_ram -
+                                CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        } else {
                gd->bd->bi_dram[0].size = gd->ram_size;
+#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
+               gd->secure_ram = gd->bd->bi_dram[0].start + gd->secure_ram;
+               gd->secure_ram |= MEM_RESERVE_SECURE_MAINTAINED;
+#endif
        }
 
 #ifdef CONFIG_SYS_DP_DDR_BASE_PHY