blob: eb4fc548f77faa463aa8961425ecf885b76e324c [file] [log] [blame]
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +00001/*
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 */
Douglas Raillard1bd2d742017-08-03 15:59:49 +010021#define GICR_PWRR 0x24
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000022
23/* GICR_PWRR fields */
24#define PWRR_RDPD_SHIFT 0
25#define PWRR_RDGPD_SHIFT 2
26#define PWRR_RDGPO_SHIFT 3
27
Douglas Raillard1bd2d742017-08-03 15:59:49 +010028#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
29#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000030
31/* Values to write to GICR_PWRR register to power redistributor */
Douglas Raillard1bd2d742017-08-03 15:59:49 +010032#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
33#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000034
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000035/* GIC600-specific accessor functions */
36static void gicr_write_pwrr(uintptr_t base, unsigned int val)
37{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010038 mmio_write_32(base + GICR_PWRR, val);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000039}
40
41static uint32_t gicr_read_pwrr(uintptr_t base)
42{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010043 return mmio_read_32(base + GICR_PWRR);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000044}
45
46static 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
55static 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
65static 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
Soby Mathew327548c2017-07-13 15:19:51 +010082void gicv3_distif_pre_save(unsigned int proc_num)
83{
84 arm_gicv3_distif_pre_save(proc_num);
85}
86
87void gicv3_distif_post_restore(unsigned int proc_num)
88{
89 arm_gicv3_distif_post_restore(proc_num);
90}
91
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000092/*
93 * Power off GIC600 redistributor
94 */
95void 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 */
113void 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}