blob: 9cb2ab25ed58c94f09005f4f860160e8533fe354 [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
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000014#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015
16#include <arch_helpers.h>
17#include <drivers/arm/gicv3.h>
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000018
19#include "gicv3_private.h"
20
21/* GIC600-specific register offsets */
Douglas Raillard1bd2d742017-08-03 15:59:49 +010022#define GICR_PWRR 0x24
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000023
24/* GICR_PWRR fields */
25#define PWRR_RDPD_SHIFT 0
26#define PWRR_RDGPD_SHIFT 2
27#define PWRR_RDGPO_SHIFT 3
28
Douglas Raillard1bd2d742017-08-03 15:59:49 +010029#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
30#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000031
32/* Values to write to GICR_PWRR register to power redistributor */
Douglas Raillard1bd2d742017-08-03 15:59:49 +010033#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
34#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000035
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000036/* GIC600-specific accessor functions */
37static void gicr_write_pwrr(uintptr_t base, unsigned int val)
38{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010039 mmio_write_32(base + GICR_PWRR, val);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000040}
41
42static uint32_t gicr_read_pwrr(uintptr_t base)
43{
Douglas Raillard1bd2d742017-08-03 15:59:49 +010044 return mmio_read_32(base + GICR_PWRR);
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000045}
46
47static int gicr_group_powering_down(uint32_t pwrr)
48{
49 /*
50 * Whether the redistributor group power down operation is in transit:
51 * i.e. it's intending to, but not finished yet.
52 */
53 return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
54}
55
56static void gic600_pwr_on(uintptr_t base)
57{
58 /* Power on redistributor */
59 gicr_write_pwrr(base, PWRR_ON);
60
61 /* Wait until the power on state is reflected */
62 while (gicr_read_pwrr(base) & PWRR_RDGPO)
63 ;
64}
65
66static void gic600_pwr_off(uintptr_t base)
67{
68 /* Power off redistributor */
69 gicr_write_pwrr(base, PWRR_OFF);
70
71 /*
72 * If this is the last man, turning this redistributor frame off will
73 * result in the group itself being powered off. In that case, wait as
74 * long as it's in transition, or has aborted the transition altogether
75 * for any reason.
76 */
77 if (gicr_read_pwrr(base) & PWRR_RDGPD) {
78 while (gicr_group_powering_down(gicr_read_pwrr(base)))
79 ;
80 }
81}
82
Soby Mathew327548c2017-07-13 15:19:51 +010083void gicv3_distif_pre_save(unsigned int proc_num)
84{
85 arm_gicv3_distif_pre_save(proc_num);
86}
87
88void gicv3_distif_post_restore(unsigned int proc_num)
89{
90 arm_gicv3_distif_post_restore(proc_num);
91}
92
Jeenu Viswambharand7a901e2016-12-06 16:15:22 +000093/*
94 * Power off GIC600 redistributor
95 */
96void gicv3_rdistif_off(unsigned int proc_num)
97{
98 uintptr_t gicr_base;
99
100 assert(gicv3_driver_data);
101 assert(proc_num < gicv3_driver_data->rdistif_num);
102 assert(gicv3_driver_data->rdistif_base_addrs);
103
104 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
105 assert(gicr_base);
106
107 /* Attempt to power redistributor off */
108 gic600_pwr_off(gicr_base);
109}
110
111/*
112 * Power on GIC600 redistributor
113 */
114void gicv3_rdistif_on(unsigned int proc_num)
115{
116 uintptr_t gicr_base;
117
118 assert(gicv3_driver_data);
119 assert(proc_num < gicv3_driver_data->rdistif_num);
120 assert(gicv3_driver_data->rdistif_base_addrs);
121
122 gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
123 assert(gicr_base);
124
125 /* Power redistributor on */
126 gic600_pwr_on(gicr_base);
127}