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/armv8/mmu.h> 12 #include <asm/io.h> 13 14 #define ZYNQ_SILICON_VER_MASK 0xF000 15 #define ZYNQ_SILICON_VER_SHIFT 12 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 static struct mm_region zynqmp_mem_map[] = { 20 { 21 .virt = 0x0UL, 22 .phys = 0x0UL, 23 .size = 0x80000000UL, 24 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 25 PTE_BLOCK_INNER_SHARE 26 }, { 27 .virt = 0x80000000UL, 28 .phys = 0x80000000UL, 29 .size = 0x70000000UL, 30 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 31 PTE_BLOCK_NON_SHARE | 32 PTE_BLOCK_PXN | PTE_BLOCK_UXN 33 }, { 34 .virt = 0xf8000000UL, 35 .phys = 0xf8000000UL, 36 .size = 0x07e00000UL, 37 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 38 PTE_BLOCK_NON_SHARE | 39 PTE_BLOCK_PXN | PTE_BLOCK_UXN 40 }, { 41 #if defined(CONFIG_DEFINE_TCM_OCM_MMAP) 42 .virt = 0xffe00000UL, 43 .phys = 0xffe00000UL, 44 .size = 0x00200000UL, 45 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 46 PTE_BLOCK_INNER_SHARE 47 }, { 48 #endif 49 .virt = 0x400000000UL, 50 .phys = 0x400000000UL, 51 .size = 0x200000000UL, 52 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 53 PTE_BLOCK_NON_SHARE | 54 PTE_BLOCK_PXN | PTE_BLOCK_UXN 55 }, { 56 .virt = 0x600000000UL, 57 .phys = 0x600000000UL, 58 .size = 0x800000000UL, 59 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 60 PTE_BLOCK_INNER_SHARE 61 }, { 62 .virt = 0xe00000000UL, 63 .phys = 0xe00000000UL, 64 .size = 0xf200000000UL, 65 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 66 PTE_BLOCK_NON_SHARE | 67 PTE_BLOCK_PXN | PTE_BLOCK_UXN 68 }, { 69 /* List terminator */ 70 0, 71 } 72 }; 73 struct mm_region *mem_map = zynqmp_mem_map; 74 75 u64 get_page_table_size(void) 76 { 77 return 0x14000; 78 } 79 80 static unsigned int zynqmp_get_silicon_version_secure(void) 81 { 82 u32 ver; 83 84 ver = readl(&csu_base->version); 85 ver &= ZYNQMP_SILICON_VER_MASK; 86 ver >>= ZYNQMP_SILICON_VER_SHIFT; 87 88 return ver; 89 } 90 91 unsigned int zynqmp_get_silicon_version(void) 92 { 93 if (current_el() == 3) 94 return zynqmp_get_silicon_version_secure(); 95 96 gd->cpu_clk = get_tbclk(); 97 98 switch (gd->cpu_clk) { 99 case 0 ... 1000000: 100 return ZYNQMP_CSU_VERSION_VELOCE; 101 case 50000000: 102 return ZYNQMP_CSU_VERSION_QEMU; 103 case 4000000: 104 return ZYNQMP_CSU_VERSION_EP108; 105 } 106 107 return ZYNQMP_CSU_VERSION_SILICON; 108 } 109 110 #define ZYNQMP_MMIO_READ 0xC2000014 111 #define ZYNQMP_MMIO_WRITE 0xC2000013 112 113 int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, 114 u32 arg3, u32 *ret_payload) 115 { 116 /* 117 * Added SIP service call Function Identifier 118 * Make sure to stay in x0 register 119 */ 120 struct pt_regs regs; 121 122 regs.regs[0] = pm_api_id; 123 regs.regs[1] = ((u64)arg1 << 32) | arg0; 124 regs.regs[2] = ((u64)arg3 << 32) | arg2; 125 126 smc_call(®s); 127 128 if (ret_payload != NULL) { 129 ret_payload[0] = (u32)regs.regs[0]; 130 ret_payload[1] = upper_32_bits(regs.regs[0]); 131 ret_payload[2] = (u32)regs.regs[1]; 132 ret_payload[3] = upper_32_bits(regs.regs[1]); 133 ret_payload[4] = (u32)regs.regs[2]; 134 } 135 136 return regs.regs[0]; 137 } 138 139 #define ZYNQMP_SIP_SVC_GET_API_VERSION 0xC2000001 140 141 #define ZYNQMP_PM_VERSION_MAJOR 0 142 #define ZYNQMP_PM_VERSION_MINOR 3 143 #define ZYNQMP_PM_VERSION_MAJOR_SHIFT 16 144 #define ZYNQMP_PM_VERSION_MINOR_MASK 0xFFFF 145 146 #define ZYNQMP_PM_VERSION \ 147 ((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \ 148 ZYNQMP_PM_VERSION_MINOR) 149 150 #if defined(CONFIG_CLK_ZYNQMP) 151 void zynqmp_pmufw_version(void) 152 { 153 int ret; 154 u32 ret_payload[PAYLOAD_ARG_CNT]; 155 u32 pm_api_version; 156 157 ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0, 158 ret_payload); 159 pm_api_version = ret_payload[1]; 160 161 if (ret) 162 panic("PMUFW is not found - Please load it!\n"); 163 164 printf("PMUFW:\tv%d.%d\n", 165 pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, 166 pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK); 167 168 if (pm_api_version != ZYNQMP_PM_VERSION) 169 panic("PMUFW version error. Expected: v%d.%d\n", 170 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR); 171 } 172 #endif 173 174 static int zynqmp_mmio_rawwrite(const u32 address, 175 const u32 mask, 176 const u32 value) 177 { 178 u32 data; 179 u32 value_local = value; 180 181 zynqmp_mmio_read(address, &data); 182 data &= ~mask; 183 value_local &= mask; 184 value_local |= data; 185 writel(value_local, (ulong)address); 186 return 0; 187 } 188 189 static int zynqmp_mmio_rawread(const u32 address, u32 *value) 190 { 191 *value = readl((ulong)address); 192 return 0; 193 } 194 195 int zynqmp_mmio_write(const u32 address, 196 const u32 mask, 197 const u32 value) 198 { 199 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) 200 return zynqmp_mmio_rawwrite(address, mask, value); 201 else if (!IS_ENABLED(CONFIG_SPL_BUILD)) 202 return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask, 203 value, 0, NULL); 204 205 return -EINVAL; 206 } 207 208 int zynqmp_mmio_read(const u32 address, u32 *value) 209 { 210 u32 ret_payload[PAYLOAD_ARG_CNT]; 211 u32 ret; 212 213 if (!value) 214 return -EINVAL; 215 216 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { 217 ret = zynqmp_mmio_rawread(address, value); 218 } else if (!IS_ENABLED(CONFIG_SPL_BUILD)) { 219 ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0, 220 0, ret_payload); 221 *value = ret_payload[1]; 222 } 223 224 return ret; 225 } 226