1 /* 2 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* 8 * Driver for GIC-600 specific features. This driver only overrides 9 * APIs that are different to those generic ones in GICv3 driver. 10 * 11 * GIC-600 supports independently power-gating redistributor interface. 12 */ 13 14 #include <assert.h> 15 16 #include <arch_helpers.h> 17 #include <drivers/arm/gicv3.h> 18 19 #include "gicv3_private.h" 20 21 /* GIC-600 specific register offsets */ 22 #define GICR_PWRR 0x24 23 24 /* GICR_PWRR fields */ 25 #define PWRR_RDPD_SHIFT 0 26 #define PWRR_RDAG_SHIFT 1 27 #define PWRR_RDGPD_SHIFT 2 28 #define PWRR_RDGPO_SHIFT 3 29 30 #define PWRR_RDPD (1 << PWRR_RDPD_SHIFT) 31 #define PWRR_RDAG (1 << PWRR_RDAG_SHIFT) 32 #define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT) 33 #define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT) 34 35 /* 36 * Values to write to GICR_PWRR register to power redistributor 37 * for operating through the core (GICR_PWRR.RDAG = 0) 38 */ 39 #define PWRR_ON (0 << PWRR_RDPD_SHIFT) 40 #define PWRR_OFF (1 << PWRR_RDPD_SHIFT) 41 42 /* GIC-600 specific accessor functions */ gicr_write_pwrr(uintptr_t base,unsigned int val)43static void gicr_write_pwrr(uintptr_t base, unsigned int val) 44 { 45 mmio_write_32(base + GICR_PWRR, val); 46 } 47 gicr_read_pwrr(uintptr_t base)48static uint32_t gicr_read_pwrr(uintptr_t base) 49 { 50 return mmio_read_32(base + GICR_PWRR); 51 } 52 gicr_wait_group_not_in_transit(uintptr_t base)53static void gicr_wait_group_not_in_transit(uintptr_t base) 54 { 55 /* Check group not transitioning: RDGPD == RDGPO */ 56 while (((gicr_read_pwrr(base) & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) != 57 ((gicr_read_pwrr(base) & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT)) 58 ; 59 } 60 gic600_pwr_on(uintptr_t base)61static void gic600_pwr_on(uintptr_t base) 62 { 63 do { /* Wait until group not transitioning */ 64 gicr_wait_group_not_in_transit(base); 65 66 /* Power on redistributor */ 67 gicr_write_pwrr(base, PWRR_ON); 68 69 /* 70 * Wait until the power on state is reflected. 71 * If RDPD == 0 then powered on. 72 */ 73 } while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON); 74 } 75 gic600_pwr_off(uintptr_t base)76static void gic600_pwr_off(uintptr_t base) 77 { 78 /* Wait until group not transitioning */ 79 gicr_wait_group_not_in_transit(base); 80 81 /* Power off redistributor */ 82 gicr_write_pwrr(base, PWRR_OFF); 83 84 /* 85 * If this is the last man, turning this redistributor frame off will 86 * result in the group itself being powered off and RDGPD = 1. 87 * In that case, wait as long as it's in transition, or has aborted 88 * the transition altogether for any reason. 89 */ 90 if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0) { 91 /* Wait until group not transitioning */ 92 gicr_wait_group_not_in_transit(base); 93 } 94 } 95 gicv3_distif_pre_save(unsigned int proc_num)96void gicv3_distif_pre_save(unsigned int proc_num) 97 { 98 arm_gicv3_distif_pre_save(proc_num); 99 } 100 gicv3_distif_post_restore(unsigned int proc_num)101void gicv3_distif_post_restore(unsigned int proc_num) 102 { 103 arm_gicv3_distif_post_restore(proc_num); 104 } 105 106 /* 107 * Power off GIC-600 redistributor 108 */ gicv3_rdistif_off(unsigned int proc_num)109void gicv3_rdistif_off(unsigned int proc_num) 110 { 111 uintptr_t gicr_base; 112 113 assert(gicv3_driver_data); 114 assert(proc_num < gicv3_driver_data->rdistif_num); 115 assert(gicv3_driver_data->rdistif_base_addrs); 116 117 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; 118 assert(gicr_base); 119 120 /* Attempt to power redistributor off */ 121 gic600_pwr_off(gicr_base); 122 } 123 124 /* 125 * Power on GIC-600 redistributor 126 */ gicv3_rdistif_on(unsigned int proc_num)127void gicv3_rdistif_on(unsigned int proc_num) 128 { 129 uintptr_t gicr_base; 130 131 assert(gicv3_driver_data); 132 assert(proc_num < gicv3_driver_data->rdistif_num); 133 assert(gicv3_driver_data->rdistif_base_addrs); 134 135 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; 136 assert(gicr_base); 137 138 /* Power redistributor on */ 139 gic600_pwr_on(gicr_base); 140 } 141