Home | History | Annotate | Download | only in v3
      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