1*d3c37848SAkshay Belsare // SPDX-License-Identifier: BSD-2-Clause
2*d3c37848SAkshay Belsare /*
3*d3c37848SAkshay Belsare * Copyright (C) 2002-2021 Xilinx, Inc. All rights reserved.
4*d3c37848SAkshay Belsare * Copyright (c) 2022 Foundries.io Ltd. (jorge@foundries.io)
5*d3c37848SAkshay Belsare * Copyright (c) 2024-2025, Advanced Micro Devices, Inc. All rights reserved.
6*d3c37848SAkshay Belsare *
7*d3c37848SAkshay Belsare */
8*d3c37848SAkshay Belsare
9*d3c37848SAkshay Belsare #include <assert.h>
10*d3c37848SAkshay Belsare #include <drivers/gpio.h>
11*d3c37848SAkshay Belsare #include <io.h>
12*d3c37848SAkshay Belsare #include <kernel/dt.h>
13*d3c37848SAkshay Belsare #include <kernel/panic.h>
14*d3c37848SAkshay Belsare #include <libfdt.h>
15*d3c37848SAkshay Belsare #include <malloc.h>
16*d3c37848SAkshay Belsare #include <mm/core_mmu.h>
17*d3c37848SAkshay Belsare #include <stdbool.h>
18*d3c37848SAkshay Belsare #include <stdint.h>
19*d3c37848SAkshay Belsare #include <trace.h>
20*d3c37848SAkshay Belsare #include <util.h>
21*d3c37848SAkshay Belsare
22*d3c37848SAkshay Belsare #include "gpio_private.h"
23*d3c37848SAkshay Belsare
24*d3c37848SAkshay Belsare static struct amd_gbank_data ps_bank = {
25*d3c37848SAkshay Belsare .label = "ps_gpio",
26*d3c37848SAkshay Belsare .ngpio = 58,
27*d3c37848SAkshay Belsare .max_bank = PS_BANK_MAX,
28*d3c37848SAkshay Belsare .bank_min[0] = 0,
29*d3c37848SAkshay Belsare .bank_max[0] = 25,
30*d3c37848SAkshay Belsare .bank_min[3] = 26,
31*d3c37848SAkshay Belsare .bank_max[3] = 57,
32*d3c37848SAkshay Belsare };
33*d3c37848SAkshay Belsare
34*d3c37848SAkshay Belsare /* Standard GPIO Operations */
ps_gpio_get_value(struct gpio_chip * chip,unsigned int gpio_pin)35*d3c37848SAkshay Belsare static enum gpio_level ps_gpio_get_value(struct gpio_chip *chip,
36*d3c37848SAkshay Belsare unsigned int gpio_pin)
37*d3c37848SAkshay Belsare {
38*d3c37848SAkshay Belsare uint32_t bank = 0;
39*d3c37848SAkshay Belsare uint32_t pin = 0;
40*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
41*d3c37848SAkshay Belsare chip);
42*d3c37848SAkshay Belsare
43*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
44*d3c37848SAkshay Belsare
45*d3c37848SAkshay Belsare if (io_read32(ps->vbase + DATA_RO_OFFSET(bank)) & BIT(pin))
46*d3c37848SAkshay Belsare return GPIO_LEVEL_HIGH;
47*d3c37848SAkshay Belsare
48*d3c37848SAkshay Belsare return GPIO_LEVEL_LOW;
49*d3c37848SAkshay Belsare }
50*d3c37848SAkshay Belsare
ps_gpio_set_value(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_level level)51*d3c37848SAkshay Belsare static void ps_gpio_set_value(struct gpio_chip *chip,
52*d3c37848SAkshay Belsare unsigned int gpio_pin,
53*d3c37848SAkshay Belsare enum gpio_level level)
54*d3c37848SAkshay Belsare {
55*d3c37848SAkshay Belsare uint32_t bank = 0;
56*d3c37848SAkshay Belsare uint32_t pin = 0;
57*d3c37848SAkshay Belsare uint32_t offset = 0;
58*d3c37848SAkshay Belsare uint32_t lvl = 0;
59*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
60*d3c37848SAkshay Belsare chip);
61*d3c37848SAkshay Belsare
62*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
63*d3c37848SAkshay Belsare
64*d3c37848SAkshay Belsare if (pin < GPIO_NUM_MAX) {
65*d3c37848SAkshay Belsare offset = DATA_LSW_OFFSET(bank);
66*d3c37848SAkshay Belsare } else {
67*d3c37848SAkshay Belsare pin -= GPIO_NUM_MAX;
68*d3c37848SAkshay Belsare offset = DATA_MSW_OFFSET(bank);
69*d3c37848SAkshay Belsare }
70*d3c37848SAkshay Belsare
71*d3c37848SAkshay Belsare /* Explicitly compare the enum value */
72*d3c37848SAkshay Belsare if (level == GPIO_LEVEL_HIGH)
73*d3c37848SAkshay Belsare lvl = 1;
74*d3c37848SAkshay Belsare else
75*d3c37848SAkshay Belsare lvl = 0;
76*d3c37848SAkshay Belsare
77*d3c37848SAkshay Belsare lvl = ~BIT32(pin + GPIO_NUM_MAX) &
78*d3c37848SAkshay Belsare (SHIFT_U32(lvl, pin) | GPIO_UPPER_MASK);
79*d3c37848SAkshay Belsare
80*d3c37848SAkshay Belsare io_write32(ps->vbase + offset, lvl);
81*d3c37848SAkshay Belsare }
82*d3c37848SAkshay Belsare
ps_gpio_get_dir(struct gpio_chip * chip,unsigned int gpio_pin)83*d3c37848SAkshay Belsare static enum gpio_dir ps_gpio_get_dir(struct gpio_chip *chip,
84*d3c37848SAkshay Belsare unsigned int gpio_pin)
85*d3c37848SAkshay Belsare {
86*d3c37848SAkshay Belsare uint32_t bank = 0;
87*d3c37848SAkshay Belsare uint32_t pin = 0;
88*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
89*d3c37848SAkshay Belsare chip);
90*d3c37848SAkshay Belsare
91*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
92*d3c37848SAkshay Belsare
93*d3c37848SAkshay Belsare if (io_read32(ps->vbase + DIRM_OFFSET(bank)) & BIT(pin))
94*d3c37848SAkshay Belsare return GPIO_DIR_OUT;
95*d3c37848SAkshay Belsare
96*d3c37848SAkshay Belsare return GPIO_DIR_IN;
97*d3c37848SAkshay Belsare }
98*d3c37848SAkshay Belsare
ps_gpio_set_dir(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_dir direction)99*d3c37848SAkshay Belsare static void ps_gpio_set_dir(struct gpio_chip *chip,
100*d3c37848SAkshay Belsare unsigned int gpio_pin,
101*d3c37848SAkshay Belsare enum gpio_dir direction)
102*d3c37848SAkshay Belsare {
103*d3c37848SAkshay Belsare uint32_t bank = 0;
104*d3c37848SAkshay Belsare uint32_t pin = 0;
105*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
106*d3c37848SAkshay Belsare chip);
107*d3c37848SAkshay Belsare
108*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
109*d3c37848SAkshay Belsare
110*d3c37848SAkshay Belsare if (direction == GPIO_DIR_OUT) {
111*d3c37848SAkshay Belsare /* set the GPIO pin as output */
112*d3c37848SAkshay Belsare io_setbits32(ps->vbase + DIRM_OFFSET(bank), BIT(pin));
113*d3c37848SAkshay Belsare
114*d3c37848SAkshay Belsare /* configure the output enable reg for the pin */
115*d3c37848SAkshay Belsare io_setbits32(ps->vbase + OUTEN_OFFSET(bank), BIT(pin));
116*d3c37848SAkshay Belsare
117*d3c37848SAkshay Belsare /* set the state of the pin */
118*d3c37848SAkshay Belsare ps_gpio_set_value(chip, gpio_pin, GPIO_LEVEL_LOW);
119*d3c37848SAkshay Belsare } else {
120*d3c37848SAkshay Belsare /* Set the GPIO pin as input */
121*d3c37848SAkshay Belsare io_clrbits32(ps->vbase + DIRM_OFFSET(bank), BIT(pin));
122*d3c37848SAkshay Belsare }
123*d3c37848SAkshay Belsare }
124*d3c37848SAkshay Belsare
ps_gpio_get_intr(struct gpio_chip * chip,unsigned int gpio_pin)125*d3c37848SAkshay Belsare static enum gpio_interrupt ps_gpio_get_intr(struct gpio_chip *chip,
126*d3c37848SAkshay Belsare unsigned int gpio_pin)
127*d3c37848SAkshay Belsare {
128*d3c37848SAkshay Belsare uint32_t bank = 0;
129*d3c37848SAkshay Belsare uint32_t pin = 0;
130*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
131*d3c37848SAkshay Belsare chip);
132*d3c37848SAkshay Belsare
133*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
134*d3c37848SAkshay Belsare
135*d3c37848SAkshay Belsare if ((io_read32(ps->vbase + INTMASK_OFFSET(bank)) & BIT(pin)))
136*d3c37848SAkshay Belsare return GPIO_INTERRUPT_DISABLE;
137*d3c37848SAkshay Belsare
138*d3c37848SAkshay Belsare return GPIO_INTERRUPT_ENABLE;
139*d3c37848SAkshay Belsare }
140*d3c37848SAkshay Belsare
ps_gpio_set_intr(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_interrupt interrupt)141*d3c37848SAkshay Belsare static void ps_gpio_set_intr(struct gpio_chip *chip,
142*d3c37848SAkshay Belsare unsigned int gpio_pin,
143*d3c37848SAkshay Belsare enum gpio_interrupt interrupt)
144*d3c37848SAkshay Belsare {
145*d3c37848SAkshay Belsare uint32_t bank = 0;
146*d3c37848SAkshay Belsare uint32_t pin = 0;
147*d3c37848SAkshay Belsare uint32_t offset = 0;
148*d3c37848SAkshay Belsare uint32_t mask = 0;
149*d3c37848SAkshay Belsare struct amd_gpio_info *ps = container_of(chip, struct amd_gpio_info,
150*d3c37848SAkshay Belsare chip);
151*d3c37848SAkshay Belsare
152*d3c37848SAkshay Belsare amd_gpio_get_bank_and_pin(ps->bdata, gpio_pin, &bank, &pin);
153*d3c37848SAkshay Belsare
154*d3c37848SAkshay Belsare mask = io_read32(ps->vbase + INTMASK_OFFSET(bank)) & BIT(pin);
155*d3c37848SAkshay Belsare
156*d3c37848SAkshay Belsare /*
157*d3c37848SAkshay Belsare * mask = 1 --> Interrupt is masked/disabled.
158*d3c37848SAkshay Belsare * mask = 0 --> Interrupt is un-masked/enabled.
159*d3c37848SAkshay Belsare */
160*d3c37848SAkshay Belsare if (mask && interrupt == GPIO_INTERRUPT_ENABLE) {
161*d3c37848SAkshay Belsare offset = INTEN_OFFSET(bank);
162*d3c37848SAkshay Belsare } else if (!mask && interrupt == GPIO_INTERRUPT_DISABLE) {
163*d3c37848SAkshay Belsare offset = INTDIS_OFFSET(bank);
164*d3c37848SAkshay Belsare } else {
165*d3c37848SAkshay Belsare DMSG("No change, interrupt already %s",
166*d3c37848SAkshay Belsare interrupt ? "Enabled" : "Disabled");
167*d3c37848SAkshay Belsare return;
168*d3c37848SAkshay Belsare }
169*d3c37848SAkshay Belsare
170*d3c37848SAkshay Belsare io_setbits32(ps->vbase + offset, BIT(pin));
171*d3c37848SAkshay Belsare }
172*d3c37848SAkshay Belsare
173*d3c37848SAkshay Belsare static const struct gpio_ops ps_gpio_ops = {
174*d3c37848SAkshay Belsare .get_direction = ps_gpio_get_dir,
175*d3c37848SAkshay Belsare .set_direction = ps_gpio_set_dir,
176*d3c37848SAkshay Belsare .get_value = ps_gpio_get_value,
177*d3c37848SAkshay Belsare .set_value = ps_gpio_set_value,
178*d3c37848SAkshay Belsare .get_interrupt = ps_gpio_get_intr,
179*d3c37848SAkshay Belsare .set_interrupt = ps_gpio_set_intr,
180*d3c37848SAkshay Belsare };
181*d3c37848SAkshay Belsare
amd_ps_gpio_probe(const void * fdt,int node,const void * compat_data __unused)182*d3c37848SAkshay Belsare static TEE_Result amd_ps_gpio_probe(const void *fdt, int node,
183*d3c37848SAkshay Belsare const void *compat_data __unused)
184*d3c37848SAkshay Belsare {
185*d3c37848SAkshay Belsare TEE_Result res = TEE_ERROR_GENERIC;
186*d3c37848SAkshay Belsare int status = DT_STATUS_DISABLED;
187*d3c37848SAkshay Belsare struct amd_gpio_info *ps_gpio = NULL;
188*d3c37848SAkshay Belsare paddr_t base = 0;
189*d3c37848SAkshay Belsare size_t len = 0;
190*d3c37848SAkshay Belsare
191*d3c37848SAkshay Belsare /* Status Check */
192*d3c37848SAkshay Belsare status = fdt_get_status(fdt, node);
193*d3c37848SAkshay Belsare
194*d3c37848SAkshay Belsare /* PS GPIO Controller to be in Non Secure World */
195*d3c37848SAkshay Belsare if (status & DT_STATUS_OK_NSEC) {
196*d3c37848SAkshay Belsare DMSG("PS GPIO controller configured for NS world");
197*d3c37848SAkshay Belsare return TEE_SUCCESS;
198*d3c37848SAkshay Belsare }
199*d3c37848SAkshay Belsare
200*d3c37848SAkshay Belsare /* PS GPIO Controller is disabled for Secure World as well */
201*d3c37848SAkshay Belsare if (!(status & DT_STATUS_OK_SEC)) {
202*d3c37848SAkshay Belsare DMSG("PS GPIO Controller is disabled");
203*d3c37848SAkshay Belsare return TEE_SUCCESS;
204*d3c37848SAkshay Belsare }
205*d3c37848SAkshay Belsare
206*d3c37848SAkshay Belsare ps_gpio = calloc(1, sizeof(*ps_gpio));
207*d3c37848SAkshay Belsare if (!ps_gpio) {
208*d3c37848SAkshay Belsare EMSG("Failed to allocate memory for ps_gpio");
209*d3c37848SAkshay Belsare return TEE_ERROR_OUT_OF_MEMORY;
210*d3c37848SAkshay Belsare }
211*d3c37848SAkshay Belsare
212*d3c37848SAkshay Belsare if (fdt_reg_info(fdt, node, &base, &len) != 0) {
213*d3c37848SAkshay Belsare EMSG("Failed to get Register Base and Size");
214*d3c37848SAkshay Belsare free(ps_gpio);
215*d3c37848SAkshay Belsare return TEE_ERROR_GENERIC;
216*d3c37848SAkshay Belsare }
217*d3c37848SAkshay Belsare
218*d3c37848SAkshay Belsare /* Populate GPIO ops */
219*d3c37848SAkshay Belsare ps_gpio->chip.ops = &ps_gpio_ops;
220*d3c37848SAkshay Belsare /* Populate Bank information */
221*d3c37848SAkshay Belsare ps_gpio->bdata = &ps_bank;
222*d3c37848SAkshay Belsare
223*d3c37848SAkshay Belsare /* Validate node entries */
224*d3c37848SAkshay Belsare assert(base);
225*d3c37848SAkshay Belsare assert(len);
226*d3c37848SAkshay Belsare
227*d3c37848SAkshay Belsare ps_gpio->vbase = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, base,
228*d3c37848SAkshay Belsare len);
229*d3c37848SAkshay Belsare if (!ps_gpio->vbase) {
230*d3c37848SAkshay Belsare EMSG("AMD PS GPIO initialization Failed");
231*d3c37848SAkshay Belsare free(ps_gpio);
232*d3c37848SAkshay Belsare return TEE_ERROR_GENERIC;
233*d3c37848SAkshay Belsare }
234*d3c37848SAkshay Belsare
235*d3c37848SAkshay Belsare res = gpio_register_provider(fdt, node, amd_gpio_get_dt, ps_gpio);
236*d3c37848SAkshay Belsare if (res) {
237*d3c37848SAkshay Belsare EMSG("Failed to register PS GPIO Provider");
238*d3c37848SAkshay Belsare /* Ignoring return value */
239*d3c37848SAkshay Belsare core_mmu_remove_mapping(MEM_AREA_IO_SEC,
240*d3c37848SAkshay Belsare (void *)ps_gpio->vbase, len);
241*d3c37848SAkshay Belsare free(ps_gpio);
242*d3c37848SAkshay Belsare return res;
243*d3c37848SAkshay Belsare }
244*d3c37848SAkshay Belsare
245*d3c37848SAkshay Belsare DMSG("AMD PS GPIO initialized");
246*d3c37848SAkshay Belsare
247*d3c37848SAkshay Belsare return TEE_SUCCESS;
248*d3c37848SAkshay Belsare }
249*d3c37848SAkshay Belsare
250*d3c37848SAkshay Belsare GPIO_DT_DECLARE(amd_ps_gpio, "xlnx,versal-gpio-1.0", amd_ps_gpio_probe);
251