Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2014 - 2015 Xilinx, Inc. |
| 3 | * Michal Simek <michal.simek@xilinx.com> |
| 4 | * |
| 5 | * SPDX-License-Identifier: GPL-2.0+ |
| 6 | */ |
| 7 | |
| 8 | #include <common.h> |
| 9 | #include <asm/arch/hardware.h> |
| 10 | #include <asm/arch/sys_proto.h> |
| 11 | #include <asm/io.h> |
| 12 | |
| 13 | #define ZYNQ_SILICON_VER_MASK 0xF000 |
| 14 | #define ZYNQ_SILICON_VER_SHIFT 12 |
| 15 | |
| 16 | DECLARE_GLOBAL_DATA_PTR; |
| 17 | |
Michal Simek | c23d3f8 | 2015-11-05 08:34:35 +0100 | [diff] [blame] | 18 | static unsigned int zynqmp_get_silicon_version_secure(void) |
| 19 | { |
| 20 | u32 ver; |
| 21 | |
| 22 | ver = readl(&csu_base->version); |
| 23 | ver &= ZYNQMP_SILICON_VER_MASK; |
| 24 | ver >>= ZYNQMP_SILICON_VER_SHIFT; |
| 25 | |
| 26 | return ver; |
| 27 | } |
| 28 | |
Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 29 | unsigned int zynqmp_get_silicon_version(void) |
| 30 | { |
Michal Simek | c23d3f8 | 2015-11-05 08:34:35 +0100 | [diff] [blame] | 31 | if (current_el() == 3) |
| 32 | return zynqmp_get_silicon_version_secure(); |
| 33 | |
Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 34 | gd->cpu_clk = get_tbclk(); |
| 35 | |
| 36 | switch (gd->cpu_clk) { |
Michal Simek | 0ca5557 | 2015-04-15 14:59:19 +0200 | [diff] [blame] | 37 | case 0 ... 1000000: |
| 38 | return ZYNQMP_CSU_VERSION_VELOCE; |
Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 39 | case 50000000: |
| 40 | return ZYNQMP_CSU_VERSION_QEMU; |
Michal Simek | 8d2c02d | 2015-08-20 14:01:39 +0200 | [diff] [blame] | 41 | case 4000000: |
| 42 | return ZYNQMP_CSU_VERSION_EP108; |
Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 43 | } |
| 44 | |
Michal Simek | 8d2c02d | 2015-08-20 14:01:39 +0200 | [diff] [blame] | 45 | return ZYNQMP_CSU_VERSION_SILICON; |
Michal Simek | 04b7e62 | 2015-01-15 10:01:51 +0100 | [diff] [blame] | 46 | } |
Siva Durga Prasad Paladugu | a38e81e | 2014-12-06 12:57:51 +0530 | [diff] [blame] | 47 | |
| 48 | #ifndef CONFIG_SYS_DCACHE_OFF |
| 49 | #include <asm/armv8/mmu.h> |
| 50 | |
| 51 | #define SECTION_SHIFT_L1 30UL |
| 52 | #define SECTION_SHIFT_L2 21UL |
| 53 | #define BLOCK_SIZE_L0 0x8000000000UL |
| 54 | #define BLOCK_SIZE_L1 (1 << SECTION_SHIFT_L1) |
| 55 | #define BLOCK_SIZE_L2 (1 << SECTION_SHIFT_L2) |
| 56 | |
| 57 | #define TCR_TG1_4K (1 << 31) |
| 58 | #define TCR_EPD1_DISABLE (1 << 23) |
| 59 | #define ZYNQMO_VA_BITS 40 |
| 60 | #define ZYNQMP_TCR TCR_TG1_4K | \ |
| 61 | TCR_EPD1_DISABLE | \ |
| 62 | TCR_SHARED_OUTER | \ |
| 63 | TCR_SHARED_INNER | \ |
| 64 | TCR_IRGN_WBWA | \ |
| 65 | TCR_ORGN_WBWA | \ |
| 66 | TCR_T0SZ(ZYNQMO_VA_BITS) |
| 67 | |
| 68 | #define MEMORY_ATTR PMD_SECT_AF | PMD_SECT_INNER_SHARE | \ |
| 69 | PMD_ATTRINDX(MT_NORMAL) | \ |
| 70 | PMD_TYPE_SECT |
| 71 | #define DEVICE_ATTR PMD_SECT_AF | PMD_SECT_PXN | \ |
| 72 | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_NGNRNE) | \ |
| 73 | PMD_TYPE_SECT |
| 74 | |
| 75 | /* 4K size is required to place 512 entries in each level */ |
| 76 | #define TLB_TABLE_SIZE 0x1000 |
| 77 | |
| 78 | struct attr_tbl { |
| 79 | u32 num; |
| 80 | u64 attr; |
| 81 | }; |
| 82 | |
| 83 | static struct attr_tbl attr_tbll1t0[4] = { {16, 0x0}, |
| 84 | {8, DEVICE_ATTR}, |
| 85 | {32, MEMORY_ATTR}, |
| 86 | {456, DEVICE_ATTR} |
| 87 | }; |
| 88 | static struct attr_tbl attr_tbll2t3[4] = { {0x180, DEVICE_ATTR}, |
| 89 | {0x40, 0x0}, |
| 90 | {0x3F, DEVICE_ATTR}, |
| 91 | {0x1, MEMORY_ATTR} |
| 92 | }; |
| 93 | |
| 94 | /* |
| 95 | * This mmu table looks as below |
| 96 | * Level 0 table contains two entries to 512GB sizes. One is Level1 Table 0 |
| 97 | * and other Level1 Table1. |
| 98 | * Level1 Table0 contains entries for each 1GB from 0 to 511GB. |
| 99 | * Level1 Table1 contains entries for each 1GB from 512GB to 1TB. |
| 100 | * Level2 Table0, Level2 Table1, Level2 Table2 and Level2 Table3 contains |
| 101 | * entries for each 2MB starting from 0GB, 1GB, 2GB and 3GB respectively. |
| 102 | */ |
| 103 | static void zynqmp_mmu_setup(void) |
| 104 | { |
| 105 | int el; |
| 106 | u32 index_attr; |
| 107 | u64 i, section_l1t0, section_l1t1; |
| 108 | u64 section_l2t0, section_l2t1, section_l2t2, section_l2t3; |
| 109 | u64 *level0_table = (u64 *)gd->arch.tlb_addr; |
| 110 | u64 *level1_table_0 = (u64 *)(gd->arch.tlb_addr + TLB_TABLE_SIZE); |
| 111 | u64 *level1_table_1 = (u64 *)(gd->arch.tlb_addr + (2 * TLB_TABLE_SIZE)); |
| 112 | u64 *level2_table_0 = (u64 *)(gd->arch.tlb_addr + (3 * TLB_TABLE_SIZE)); |
| 113 | u64 *level2_table_1 = (u64 *)(gd->arch.tlb_addr + (4 * TLB_TABLE_SIZE)); |
| 114 | u64 *level2_table_2 = (u64 *)(gd->arch.tlb_addr + (5 * TLB_TABLE_SIZE)); |
| 115 | u64 *level2_table_3 = (u64 *)(gd->arch.tlb_addr + (6 * TLB_TABLE_SIZE)); |
| 116 | |
| 117 | level0_table[0] = |
| 118 | (u64)level1_table_0 | PMD_TYPE_TABLE; |
| 119 | level0_table[1] = |
| 120 | (u64)level1_table_1 | PMD_TYPE_TABLE; |
| 121 | |
| 122 | /* |
| 123 | * set level 1 table 0, covering 0 to 512GB |
| 124 | * set level 1 table 1, covering 512GB to 1TB |
| 125 | */ |
| 126 | section_l1t0 = 0; |
| 127 | section_l1t1 = BLOCK_SIZE_L0; |
| 128 | |
| 129 | index_attr = 0; |
| 130 | for (i = 0; i < 512; i++) { |
| 131 | level1_table_0[i] = section_l1t0; |
| 132 | level1_table_0[i] |= attr_tbll1t0[index_attr].attr; |
| 133 | attr_tbll1t0[index_attr].num--; |
| 134 | if (attr_tbll1t0[index_attr].num == 0) |
| 135 | index_attr++; |
| 136 | level1_table_1[i] = section_l1t1; |
| 137 | level1_table_1[i] |= DEVICE_ATTR; |
| 138 | section_l1t0 += BLOCK_SIZE_L1; |
| 139 | section_l1t1 += BLOCK_SIZE_L1; |
| 140 | } |
| 141 | |
| 142 | level1_table_0[0] = |
| 143 | (u64)level2_table_0 | PMD_TYPE_TABLE; |
| 144 | level1_table_0[1] = |
| 145 | (u64)level2_table_1 | PMD_TYPE_TABLE; |
| 146 | level1_table_0[2] = |
| 147 | (u64)level2_table_2 | PMD_TYPE_TABLE; |
| 148 | level1_table_0[3] = |
| 149 | (u64)level2_table_3 | PMD_TYPE_TABLE; |
| 150 | |
| 151 | section_l2t0 = 0; |
| 152 | section_l2t1 = section_l2t0 + BLOCK_SIZE_L1; /* 1GB */ |
| 153 | section_l2t2 = section_l2t1 + BLOCK_SIZE_L1; /* 2GB */ |
| 154 | section_l2t3 = section_l2t2 + BLOCK_SIZE_L1; /* 3GB */ |
| 155 | |
| 156 | index_attr = 0; |
| 157 | |
| 158 | for (i = 0; i < 512; i++) { |
| 159 | level2_table_0[i] = section_l2t0 | MEMORY_ATTR; |
| 160 | level2_table_1[i] = section_l2t1 | MEMORY_ATTR; |
| 161 | level2_table_2[i] = section_l2t2 | DEVICE_ATTR; |
| 162 | level2_table_3[i] = section_l2t3 | |
| 163 | attr_tbll2t3[index_attr].attr; |
| 164 | attr_tbll2t3[index_attr].num--; |
| 165 | if (attr_tbll2t3[index_attr].num == 0) |
| 166 | index_attr++; |
| 167 | section_l2t0 += BLOCK_SIZE_L2; |
| 168 | section_l2t1 += BLOCK_SIZE_L2; |
| 169 | section_l2t2 += BLOCK_SIZE_L2; |
| 170 | section_l2t3 += BLOCK_SIZE_L2; |
| 171 | } |
| 172 | |
| 173 | /* flush new MMU table */ |
| 174 | flush_dcache_range(gd->arch.tlb_addr, |
| 175 | gd->arch.tlb_addr + gd->arch.tlb_size); |
| 176 | |
| 177 | /* point TTBR to the new table */ |
| 178 | el = current_el(); |
| 179 | set_ttbr_tcr_mair(el, gd->arch.tlb_addr, |
| 180 | ZYNQMP_TCR, MEMORY_ATTRIBUTES); |
| 181 | |
| 182 | set_sctlr(get_sctlr() | CR_M); |
| 183 | } |
| 184 | |
| 185 | int arch_cpu_init(void) |
| 186 | { |
| 187 | icache_enable(); |
| 188 | __asm_invalidate_dcache_all(); |
| 189 | __asm_invalidate_tlb_all(); |
| 190 | return 0; |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | * This function is called from lib/board.c. |
| 195 | * It recreates MMU table in main memory. MMU and d-cache are enabled earlier. |
| 196 | * There is no need to disable d-cache for this operation. |
| 197 | */ |
| 198 | void enable_caches(void) |
| 199 | { |
| 200 | /* The data cache is not active unless the mmu is enabled */ |
| 201 | if (!(get_sctlr() & CR_M)) { |
| 202 | invalidate_dcache_all(); |
| 203 | __asm_invalidate_tlb_all(); |
| 204 | zynqmp_mmu_setup(); |
| 205 | } |
| 206 | puts("Enabling Caches...\n"); |
| 207 | |
| 208 | set_sctlr(get_sctlr() | CR_C); |
| 209 | } |
Michal Simek | 4516f5d | 2015-08-05 07:50:16 +0200 | [diff] [blame] | 210 | |
| 211 | u64 *arch_get_page_table(void) |
| 212 | { |
| 213 | return (u64 *)(gd->arch.tlb_addr + 0x3000); |
| 214 | } |
Siva Durga Prasad Paladugu | a38e81e | 2014-12-06 12:57:51 +0530 | [diff] [blame] | 215 | #endif |