blob: 2d3fdb600eb4a617ec368aa78cab6962234b5085 [file] [log] [blame]
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Broadcom.
4 */
5#include <common.h>
Hou Zhiqiang6f6876a2021-03-05 15:02:35 +08006#include <cpu_func.h>
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +05307#include <dm.h>
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +05308#include <regmap.h>
9#include <syscon.h>
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -080010#include <asm/gic.h>
11#include <asm/gic-v3.h>
12#include <asm/io.h>
Simon Glasscd93d622020-05-10 11:40:13 -060013#include <linux/bitops.h>
Wasim Khanf381a262020-02-14 11:00:52 +053014#include <linux/sizes.h>
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -080015
16static u32 lpi_id_bits;
17
18#define LPI_NRBITS lpi_id_bits
19#define LPI_PROPBASE_SZ ALIGN(BIT(LPI_NRBITS), SZ_64K)
20#define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K)
21
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053022/* Number of GIC re-distributors */
23#define MAX_GIC_REDISTRIBUTORS 8
24
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -080025/*
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053026 * gic_v3_its_priv - gic details
27 *
28 * @gicd_base: gicd base address
29 * @gicr_base: gicr base address
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053030 * @lpi_base: gic lpi base address
31 * @num_redist: number of gic re-distributors
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053032 */
33struct gic_v3_its_priv {
34 ulong gicd_base;
35 ulong gicr_base;
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053036 ulong lpi_base;
37 u32 num_redist;
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053038};
39
40static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv)
41{
42 struct udevice *dev;
43 fdt_addr_t addr;
44 int ret;
45
46 ret = uclass_get_device_by_driver(UCLASS_IRQ,
Simon Glass65e25be2020-12-28 20:34:56 -070047 DM_DRIVER_GET(arm_gic_v3_its), &dev);
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053048 if (ret) {
49 pr_err("%s: failed to get %s irq device\n", __func__,
Simon Glass65e25be2020-12-28 20:34:56 -070050 DM_DRIVER_GET(arm_gic_v3_its)->name);
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053051 return ret;
52 }
53
54 addr = dev_read_addr_index(dev, 0);
55 if (addr == FDT_ADDR_T_NONE) {
56 pr_err("%s: failed to get GICD address\n", __func__);
57 return -EINVAL;
58 }
59 priv->gicd_base = addr;
60
61 addr = dev_read_addr_index(dev, 1);
62 if (addr == FDT_ADDR_T_NONE) {
63 pr_err("%s: failed to get GICR address\n", __func__);
64 return -EINVAL;
65 }
66 priv->gicr_base = addr;
67
68 return 0;
69}
70
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053071static int gic_v3_its_get_gic_lpi_addr(struct gic_v3_its_priv *priv)
72{
73 struct regmap *regmap;
74 struct udevice *dev;
75 int ret;
76
77 ret = uclass_get_device_by_driver(UCLASS_SYSCON,
Simon Glass65e25be2020-12-28 20:34:56 -070078 DM_DRIVER_GET(gic_lpi_syscon), &dev);
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053079 if (ret) {
80 pr_err("%s: failed to get %s syscon device\n", __func__,
Simon Glass65e25be2020-12-28 20:34:56 -070081 DM_DRIVER_GET(gic_lpi_syscon)->name);
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053082 return ret;
83 }
84
85 regmap = syscon_get_regmap(dev);
86 if (!regmap) {
87 pr_err("%s: failed to regmap for %s syscon device\n", __func__,
Simon Glass65e25be2020-12-28 20:34:56 -070088 DM_DRIVER_GET(gic_lpi_syscon)->name);
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +053089 return -ENODEV;
90 }
91 priv->lpi_base = regmap->ranges[0].start;
92
93 priv->num_redist = dev_read_u32_default(dev, "max-gic-redistributors",
94 MAX_GIC_REDISTRIBUTORS);
95
96 return 0;
97}
98
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +053099/*
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800100 * Program the GIC LPI configuration tables for all
101 * the re-distributors and enable the LPI table
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800102 */
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530103int gic_lpi_tables_init(void)
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800104{
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530105 struct gic_v3_its_priv priv;
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800106 u32 gicd_typer;
107 u64 val;
108 u64 tmp;
109 int i;
110 u64 redist_lpi_base;
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530111 u64 pend_base;
Hou Zhiqiang6f6876a2021-03-05 15:02:35 +0800112 ulong pend_tab_total_sz;
113 void *pend_tab_va;
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800114
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530115 if (gic_v3_its_get_gic_addr(&priv))
116 return -EINVAL;
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800117
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530118 if (gic_v3_its_get_gic_lpi_addr(&priv))
119 return -EINVAL;
120
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530121 gicd_typer = readl((uintptr_t)(priv.gicd_base + GICD_TYPER));
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800122 /* GIC support for Locality specific peripheral interrupts (LPI's) */
123 if (!(gicd_typer & GICD_TYPER_LPIS)) {
124 pr_err("GIC implementation does not support LPI's\n");
125 return -EINVAL;
126 }
127
128 /*
129 * Check for LPI is disabled for all the redistributors.
130 * Once the LPI table is enabled, can not program the
131 * LPI configuration tables again, unless the GIC is reset.
132 */
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530133 for (i = 0; i < priv.num_redist; i++) {
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800134 u32 offset = i * GIC_REDISTRIBUTOR_OFFSET;
135
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530136 if ((readl((uintptr_t)(priv.gicr_base + offset))) &
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800137 GICR_CTLR_ENABLE_LPIS) {
138 pr_err("Re-Distributor %d LPI is already enabled\n",
139 i);
140 return -EINVAL;
141 }
142 }
143
144 /* lpi_id_bits to get LPI_PENDBASE_SZ and LPi_PROPBASE_SZ */
145 lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gicd_typer),
146 ITS_MAX_LPI_NRBITS);
147
148 /* Set PropBase */
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530149 val = (priv.lpi_base |
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800150 GICR_PROPBASER_INNERSHAREABLE |
151 GICR_PROPBASER_RAWAWB |
152 ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
153
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530154 writeq(val, (uintptr_t)(priv.gicr_base + GICR_PROPBASER));
155 tmp = readl((uintptr_t)(priv.gicr_base + GICR_PROPBASER));
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800156 if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
157 if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
158 val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
159 GICR_PROPBASER_CACHEABILITY_MASK);
160 val |= GICR_PROPBASER_NC;
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530161 writeq(val,
162 (uintptr_t)(priv.gicr_base + GICR_PROPBASER));
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800163 }
164 }
165
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530166 redist_lpi_base = priv.lpi_base + LPI_PROPBASE_SZ;
Hou Zhiqiang6f6876a2021-03-05 15:02:35 +0800167 pend_tab_total_sz = priv.num_redist * LPI_PENDBASE_SZ;
168 pend_tab_va = map_physmem(redist_lpi_base, pend_tab_total_sz,
169 MAP_NOCACHE);
170 memset(pend_tab_va, 0, pend_tab_total_sz);
171 flush_cache((ulong)pend_tab_va, pend_tab_total_sz);
172 unmap_physmem(pend_tab_va, MAP_NOCACHE);
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800173
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530174 pend_base = priv.gicr_base + GICR_PENDBASER;
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530175 for (i = 0; i < priv.num_redist; i++) {
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800176 u32 offset = i * GIC_REDISTRIBUTOR_OFFSET;
177
178 val = ((redist_lpi_base + (i * LPI_PENDBASE_SZ)) |
179 GICR_PENDBASER_INNERSHAREABLE |
Hou Zhiqiang6f6876a2021-03-05 15:02:35 +0800180 GICR_PENDBASER_RAWAWB |
181 GICR_PENDBASER_PTZ);
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800182
183 writeq(val, (uintptr_t)(pend_base + offset));
184 tmp = readq((uintptr_t)(pend_base + offset));
185 if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
186 val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
187 GICR_PENDBASER_CACHEABILITY_MASK);
188 val |= GICR_PENDBASER_NC;
189 writeq(val, (uintptr_t)(pend_base + offset));
190 }
191
192 /* Enable LPI for the redistributor */
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530193 writel(GICR_CTLR_ENABLE_LPIS,
194 (uintptr_t)(priv.gicr_base + offset));
Bharat Kumar Reddy Gooty0bc43562019-12-16 09:09:43 -0800195 }
196
197 return 0;
198}
199
Rayagonda Kokatanura76bfe52020-07-26 22:37:32 +0530200static const struct udevice_id gic_v3_its_ids[] = {
201 { .compatible = "arm,gic-v3" },
202 {}
203};
204
205U_BOOT_DRIVER(arm_gic_v3_its) = {
206 .name = "gic-v3",
207 .id = UCLASS_IRQ,
208 .of_match = gic_v3_its_ids,
209};
Rayagonda Kokatanur2ae7adc2020-07-26 22:37:33 +0530210
211static const struct udevice_id gic_lpi_syscon_ids[] = {
212 { .compatible = "gic-lpi-base" },
213 {}
214};
215
216U_BOOT_DRIVER(gic_lpi_syscon) = {
217 .name = "gic-lpi-base",
218 .id = UCLASS_SYSCON,
219 .of_match = gic_lpi_syscon_ids,
220};