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 <arch_helpers.h> 32 #include <cci.h> 33 #include <debug.h> 34 #include <gicv2.h> 35 #include <mmio.h> 36 #include <plat_arm.h> 37 #include <platform.h> 38 #include <xlat_tables.h> 39 #include "../zynqmp_private.h" 40 41 /* 42 * Table of regions to map using the MMU. 43 * This doesn't include TZRAM as the 'mem_layout' argument passed to 44 * configure_mmu_elx() will give the available subset of that, 45 */ 46 const mmap_region_t plat_arm_mmap[] = { 47 { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 48 { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 49 { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 50 {0} 51 }; 52 53 static unsigned int zynqmp_get_silicon_ver(void) 54 { 55 unsigned int ver; 56 57 ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 58 ver &= ZYNQMP_SILICON_VER_MASK; 59 ver >>= ZYNQMP_SILICON_VER_SHIFT; 60 61 return ver; 62 } 63 64 unsigned int zynqmp_get_uart_clk(void) 65 { 66 unsigned int ver = zynqmp_get_silicon_ver(); 67 68 switch (ver) { 69 case ZYNQMP_CSU_VERSION_VELOCE: 70 return 48000; 71 case ZYNQMP_CSU_VERSION_EP108: 72 return 25000000; 73 case ZYNQMP_CSU_VERSION_QEMU: 74 return 133000000; 75 } 76 77 return 100000000; 78 } 79 80 static unsigned int zynqmp_get_system_timer_freq(void) 81 { 82 unsigned int ver = zynqmp_get_silicon_ver(); 83 84 switch (ver) { 85 case ZYNQMP_CSU_VERSION_VELOCE: 86 return 10000; 87 case ZYNQMP_CSU_VERSION_EP108: 88 return 4000000; 89 case ZYNQMP_CSU_VERSION_QEMU: 90 return 50000000; 91 } 92 93 return 100000000; 94 } 95 96 #if LOG_LEVEL >= LOG_LEVEL_NOTICE 97 static const struct { 98 unsigned int id; 99 char *name; 100 } zynqmp_devices[] = { 101 { 102 .id = 0x10, 103 .name = "3EG", 104 }, 105 { 106 .id = 0x11, 107 .name = "2EG", 108 }, 109 { 110 .id = 0x20, 111 .name = "5EV", 112 }, 113 { 114 .id = 0x21, 115 .name = "4EV", 116 }, 117 { 118 .id = 0x30, 119 .name = "7EV", 120 }, 121 { 122 .id = 0x38, 123 .name = "9EG", 124 }, 125 { 126 .id = 0x39, 127 .name = "6EG", 128 }, 129 { 130 .id = 0x40, 131 .name = "11EG", 132 }, 133 { 134 .id = 0x50, 135 .name = "15EG", 136 }, 137 { 138 .id = 0x58, 139 .name = "19EG", 140 }, 141 { 142 .id = 0x59, 143 .name = "17EG", 144 }, 145 }; 146 147 static unsigned int zynqmp_get_silicon_id(void) 148 { 149 uint32_t id; 150 151 id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 152 153 id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK; 154 id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; 155 156 return id; 157 } 158 159 static char *zynqmp_get_silicon_idcode_name(void) 160 { 161 unsigned int id; 162 163 id = zynqmp_get_silicon_id(); 164 for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { 165 if (zynqmp_devices[i].id == id) 166 return zynqmp_devices[i].name; 167 } 168 return "UNKN"; 169 } 170 171 static unsigned int zynqmp_get_rtl_ver(void) 172 { 173 uint32_t ver; 174 175 ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 176 ver &= ZYNQMP_RTL_VER_MASK; 177 ver >>= ZYNQMP_RTL_VER_SHIFT; 178 179 return ver; 180 } 181 182 static char *zynqmp_print_silicon_idcode(void) 183 { 184 uint32_t id, maskid, tmp; 185 186 id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 187 188 tmp = id; 189 tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK | 190 ZYNQMP_CSU_IDCODE_FAMILY_MASK | 191 ZYNQMP_CSU_IDCODE_REVISION_MASK; 192 maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT | 193 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT | 194 ZYNQMP_CSU_IDCODE_REVISION << ZYNQMP_CSU_IDCODE_REVISION_SHIFT; 195 if (tmp != maskid) { 196 ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid); 197 return "UNKN"; 198 } 199 VERBOSE("Xilinx IDCODE 0x%x\n", id); 200 return zynqmp_get_silicon_idcode_name(); 201 } 202 203 static unsigned int zynqmp_get_ps_ver(void) 204 { 205 uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 206 207 ver &= ZYNQMP_PS_VER_MASK; 208 ver >>= ZYNQMP_PS_VER_SHIFT; 209 210 return ver + 1; 211 } 212 213 static void zynqmp_print_platform_name(void) 214 { 215 unsigned int ver = zynqmp_get_silicon_ver(); 216 unsigned int rtl = zynqmp_get_rtl_ver(); 217 char *label = "Unknown"; 218 219 switch (ver) { 220 case ZYNQMP_CSU_VERSION_VELOCE: 221 label = "VELOCE"; 222 break; 223 case ZYNQMP_CSU_VERSION_EP108: 224 label = "EP108"; 225 break; 226 case ZYNQMP_CSU_VERSION_QEMU: 227 label = "QEMU"; 228 break; 229 case ZYNQMP_CSU_VERSION_SILICON: 230 label = "silicon"; 231 break; 232 } 233 234 NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n", 235 zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(), 236 (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE, 237 zynqmp_is_pmu_up() ? ", with PMU firmware" : ""); 238 } 239 #else 240 static inline void zynqmp_print_platform_name(void) { } 241 #endif 242 243 /* 244 * Indicator for PMUFW discovery: 245 * 0 = No FW found 246 * non-zero = FW is present 247 */ 248 static int zynqmp_pmufw_present; 249 250 /* 251 * zynqmp_discover_pmufw - Discover presence of PMUFW 252 * 253 * Discover the presence of PMUFW and store it for later run-time queries 254 * through zynqmp_is_pmu_up. 255 * NOTE: This discovery method is fragile and will break if: 256 * - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW 257 * (be it by error or intentionally) 258 * - XPPU/XMPU may restrict ATF's access to the PMU address space 259 */ 260 static int zynqmp_discover_pmufw(void) 261 { 262 zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL); 263 zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT; 264 265 return !!zynqmp_pmufw_present; 266 } 267 268 /* 269 * zynqmp_is_pmu_up - Find if PMU firmware is up and running 270 * 271 * Return 0 if firmware is not available, non 0 otherwise 272 */ 273 int zynqmp_is_pmu_up(void) 274 { 275 return zynqmp_pmufw_present; 276 } 277 278 /* 279 * A single boot loader stack is expected to work on both the Foundation ZYNQMP 280 * models and the two flavours of the Base ZYNQMP models (AEMv8 & Cortex). The 281 * SYS_ID register provides a mechanism for detecting the differences between 282 * these platforms. This information is stored in a per-BL array to allow the 283 * code to take the correct path.Per BL platform configuration. 284 */ 285 void zynqmp_config_setup(void) 286 { 287 zynqmp_discover_pmufw(); 288 zynqmp_print_platform_name(); 289 290 /* Global timer init - Program time stamp reference clk */ 291 uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL); 292 val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; 293 mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val); 294 295 /* Program freq register in System counter and enable system counter. */ 296 mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq()); 297 mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN); 298 } 299 300 unsigned int plat_get_syscnt_freq2(void) 301 { 302 unsigned int counter_base_frequency; 303 304 /* FIXME: Read the frequency from Frequency modes table */ 305 counter_base_frequency = zynqmp_get_system_timer_freq(); 306 307 return counter_base_frequency; 308 } 309