1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2014 - 2015 Xilinx, Inc. 4 * Michal Simek <michal.simek@xilinx.com> 5 */ 6 7 #include <common.h> 8 #include <asm/arch/hardware.h> 9 #include <asm/arch/sys_proto.h> 10 #include <asm/armv8/mmu.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 18 /* 19 * Number of filled static entries and also the first empty 20 * slot in zynqmp_mem_map. 21 */ 22 #define ZYNQMP_MEM_MAP_USED 4 23 24 #if !defined(CONFIG_ZYNQMP_NO_DDR) 25 #define DRAM_BANKS CONFIG_NR_DRAM_BANKS 26 #else 27 #define DRAM_BANKS 0 28 #endif 29 30 #if defined(CONFIG_DEFINE_TCM_OCM_MMAP) 31 #define TCM_MAP 1 32 #else 33 #define TCM_MAP 0 34 #endif 35 36 /* +1 is end of list which needs to be empty */ 37 #define ZYNQMP_MEM_MAP_MAX (ZYNQMP_MEM_MAP_USED + DRAM_BANKS + TCM_MAP + 1) 38 39 static struct mm_region zynqmp_mem_map[ZYNQMP_MEM_MAP_MAX] = { 40 { 41 .virt = 0x80000000UL, 42 .phys = 0x80000000UL, 43 .size = 0x70000000UL, 44 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 45 PTE_BLOCK_NON_SHARE | 46 PTE_BLOCK_PXN | PTE_BLOCK_UXN 47 }, { 48 .virt = 0xf8000000UL, 49 .phys = 0xf8000000UL, 50 .size = 0x07e00000UL, 51 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 52 PTE_BLOCK_NON_SHARE | 53 PTE_BLOCK_PXN | PTE_BLOCK_UXN 54 }, { 55 .virt = 0x400000000UL, 56 .phys = 0x400000000UL, 57 .size = 0x400000000UL, 58 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 59 PTE_BLOCK_NON_SHARE | 60 PTE_BLOCK_PXN | PTE_BLOCK_UXN 61 }, { 62 .virt = 0x1000000000UL, 63 .phys = 0x1000000000UL, 64 .size = 0xf000000000UL, 65 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 66 PTE_BLOCK_NON_SHARE | 67 PTE_BLOCK_PXN | PTE_BLOCK_UXN 68 } 69 }; 70 71 void mem_map_fill(void) 72 { 73 int banks = ZYNQMP_MEM_MAP_USED; 74 75 #if defined(CONFIG_DEFINE_TCM_OCM_MMAP) 76 zynqmp_mem_map[banks].virt = 0xffe00000UL; 77 zynqmp_mem_map[banks].phys = 0xffe00000UL; 78 zynqmp_mem_map[banks].size = 0x00200000UL; 79 zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 80 PTE_BLOCK_INNER_SHARE; 81 banks = banks + 1; 82 #endif 83 84 #if !defined(CONFIG_ZYNQMP_NO_DDR) 85 for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 86 /* Zero size means no more DDR that's this is end */ 87 if (!gd->bd->bi_dram[i].size) 88 break; 89 90 zynqmp_mem_map[banks].virt = gd->bd->bi_dram[i].start; 91 zynqmp_mem_map[banks].phys = gd->bd->bi_dram[i].start; 92 zynqmp_mem_map[banks].size = gd->bd->bi_dram[i].size; 93 zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 94 PTE_BLOCK_INNER_SHARE; 95 banks = banks + 1; 96 } 97 #endif 98 } 99 100 struct mm_region *mem_map = zynqmp_mem_map; 101 102 u64 get_page_table_size(void) 103 { 104 return 0x14000; 105 } 106 107 #if defined(CONFIG_SYS_MEM_RSVD_FOR_MMU) || defined(CONFIG_DEFINE_TCM_OCM_MMAP) 108 void tcm_init(u8 mode) 109 { 110 puts("WARNING: Initializing TCM overwrites TCM content\n"); 111 initialize_tcm(mode); 112 memset((void *)ZYNQMP_TCM_BASE_ADDR, 0, ZYNQMP_TCM_SIZE); 113 } 114 #endif 115 116 #ifdef CONFIG_SYS_MEM_RSVD_FOR_MMU 117 int reserve_mmu(void) 118 { 119 tcm_init(TCM_LOCK); 120 gd->arch.tlb_size = PGTABLE_SIZE; 121 gd->arch.tlb_addr = ZYNQMP_TCM_BASE_ADDR; 122 123 return 0; 124 } 125 #endif 126 127 static unsigned int zynqmp_get_silicon_version_secure(void) 128 { 129 u32 ver; 130 131 ver = readl(&csu_base->version); 132 ver &= ZYNQMP_SILICON_VER_MASK; 133 ver >>= ZYNQMP_SILICON_VER_SHIFT; 134 135 return ver; 136 } 137 138 unsigned int zynqmp_get_silicon_version(void) 139 { 140 if (current_el() == 3) 141 return zynqmp_get_silicon_version_secure(); 142 143 gd->cpu_clk = get_tbclk(); 144 145 switch (gd->cpu_clk) { 146 case 50000000: 147 return ZYNQMP_CSU_VERSION_QEMU; 148 } 149 150 return ZYNQMP_CSU_VERSION_SILICON; 151 } 152 153 #define ZYNQMP_MMIO_READ 0xC2000014 154 #define ZYNQMP_MMIO_WRITE 0xC2000013 155 156 int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, 157 u32 arg3, u32 *ret_payload) 158 { 159 /* 160 * Added SIP service call Function Identifier 161 * Make sure to stay in x0 register 162 */ 163 struct pt_regs regs; 164 165 regs.regs[0] = pm_api_id; 166 regs.regs[1] = ((u64)arg1 << 32) | arg0; 167 regs.regs[2] = ((u64)arg3 << 32) | arg2; 168 169 smc_call(®s); 170 171 if (ret_payload != NULL) { 172 ret_payload[0] = (u32)regs.regs[0]; 173 ret_payload[1] = upper_32_bits(regs.regs[0]); 174 ret_payload[2] = (u32)regs.regs[1]; 175 ret_payload[3] = upper_32_bits(regs.regs[1]); 176 ret_payload[4] = (u32)regs.regs[2]; 177 } 178 179 return regs.regs[0]; 180 } 181 182 unsigned int __maybe_unused zynqmp_pmufw_version(void) 183 { 184 int ret; 185 u32 ret_payload[PAYLOAD_ARG_CNT]; 186 static u32 pm_api_version = ZYNQMP_PM_VERSION_INVALID; 187 188 /* 189 * Get PMU version only once and later 190 * just return stored values instead of 191 * asking PMUFW again. 192 */ 193 if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) { 194 ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0, 195 ret_payload); 196 pm_api_version = ret_payload[1]; 197 198 if (ret) 199 panic("PMUFW is not found - Please load it!\n"); 200 } 201 202 return pm_api_version; 203 } 204 205 static int zynqmp_mmio_rawwrite(const u32 address, 206 const u32 mask, 207 const u32 value) 208 { 209 u32 data; 210 u32 value_local = value; 211 int ret; 212 213 ret = zynqmp_mmio_read(address, &data); 214 if (ret) 215 return ret; 216 217 data &= ~mask; 218 value_local &= mask; 219 value_local |= data; 220 writel(value_local, (ulong)address); 221 return 0; 222 } 223 224 static int zynqmp_mmio_rawread(const u32 address, u32 *value) 225 { 226 *value = readl((ulong)address); 227 return 0; 228 } 229 230 int zynqmp_mmio_write(const u32 address, 231 const u32 mask, 232 const u32 value) 233 { 234 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) 235 return zynqmp_mmio_rawwrite(address, mask, value); 236 else 237 return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask, 238 value, 0, NULL); 239 240 return -EINVAL; 241 } 242 243 int zynqmp_mmio_read(const u32 address, u32 *value) 244 { 245 u32 ret_payload[PAYLOAD_ARG_CNT]; 246 u32 ret; 247 248 if (!value) 249 return -EINVAL; 250 251 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { 252 ret = zynqmp_mmio_rawread(address, value); 253 } else { 254 ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0, 255 0, ret_payload); 256 *value = ret_payload[1]; 257 } 258 259 return ret; 260 } 261