1 /* 2 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <debug.h> 32 #include <generic_delay_timer.h> 33 #include <mmio.h> 34 #include <platform.h> 35 #include <xlat_tables.h> 36 #include "../zynqmp_private.h" 37 38 /* 39 * Table of regions to map using the MMU. 40 * This doesn't include TZRAM as the 'mem_layout' argument passed to 41 * configure_mmu_elx() will give the available subset of that, 42 */ 43 const mmap_region_t plat_arm_mmap[] = { 44 { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 45 { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 46 { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 47 {0} 48 }; 49 50 static unsigned int zynqmp_get_silicon_ver(void) 51 { 52 unsigned int ver; 53 54 ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 55 ver &= ZYNQMP_SILICON_VER_MASK; 56 ver >>= ZYNQMP_SILICON_VER_SHIFT; 57 58 return ver; 59 } 60 61 unsigned int zynqmp_get_uart_clk(void) 62 { 63 unsigned int ver = zynqmp_get_silicon_ver(); 64 65 switch (ver) { 66 case ZYNQMP_CSU_VERSION_VELOCE: 67 return 48000; 68 case ZYNQMP_CSU_VERSION_EP108: 69 return 25000000; 70 case ZYNQMP_CSU_VERSION_QEMU: 71 return 133000000; 72 } 73 74 return 100000000; 75 } 76 77 static unsigned int zynqmp_get_system_timer_freq(void) 78 { 79 unsigned int ver = zynqmp_get_silicon_ver(); 80 81 switch (ver) { 82 case ZYNQMP_CSU_VERSION_VELOCE: 83 return 10000; 84 case ZYNQMP_CSU_VERSION_EP108: 85 return 4000000; 86 case ZYNQMP_CSU_VERSION_QEMU: 87 return 50000000; 88 } 89 90 return 100000000; 91 } 92 93 unsigned int zynqmp_get_silicon_id(void) 94 { 95 uint32_t id; 96 97 id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 98 99 id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK; 100 id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; 101 102 return id; 103 } 104 105 #if LOG_LEVEL >= LOG_LEVEL_NOTICE 106 static const struct { 107 unsigned int id; 108 char *name; 109 } zynqmp_devices[] = { 110 { 111 .id = 0x10, 112 .name = "3EG", 113 }, 114 { 115 .id = 0x11, 116 .name = "2EG", 117 }, 118 { 119 .id = 0x20, 120 .name = "5EV", 121 }, 122 { 123 .id = 0x21, 124 .name = "4EV", 125 }, 126 { 127 .id = 0x30, 128 .name = "7EV", 129 }, 130 { 131 .id = 0x38, 132 .name = "9EG", 133 }, 134 { 135 .id = 0x39, 136 .name = "6EG", 137 }, 138 { 139 .id = 0x40, 140 .name = "11EG", 141 }, 142 { 143 .id = 0x50, 144 .name = "15EG", 145 }, 146 { 147 .id = 0x58, 148 .name = "19EG", 149 }, 150 { 151 .id = 0x59, 152 .name = "17EG", 153 }, 154 }; 155 156 static char *zynqmp_get_silicon_idcode_name(void) 157 { 158 unsigned int id; 159 160 id = zynqmp_get_silicon_id(); 161 for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { 162 if (zynqmp_devices[i].id == id) 163 return zynqmp_devices[i].name; 164 } 165 return "UNKN"; 166 } 167 168 static unsigned int zynqmp_get_rtl_ver(void) 169 { 170 uint32_t ver; 171 172 ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 173 ver &= ZYNQMP_RTL_VER_MASK; 174 ver >>= ZYNQMP_RTL_VER_SHIFT; 175 176 return ver; 177 } 178 179 static char *zynqmp_print_silicon_idcode(void) 180 { 181 uint32_t id, maskid, tmp; 182 183 id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 184 185 tmp = id; 186 tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK | 187 ZYNQMP_CSU_IDCODE_FAMILY_MASK; 188 maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT | 189 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT; 190 if (tmp != maskid) { 191 ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid); 192 return "UNKN"; 193 } 194 VERBOSE("Xilinx IDCODE 0x%x\n", id); 195 return zynqmp_get_silicon_idcode_name(); 196 } 197 198 static unsigned int zynqmp_get_ps_ver(void) 199 { 200 uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 201 202 ver &= ZYNQMP_PS_VER_MASK; 203 ver >>= ZYNQMP_PS_VER_SHIFT; 204 205 return ver + 1; 206 } 207 208 static void zynqmp_print_platform_name(void) 209 { 210 unsigned int ver = zynqmp_get_silicon_ver(); 211 unsigned int rtl = zynqmp_get_rtl_ver(); 212 char *label = "Unknown"; 213 214 switch (ver) { 215 case ZYNQMP_CSU_VERSION_VELOCE: 216 label = "VELOCE"; 217 break; 218 case ZYNQMP_CSU_VERSION_EP108: 219 label = "EP108"; 220 break; 221 case ZYNQMP_CSU_VERSION_QEMU: 222 label = "QEMU"; 223 break; 224 case ZYNQMP_CSU_VERSION_SILICON: 225 label = "silicon"; 226 break; 227 } 228 229 NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n", 230 zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(), 231 (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE, 232 zynqmp_is_pmu_up() ? ", with PMU firmware" : ""); 233 } 234 #else 235 static inline void zynqmp_print_platform_name(void) { } 236 #endif 237 238 /* 239 * Indicator for PMUFW discovery: 240 * 0 = No FW found 241 * non-zero = FW is present 242 */ 243 static int zynqmp_pmufw_present; 244 245 /* 246 * zynqmp_discover_pmufw - Discover presence of PMUFW 247 * 248 * Discover the presence of PMUFW and store it for later run-time queries 249 * through zynqmp_is_pmu_up. 250 * NOTE: This discovery method is fragile and will break if: 251 * - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW 252 * (be it by error or intentionally) 253 * - XPPU/XMPU may restrict ATF's access to the PMU address space 254 */ 255 static int zynqmp_discover_pmufw(void) 256 { 257 zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL); 258 zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT; 259 260 return !!zynqmp_pmufw_present; 261 } 262 263 /* 264 * zynqmp_is_pmu_up - Find if PMU firmware is up and running 265 * 266 * Return 0 if firmware is not available, non 0 otherwise 267 */ 268 int zynqmp_is_pmu_up(void) 269 { 270 return zynqmp_pmufw_present; 271 } 272 273 unsigned int zynqmp_get_bootmode(void) 274 { 275 uint32_t r = mmio_read_32(CRL_APB_BOOT_MODE_USER); 276 277 return r & CRL_APB_BOOT_MODE_MASK; 278 } 279 280 void zynqmp_config_setup(void) 281 { 282 zynqmp_discover_pmufw(); 283 zynqmp_print_platform_name(); 284 285 /* Global timer init - Program time stamp reference clk */ 286 uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL); 287 val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; 288 mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val); 289 290 /* Program freq register in System counter and enable system counter. */ 291 mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq()); 292 mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN); 293 294 generic_delay_timer_init(); 295 } 296 297 unsigned int plat_get_syscnt_freq2(void) 298 { 299 unsigned int counter_base_frequency; 300 301 /* FIXME: Read the frequency from Frequency modes table */ 302 counter_base_frequency = zynqmp_get_system_timer_freq(); 303 304 return counter_base_frequency; 305 } 306