1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. 4*91f16700Schasinglulu * 5*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu /* 9*91f16700Schasinglulu * Driver for GIC-500 and GIC-600 specific features. This driver only 10*91f16700Schasinglulu * overrides APIs that are different to those generic ones in GICv3 11*91f16700Schasinglulu * driver. 12*91f16700Schasinglulu * 13*91f16700Schasinglulu * GIC-600 supports independently power-gating redistributor interface. 14*91f16700Schasinglulu */ 15*91f16700Schasinglulu 16*91f16700Schasinglulu #include <assert.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu #include <arch_helpers.h> 19*91f16700Schasinglulu #include <common/debug.h> 20*91f16700Schasinglulu #include <drivers/arm/arm_gicv3_common.h> 21*91f16700Schasinglulu #include <drivers/arm/gicv3.h> 22*91f16700Schasinglulu 23*91f16700Schasinglulu #include "gicv3_private.h" 24*91f16700Schasinglulu 25*91f16700Schasinglulu /* GIC-600 specific register offsets */ 26*91f16700Schasinglulu #define GICR_PWRR 0x24U 27*91f16700Schasinglulu 28*91f16700Schasinglulu /* GICR_PWRR fields */ 29*91f16700Schasinglulu #define PWRR_RDPD_SHIFT 0 30*91f16700Schasinglulu #define PWRR_RDAG_SHIFT 1 31*91f16700Schasinglulu #define PWRR_RDGPD_SHIFT 2 32*91f16700Schasinglulu #define PWRR_RDGPO_SHIFT 3 33*91f16700Schasinglulu 34*91f16700Schasinglulu #define PWRR_RDPD (1U << PWRR_RDPD_SHIFT) 35*91f16700Schasinglulu #define PWRR_RDAG (1U << PWRR_RDAG_SHIFT) 36*91f16700Schasinglulu #define PWRR_RDGPD (1U << PWRR_RDGPD_SHIFT) 37*91f16700Schasinglulu #define PWRR_RDGPO (1U << PWRR_RDGPO_SHIFT) 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* 40*91f16700Schasinglulu * Values to write to GICR_PWRR register to power redistributor 41*91f16700Schasinglulu * for operating through the core (GICR_PWRR.RDAG = 0) 42*91f16700Schasinglulu */ 43*91f16700Schasinglulu #define PWRR_ON (0U << PWRR_RDPD_SHIFT) 44*91f16700Schasinglulu #define PWRR_OFF (1U << PWRR_RDPD_SHIFT) 45*91f16700Schasinglulu 46*91f16700Schasinglulu static bool gic600_errata_wa_2384374 __unused; 47*91f16700Schasinglulu 48*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600 49*91f16700Schasinglulu 50*91f16700Schasinglulu /* GIC-600/700 specific accessor functions */ 51*91f16700Schasinglulu static void gicr_write_pwrr(uintptr_t base, unsigned int val) 52*91f16700Schasinglulu { 53*91f16700Schasinglulu mmio_write_32(base + GICR_PWRR, val); 54*91f16700Schasinglulu } 55*91f16700Schasinglulu 56*91f16700Schasinglulu static uint32_t gicr_read_pwrr(uintptr_t base) 57*91f16700Schasinglulu { 58*91f16700Schasinglulu return mmio_read_32(base + GICR_PWRR); 59*91f16700Schasinglulu } 60*91f16700Schasinglulu 61*91f16700Schasinglulu static void gicr_wait_group_not_in_transit(uintptr_t base) 62*91f16700Schasinglulu { 63*91f16700Schasinglulu uint32_t pwrr; 64*91f16700Schasinglulu 65*91f16700Schasinglulu do { 66*91f16700Schasinglulu pwrr = gicr_read_pwrr(base); 67*91f16700Schasinglulu 68*91f16700Schasinglulu /* Check group not transitioning: RDGPD == RDGPO */ 69*91f16700Schasinglulu } while (((pwrr & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) != 70*91f16700Schasinglulu ((pwrr & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT)); 71*91f16700Schasinglulu } 72*91f16700Schasinglulu 73*91f16700Schasinglulu static void gic600_pwr_on(uintptr_t base) 74*91f16700Schasinglulu { 75*91f16700Schasinglulu do { /* Wait until group not transitioning */ 76*91f16700Schasinglulu gicr_wait_group_not_in_transit(base); 77*91f16700Schasinglulu 78*91f16700Schasinglulu /* Power on redistributor */ 79*91f16700Schasinglulu gicr_write_pwrr(base, PWRR_ON); 80*91f16700Schasinglulu 81*91f16700Schasinglulu /* 82*91f16700Schasinglulu * Wait until the power on state is reflected. 83*91f16700Schasinglulu * If RDPD == 0 then powered on. 84*91f16700Schasinglulu */ 85*91f16700Schasinglulu } while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON); 86*91f16700Schasinglulu } 87*91f16700Schasinglulu 88*91f16700Schasinglulu static void gic600_pwr_off(uintptr_t base) 89*91f16700Schasinglulu { 90*91f16700Schasinglulu /* Wait until group not transitioning */ 91*91f16700Schasinglulu gicr_wait_group_not_in_transit(base); 92*91f16700Schasinglulu 93*91f16700Schasinglulu /* Power off redistributor */ 94*91f16700Schasinglulu gicr_write_pwrr(base, PWRR_OFF); 95*91f16700Schasinglulu 96*91f16700Schasinglulu /* 97*91f16700Schasinglulu * If this is the last man, turning this redistributor frame off will 98*91f16700Schasinglulu * result in the group itself being powered off and RDGPD = 1. 99*91f16700Schasinglulu * In that case, wait as long as it's in transition, or has aborted 100*91f16700Schasinglulu * the transition altogether for any reason. 101*91f16700Schasinglulu */ 102*91f16700Schasinglulu if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0U) { 103*91f16700Schasinglulu /* Wait until group not transitioning */ 104*91f16700Schasinglulu gicr_wait_group_not_in_transit(base); 105*91f16700Schasinglulu } 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu static uintptr_t get_gicr_base(unsigned int proc_num) 109*91f16700Schasinglulu { 110*91f16700Schasinglulu uintptr_t gicr_base; 111*91f16700Schasinglulu 112*91f16700Schasinglulu assert(gicv3_driver_data != NULL); 113*91f16700Schasinglulu assert(proc_num < gicv3_driver_data->rdistif_num); 114*91f16700Schasinglulu assert(gicv3_driver_data->rdistif_base_addrs != NULL); 115*91f16700Schasinglulu 116*91f16700Schasinglulu gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; 117*91f16700Schasinglulu assert(gicr_base != 0UL); 118*91f16700Schasinglulu 119*91f16700Schasinglulu return gicr_base; 120*91f16700Schasinglulu } 121*91f16700Schasinglulu 122*91f16700Schasinglulu static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base) 123*91f16700Schasinglulu { 124*91f16700Schasinglulu uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR); 125*91f16700Schasinglulu 126*91f16700Schasinglulu /* 127*91f16700Schasinglulu * The Arm GIC-600 and GIC-700 models have their redistributors 128*91f16700Schasinglulu * powered down at reset. 129*91f16700Schasinglulu */ 130*91f16700Schasinglulu return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) || 131*91f16700Schasinglulu ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) || 132*91f16700Schasinglulu ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700)); 133*91f16700Schasinglulu } 134*91f16700Schasinglulu 135*91f16700Schasinglulu #endif /* GICV3_SUPPORT_GIC600 */ 136*91f16700Schasinglulu 137*91f16700Schasinglulu void gicv3_distif_pre_save(unsigned int proc_num) 138*91f16700Schasinglulu { 139*91f16700Schasinglulu arm_gicv3_distif_pre_save(proc_num); 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu void gicv3_distif_post_restore(unsigned int proc_num) 143*91f16700Schasinglulu { 144*91f16700Schasinglulu arm_gicv3_distif_post_restore(proc_num); 145*91f16700Schasinglulu } 146*91f16700Schasinglulu 147*91f16700Schasinglulu /* 148*91f16700Schasinglulu * Power off GIC-600 redistributor (if configured and detected) 149*91f16700Schasinglulu */ 150*91f16700Schasinglulu void gicv3_rdistif_off(unsigned int proc_num) 151*91f16700Schasinglulu { 152*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600 153*91f16700Schasinglulu uintptr_t gicr_base = get_gicr_base(proc_num); 154*91f16700Schasinglulu 155*91f16700Schasinglulu /* Attempt to power redistributor off */ 156*91f16700Schasinglulu if (gicv3_redists_need_power_mgmt(gicr_base)) { 157*91f16700Schasinglulu gic600_pwr_off(gicr_base); 158*91f16700Schasinglulu } 159*91f16700Schasinglulu #endif 160*91f16700Schasinglulu } 161*91f16700Schasinglulu 162*91f16700Schasinglulu /* 163*91f16700Schasinglulu * Power on GIC-600 redistributor (if configured and detected) 164*91f16700Schasinglulu */ 165*91f16700Schasinglulu void gicv3_rdistif_on(unsigned int proc_num) 166*91f16700Schasinglulu { 167*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600 168*91f16700Schasinglulu uintptr_t gicr_base = get_gicr_base(proc_num); 169*91f16700Schasinglulu 170*91f16700Schasinglulu /* Power redistributor on */ 171*91f16700Schasinglulu if (gicv3_redists_need_power_mgmt(gicr_base)) { 172*91f16700Schasinglulu gic600_pwr_on(gicr_base); 173*91f16700Schasinglulu } 174*91f16700Schasinglulu #endif 175*91f16700Schasinglulu } 176*91f16700Schasinglulu 177*91f16700Schasinglulu #if GIC600_ERRATA_WA_2384374 178*91f16700Schasinglulu /******************************************************************************* 179*91f16700Schasinglulu * Apply part 2 of workaround for errata-2384374 as per SDEN: 180*91f16700Schasinglulu * https://developer.arm.com/documentation/sden892601/latest/ 181*91f16700Schasinglulu ******************************************************************************/ 182*91f16700Schasinglulu void gicv3_apply_errata_wa_2384374(uintptr_t gicr_base) 183*91f16700Schasinglulu { 184*91f16700Schasinglulu if (gic600_errata_wa_2384374) { 185*91f16700Schasinglulu uint32_t gicr_ctlr_val = gicr_read_ctlr(gicr_base); 186*91f16700Schasinglulu 187*91f16700Schasinglulu gicr_write_ctlr(gicr_base, gicr_ctlr_val | 188*91f16700Schasinglulu (GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT | 189*91f16700Schasinglulu GICR_CTLR_DPG1S_BIT)); 190*91f16700Schasinglulu gicr_write_ctlr(gicr_base, gicr_ctlr_val & 191*91f16700Schasinglulu ~(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT | 192*91f16700Schasinglulu GICR_CTLR_DPG1S_BIT)); 193*91f16700Schasinglulu } 194*91f16700Schasinglulu } 195*91f16700Schasinglulu #endif /* GIC600_ERRATA_WA_2384374 */ 196*91f16700Schasinglulu 197*91f16700Schasinglulu void gicv3_check_erratas_applies(uintptr_t gicd_base) 198*91f16700Schasinglulu { 199*91f16700Schasinglulu unsigned int gic_prod_id; 200*91f16700Schasinglulu uint8_t gic_rev; 201*91f16700Schasinglulu 202*91f16700Schasinglulu assert(gicd_base != 0UL); 203*91f16700Schasinglulu 204*91f16700Schasinglulu gicv3_get_component_prodid_rev(gicd_base, &gic_prod_id, &gic_rev); 205*91f16700Schasinglulu 206*91f16700Schasinglulu /* 207*91f16700Schasinglulu * This workaround applicable only to GIC600 and GIC600AE products with 208*91f16700Schasinglulu * revision less than r1p6 and r0p2 respectively. 209*91f16700Schasinglulu * As per GIC600/GIC600AE specification - 210*91f16700Schasinglulu * r1p6 = 0x17 => GICD_IIDR[19:12] 211*91f16700Schasinglulu * r0p2 = 0x04 => GICD_IIDR[19:12] 212*91f16700Schasinglulu */ 213*91f16700Schasinglulu if ((gic_prod_id == GIC_PRODUCT_ID_GIC600) || 214*91f16700Schasinglulu (gic_prod_id == GIC_PRODUCT_ID_GIC600AE)) { 215*91f16700Schasinglulu if (((gic_prod_id == GIC_PRODUCT_ID_GIC600) && 216*91f16700Schasinglulu (gic_rev <= GIC_REV(GIC_VARIANT_R1, GIC_REV_P6))) || 217*91f16700Schasinglulu ((gic_prod_id == GIC_PRODUCT_ID_GIC600AE) && 218*91f16700Schasinglulu (gic_rev <= GIC_REV(GIC_VARIANT_R0, GIC_REV_P2)))) { 219*91f16700Schasinglulu #if GIC600_ERRATA_WA_2384374 220*91f16700Schasinglulu gic600_errata_wa_2384374 = true; 221*91f16700Schasinglulu VERBOSE("%s applies\n", 222*91f16700Schasinglulu "GIC600/GIC600AE errata workaround 2384374"); 223*91f16700Schasinglulu #else 224*91f16700Schasinglulu WARN("%s missing\n", 225*91f16700Schasinglulu "GIC600/GIC600AE errata workaround 2384374"); 226*91f16700Schasinglulu #endif /* GIC600_ERRATA_WA_2384374 */ 227*91f16700Schasinglulu } else { 228*91f16700Schasinglulu VERBOSE("%s not applies\n", 229*91f16700Schasinglulu "GIC600/GIC600AE errata workaround 2384374"); 230*91f16700Schasinglulu } 231*91f16700Schasinglulu } 232*91f16700Schasinglulu } 233