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