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