• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)43 static 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)48 static 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)53 static 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)61 static 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)76 static 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)96 void 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)101 void 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)109 void 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)127 void 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