blob: 217c08fdba2c441c0d55d301db47b7e21929f87a [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
35/* Generic GICv3 resources */
36extern const gicv3_driver_data_t *gicv3_driver_data;
37
38/* GIC600-specific accessor functions */
39static void gicr_write_pwrr(uintptr_t base, unsigned int val)
40{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010041 mmio_write_32(base + GICR_PWRR, val);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000042}
43
44static uint32_t gicr_read_pwrr(uintptr_t base)
45{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010046 return mmio_read_32(base + GICR_PWRR);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000047}
48
49static int gicr_group_powering_down(uint32_t pwrr)
50{
51 /*
52 * Whether the redistributor group power down operation is in transit:
53 * i.e. it's intending to, but not finished yet.
54 */
55 return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
56}
57
58static void gic600_pwr_on(uintptr_t base)
59{
60 /* Power on redistributor */
61 gicr_write_pwrr(base, PWRR_ON);
62
63 /* Wait until the power on state is reflected */
64 while (gicr_read_pwrr(base) & PWRR_RDGPO)
65 ;
66}
67
68static void gic600_pwr_off(uintptr_t base)
69{
70 /* Power off redistributor */
71 gicr_write_pwrr(base, PWRR_OFF);
72
73 /*
74 * If this is the last man, turning this redistributor frame off will
75 * result in the group itself being powered off. In that case, wait as
76 * long as it's in transition, or has aborted the transition altogether
77 * for any reason.
78 */
79 if (gicr_read_pwrr(base) & PWRR_RDGPD) {
80 while (gicr_group_powering_down(gicr_read_pwrr(base)))
81 ;
82 }
83}
84
85/*
86 * Power off GIC600 redistributor
87 */
88void gicv3_rdistif_off(unsigned int proc_num)
89{
90 uintptr_t gicr_base;
91
92 assert(gicv3_driver_data);
93 assert(proc_num < gicv3_driver_data->rdistif_num);
94 assert(gicv3_driver_data->rdistif_base_addrs);
95
96 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
97 assert(gicr_base);
98
99 /* Attempt to power redistributor off */
100 gic600_pwr_off(gicr_base);
101}
102
103/*
104 * Power on GIC600 redistributor
105 */
106void gicv3_rdistif_on(unsigned int proc_num)
107{
108 uintptr_t gicr_base;
109
110 assert(gicv3_driver_data);
111 assert(proc_num < gicv3_driver_data->rdistif_num);
112 assert(gicv3_driver_data->rdistif_base_addrs);
113
114 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
115 assert(gicr_base);
116
117 /* Power redistributor on */
118 gic600_pwr_on(gicr_base);
119}