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