1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2014 - 2015 Xilinx, Inc. 4 * Michal Simek <michal.simek (at) 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 #ifdef CONFIG_SYS_MEM_RSVD_FOR_MMU 108 int reserve_mmu(void) 109 { 110 initialize_tcm(TCM_LOCK); 111 memset((void *)ZYNQMP_TCM_BASE_ADDR, 0, ZYNQMP_TCM_SIZE); 112 gd->arch.tlb_size = PGTABLE_SIZE; 113 gd->arch.tlb_addr = ZYNQMP_TCM_BASE_ADDR; 114 115 return 0; 116 } 117 #endif 118 119 static unsigned int zynqmp_get_silicon_version_secure(void) 120 { 121 u32 ver; 122 123 ver = readl(&csu_base->version); 124 ver &= ZYNQMP_SILICON_VER_MASK; 125 ver >>= ZYNQMP_SILICON_VER_SHIFT; 126 127 return ver; 128 } 129 130 unsigned int zynqmp_get_silicon_version(void) 131 { 132 if (current_el() == 3) 133 return zynqmp_get_silicon_version_secure(); 134 135 gd->cpu_clk = get_tbclk(); 136 137 switch (gd->cpu_clk) { 138 case 50000000: 139 return ZYNQMP_CSU_VERSION_QEMU; 140 } 141 142 return ZYNQMP_CSU_VERSION_SILICON; 143 } 144 145 #define ZYNQMP_MMIO_READ 0xC2000014 146 #define ZYNQMP_MMIO_WRITE 0xC2000013 147 148 int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, 149 u32 arg3, u32 *ret_payload) 150 { 151 /* 152 * Added SIP service call Function Identifier 153 * Make sure to stay in x0 register 154 */ 155 struct pt_regs regs; 156 157 regs.regs[0] = pm_api_id; 158 regs.regs[1] = ((u64)arg1 << 32) | arg0; 159 regs.regs[2] = ((u64)arg3 << 32) | arg2; 160 161 smc_call(®s); 162 163 if (ret_payload != NULL) { 164 ret_payload[0] = (u32)regs.regs[0]; 165 ret_payload[1] = upper_32_bits(regs.regs[0]); 166 ret_payload[2] = (u32)regs.regs[1]; 167 ret_payload[3] = upper_32_bits(regs.regs[1]); 168 ret_payload[4] = (u32)regs.regs[2]; 169 } 170 171 return regs.regs[0]; 172 } 173 174 #define ZYNQMP_SIP_SVC_GET_API_VERSION 0xC2000001 175 176 #define ZYNQMP_PM_VERSION_MAJOR 1 177 #define ZYNQMP_PM_VERSION_MINOR 0 178 #define ZYNQMP_PM_VERSION_MAJOR_SHIFT 16 179 #define ZYNQMP_PM_VERSION_MINOR_MASK 0xFFFF 180 181 #define ZYNQMP_PM_VERSION \ 182 ((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \ 183 ZYNQMP_PM_VERSION_MINOR) 184 185 #if defined(CONFIG_CLK_ZYNQMP) 186 void zynqmp_pmufw_version(void) 187 { 188 int ret; 189 u32 ret_payload[PAYLOAD_ARG_CNT]; 190 u32 pm_api_version; 191 192 ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0, 193 ret_payload); 194 pm_api_version = ret_payload[1]; 195 196 if (ret) 197 panic("PMUFW is not found - Please load it!\n"); 198 199 printf("PMUFW:\tv%d.%d\n", 200 pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, 201 pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK); 202 203 if (pm_api_version < ZYNQMP_PM_VERSION) 204 panic("PMUFW version error. Expected: v%d.%d\n", 205 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR); 206 } 207 #endif 208 209 static int zynqmp_mmio_rawwrite(const u32 address, 210 const u32 mask, 211 const u32 value) 212 { 213 u32 data; 214 u32 value_local = value; 215 int ret; 216 217 ret = zynqmp_mmio_read(address, &data); 218 if (ret) 219 return ret; 220 221 data &= ~mask; 222 value_local &= mask; 223 value_local |= data; 224 writel(value_local, (ulong)address); 225 return 0; 226 } 227 228 static int zynqmp_mmio_rawread(const u32 address, u32 *value) 229 { 230 *value = readl((ulong)address); 231 return 0; 232 } 233 234 int zynqmp_mmio_write(const u32 address, 235 const u32 mask, 236 const u32 value) 237 { 238 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) 239 return zynqmp_mmio_rawwrite(address, mask, value); 240 else 241 return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask, 242 value, 0, NULL); 243 244 return -EINVAL; 245 } 246 247 int zynqmp_mmio_read(const u32 address, u32 *value) 248 { 249 u32 ret_payload[PAYLOAD_ARG_CNT]; 250 u32 ret; 251 252 if (!value) 253 return -EINVAL; 254 255 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { 256 ret = zynqmp_mmio_rawread(address, value); 257 } else { 258 ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0, 259 0, ret_payload); 260 *value = ret_payload[1]; 261 } 262 263 return ret; 264 } 265