1cd495a5aSJorge Ramirez-Ortiz // SPDX-License-Identifier: MIT
2cd495a5aSJorge Ramirez-Ortiz /*
3cd495a5aSJorge Ramirez-Ortiz * Copyright (C) 2002 - 2021 Xilinx, Inc. All rights reserved.
4cd495a5aSJorge Ramirez-Ortiz * Copyright (c) 2022 Foundries.io Ltd. (jorge@foundries.io)
5cd495a5aSJorge Ramirez-Ortiz */
6cd495a5aSJorge Ramirez-Ortiz #include <arm.h>
7cd495a5aSJorge Ramirez-Ortiz #include <assert.h>
8cd495a5aSJorge Ramirez-Ortiz #include <crypto/crypto.h>
9cd495a5aSJorge Ramirez-Ortiz #include <initcall.h>
10cd495a5aSJorge Ramirez-Ortiz #include <io.h>
11cd495a5aSJorge Ramirez-Ortiz #include <kernel/panic.h>
12cd495a5aSJorge Ramirez-Ortiz #include <mm/core_mmu.h>
13cd495a5aSJorge Ramirez-Ortiz #include <platform_config.h>
14cd495a5aSJorge Ramirez-Ortiz #include <stdlib.h>
15cd495a5aSJorge Ramirez-Ortiz #include <string.h>
16cd495a5aSJorge Ramirez-Ortiz #include <tee/tee_cryp_utl.h>
17cd495a5aSJorge Ramirez-Ortiz
18cd495a5aSJorge Ramirez-Ortiz #include "drivers/versal_gpio.h"
19cd495a5aSJorge Ramirez-Ortiz
20cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_LEN 0x10000
21cd495a5aSJorge Ramirez-Ortiz
22cd495a5aSJorge Ramirez-Ortiz #define DATA_LSW_OFFSET(__bank) (0x000 + 0x08 * (__bank))
23cd495a5aSJorge Ramirez-Ortiz #define DATA_MSW_OFFSET(__bank) (0x004 + 0x08 * (__bank))
24cd495a5aSJorge Ramirez-Ortiz #define DATA_RO_OFFSET(__bank) (0x060 + 0x04 * (__bank))
25cd495a5aSJorge Ramirez-Ortiz #define DIRM_OFFSET(__bank) (0x204 + 0x40 * (__bank))
26cd495a5aSJorge Ramirez-Ortiz #define OUTEN_OFFSET(__bank) (0x208 + 0x40 * (__bank))
27cd495a5aSJorge Ramirez-Ortiz
28cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_MID_PIN 16
29cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_UPPER_MASK 0xFFFF0000
30cd495a5aSJorge Ramirez-Ortiz
31cd495a5aSJorge Ramirez-Ortiz /* Max pins in the PMC_GPIO devices
32cd495a5aSJorge Ramirez-Ortiz * 00 - 025, Bank 0
33cd495a5aSJorge Ramirez-Ortiz * 26 - 051, Bank 1
34cd495a5aSJorge Ramirez-Ortiz * 52 - 083, Bank 3
35cd495a5aSJorge Ramirez-Ortiz * 84 - 115, Bank 4
36cd495a5aSJorge Ramirez-Ortiz */
37cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PMC_BASE 0xf1020000
38cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PMC_NR_GPIOS 116
39cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PMC_MAX_BANK 5
40cd495a5aSJorge Ramirez-Ortiz
41cd495a5aSJorge Ramirez-Ortiz static const struct versal_gpio_platform_data versal_gpio_pmc_def = {
42cd495a5aSJorge Ramirez-Ortiz .max_bank = VERSAL_GPIO_PMC_MAX_BANK,
43cd495a5aSJorge Ramirez-Ortiz .ngpio = VERSAL_GPIO_PMC_NR_GPIOS,
44cd495a5aSJorge Ramirez-Ortiz .label = "versal_pmc_gpio",
45cd495a5aSJorge Ramirez-Ortiz .bank_min[0] = 0,
46cd495a5aSJorge Ramirez-Ortiz .bank_max[0] = 25,
47cd495a5aSJorge Ramirez-Ortiz .bank_min[1] = 26,
48cd495a5aSJorge Ramirez-Ortiz .bank_max[1] = 51,
49cd495a5aSJorge Ramirez-Ortiz .bank_min[3] = 52,
50cd495a5aSJorge Ramirez-Ortiz .bank_max[3] = 83,
51cd495a5aSJorge Ramirez-Ortiz .bank_min[4] = 84,
52cd495a5aSJorge Ramirez-Ortiz .bank_max[4] = 115,
53cd495a5aSJorge Ramirez-Ortiz };
54cd495a5aSJorge Ramirez-Ortiz
55cd495a5aSJorge Ramirez-Ortiz /* Max pins in the PS_GPIO devices
56cd495a5aSJorge Ramirez-Ortiz * 00 - 25, Bank 0
57cd495a5aSJorge Ramirez-Ortiz * 26 - 57, Bank 3
58cd495a5aSJorge Ramirez-Ortiz */
59cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PS_BASE 0xff0b0000
60cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PS_NR_GPIOS 58
61cd495a5aSJorge Ramirez-Ortiz #define VERSAL_GPIO_PS_MAX_BANK 4
62cd495a5aSJorge Ramirez-Ortiz
63cd495a5aSJorge Ramirez-Ortiz static const struct versal_gpio_platform_data versal_gpio_ps_def = {
64cd495a5aSJorge Ramirez-Ortiz .max_bank = VERSAL_GPIO_PS_MAX_BANK,
65cd495a5aSJorge Ramirez-Ortiz .ngpio = VERSAL_GPIO_PS_NR_GPIOS,
66cd495a5aSJorge Ramirez-Ortiz .label = "versal_ps_gpio",
67cd495a5aSJorge Ramirez-Ortiz .bank_min[0] = 0,
68cd495a5aSJorge Ramirez-Ortiz .bank_max[0] = 25,
69cd495a5aSJorge Ramirez-Ortiz .bank_min[3] = 26,
70cd495a5aSJorge Ramirez-Ortiz .bank_max[3] = 57,
71cd495a5aSJorge Ramirez-Ortiz };
72cd495a5aSJorge Ramirez-Ortiz
versal_gpio_get_pin(struct versal_gpio_chip * chip,uint32_t gpio,uint32_t * bank,uint32_t * pin)73cd495a5aSJorge Ramirez-Ortiz static void versal_gpio_get_pin(struct versal_gpio_chip *chip, uint32_t gpio,
74cd495a5aSJorge Ramirez-Ortiz uint32_t *bank, uint32_t *pin)
75cd495a5aSJorge Ramirez-Ortiz {
76cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_platdata *platdata = &chip->plat;
77cd495a5aSJorge Ramirez-Ortiz uint32_t bnk = 0;
78cd495a5aSJorge Ramirez-Ortiz
79cd495a5aSJorge Ramirez-Ortiz assert(gpio < platdata->p_data->ngpio);
80cd495a5aSJorge Ramirez-Ortiz
81cd495a5aSJorge Ramirez-Ortiz for (bnk = 0; bnk < platdata->p_data->max_bank; bnk++) {
82cd495a5aSJorge Ramirez-Ortiz if (gpio < platdata->p_data->bank_min[bnk])
83cd495a5aSJorge Ramirez-Ortiz continue;
84cd495a5aSJorge Ramirez-Ortiz
85cd495a5aSJorge Ramirez-Ortiz if (gpio > platdata->p_data->bank_max[bnk])
86cd495a5aSJorge Ramirez-Ortiz continue;
87cd495a5aSJorge Ramirez-Ortiz
88cd495a5aSJorge Ramirez-Ortiz *bank = bnk;
89cd495a5aSJorge Ramirez-Ortiz *pin = gpio - platdata->p_data->bank_min[bnk];
90cd495a5aSJorge Ramirez-Ortiz
91cd495a5aSJorge Ramirez-Ortiz return;
92cd495a5aSJorge Ramirez-Ortiz }
93cd495a5aSJorge Ramirez-Ortiz
94cd495a5aSJorge Ramirez-Ortiz EMSG("GPIO_%d not found", gpio);
95cd495a5aSJorge Ramirez-Ortiz panic();
96cd495a5aSJorge Ramirez-Ortiz }
97cd495a5aSJorge Ramirez-Ortiz
versal_gpio_get_value(struct versal_gpio_chip * chip,uint32_t gpio)98*a080490cSClément Léger static enum gpio_level versal_gpio_get_value(struct versal_gpio_chip *chip,
99cd495a5aSJorge Ramirez-Ortiz uint32_t gpio)
100cd495a5aSJorge Ramirez-Ortiz {
101cd495a5aSJorge Ramirez-Ortiz uint32_t bank = 0;
102cd495a5aSJorge Ramirez-Ortiz uint32_t pin = 0;
103cd495a5aSJorge Ramirez-Ortiz
104cd495a5aSJorge Ramirez-Ortiz versal_gpio_get_pin(chip, gpio, &bank, &pin);
105cd495a5aSJorge Ramirez-Ortiz
106cd495a5aSJorge Ramirez-Ortiz return (io_read32(chip->base + DATA_RO_OFFSET(bank)) >> pin) & 1;
107cd495a5aSJorge Ramirez-Ortiz }
108cd495a5aSJorge Ramirez-Ortiz
versal_gpio_set_value(struct versal_gpio_chip * chip,uint32_t gpio,enum gpio_level val)109*a080490cSClément Léger static void versal_gpio_set_value(struct versal_gpio_chip *chip, uint32_t gpio,
110cd495a5aSJorge Ramirez-Ortiz enum gpio_level val)
111cd495a5aSJorge Ramirez-Ortiz {
112cd495a5aSJorge Ramirez-Ortiz uint32_t bank = 0;
113cd495a5aSJorge Ramirez-Ortiz uint32_t off = 0;
114cd495a5aSJorge Ramirez-Ortiz uint32_t pin = 0;
115cd495a5aSJorge Ramirez-Ortiz
116cd495a5aSJorge Ramirez-Ortiz versal_gpio_get_pin(chip, gpio, &bank, &pin);
117cd495a5aSJorge Ramirez-Ortiz
118cd495a5aSJorge Ramirez-Ortiz if (bank >= VERSAL_GPIO_MID_PIN) {
119cd495a5aSJorge Ramirez-Ortiz bank -= VERSAL_GPIO_MID_PIN;
120cd495a5aSJorge Ramirez-Ortiz off = DATA_MSW_OFFSET(bank);
121cd495a5aSJorge Ramirez-Ortiz } else {
122cd495a5aSJorge Ramirez-Ortiz off = DATA_LSW_OFFSET(bank);
123cd495a5aSJorge Ramirez-Ortiz }
124cd495a5aSJorge Ramirez-Ortiz
125cd495a5aSJorge Ramirez-Ortiz /*
126cd495a5aSJorge Ramirez-Ortiz * get the 32 bit value to be written to the mask/data register where
127cd495a5aSJorge Ramirez-Ortiz * the upper 16 bits is the mask and lower 16 bits is the data
128cd495a5aSJorge Ramirez-Ortiz */
129cd495a5aSJorge Ramirez-Ortiz val = !!val;
130cd495a5aSJorge Ramirez-Ortiz val = ~BIT32(pin + VERSAL_GPIO_MID_PIN) &
131cd495a5aSJorge Ramirez-Ortiz (SHIFT_U32(val, pin) | VERSAL_GPIO_UPPER_MASK);
132cd495a5aSJorge Ramirez-Ortiz
133cd495a5aSJorge Ramirez-Ortiz io_write32(chip->base + off, val);
134cd495a5aSJorge Ramirez-Ortiz }
135cd495a5aSJorge Ramirez-Ortiz
versal_gpio_set_direction(struct versal_gpio_chip * chip,uint32_t gpio,enum gpio_dir direction)136*a080490cSClément Léger static void versal_gpio_set_direction(struct versal_gpio_chip *chip,
137*a080490cSClément Léger uint32_t gpio, enum gpio_dir direction)
138cd495a5aSJorge Ramirez-Ortiz {
139cd495a5aSJorge Ramirez-Ortiz uint32_t bank = 0;
140cd495a5aSJorge Ramirez-Ortiz uint32_t reg = 0;
141cd495a5aSJorge Ramirez-Ortiz uint32_t pin = 0;
142cd495a5aSJorge Ramirez-Ortiz
143cd495a5aSJorge Ramirez-Ortiz versal_gpio_get_pin(chip, gpio, &bank, &pin);
144cd495a5aSJorge Ramirez-Ortiz
145cd495a5aSJorge Ramirez-Ortiz if (direction == GPIO_DIR_OUT) {
146cd495a5aSJorge Ramirez-Ortiz /* set the GPIO pin as output */
147cd495a5aSJorge Ramirez-Ortiz reg = io_read32(chip->base + DIRM_OFFSET(bank));
148cd495a5aSJorge Ramirez-Ortiz reg |= BIT(pin);
149cd495a5aSJorge Ramirez-Ortiz io_write32(chip->base + DIRM_OFFSET(bank), reg);
150cd495a5aSJorge Ramirez-Ortiz
151cd495a5aSJorge Ramirez-Ortiz /* configure the output enable reg for the pin */
152cd495a5aSJorge Ramirez-Ortiz reg = io_read32(chip->base + OUTEN_OFFSET(bank));
153cd495a5aSJorge Ramirez-Ortiz
154cd495a5aSJorge Ramirez-Ortiz reg |= BIT(pin);
155cd495a5aSJorge Ramirez-Ortiz io_write32(chip->base + OUTEN_OFFSET(bank), reg);
156cd495a5aSJorge Ramirez-Ortiz
157cd495a5aSJorge Ramirez-Ortiz /* set the state of the pin */
158*a080490cSClément Léger versal_gpio_set_value(chip, gpio, GPIO_LEVEL_LOW);
159cd495a5aSJorge Ramirez-Ortiz } else {
160cd495a5aSJorge Ramirez-Ortiz /* bnk 0 pins 7 and 8 cannot be used as inputs */
161cd495a5aSJorge Ramirez-Ortiz assert(!(bank == 0 && (pin == 7 || pin == 8)));
162cd495a5aSJorge Ramirez-Ortiz
163cd495a5aSJorge Ramirez-Ortiz reg = io_read32(chip->base + DIRM_OFFSET(bank));
164cd495a5aSJorge Ramirez-Ortiz reg &= ~BIT(pin);
165cd495a5aSJorge Ramirez-Ortiz io_write32(chip->base + DIRM_OFFSET(bank), reg);
166cd495a5aSJorge Ramirez-Ortiz }
167cd495a5aSJorge Ramirez-Ortiz }
168cd495a5aSJorge Ramirez-Ortiz
versal_gpio_get_direction(struct versal_gpio_chip * chip,uint32_t gpio)169*a080490cSClément Léger static enum gpio_dir versal_gpio_get_direction(struct versal_gpio_chip *chip,
170cd495a5aSJorge Ramirez-Ortiz uint32_t gpio)
171cd495a5aSJorge Ramirez-Ortiz {
172cd495a5aSJorge Ramirez-Ortiz uint32_t pin = 0;
173cd495a5aSJorge Ramirez-Ortiz uint32_t bank = 0;
174cd495a5aSJorge Ramirez-Ortiz
175cd495a5aSJorge Ramirez-Ortiz versal_gpio_get_pin(chip, gpio, &bank, &pin);
176cd495a5aSJorge Ramirez-Ortiz
177cd495a5aSJorge Ramirez-Ortiz if (io_read32(chip->base + DIRM_OFFSET(bank)) & BIT(pin))
178cd495a5aSJorge Ramirez-Ortiz return GPIO_DIR_OUT;
179cd495a5aSJorge Ramirez-Ortiz
180cd495a5aSJorge Ramirez-Ortiz return GPIO_DIR_IN;
181cd495a5aSJorge Ramirez-Ortiz }
182cd495a5aSJorge Ramirez-Ortiz
do_get_value(struct gpio_chip * chip,uint32_t gpio)183cd495a5aSJorge Ramirez-Ortiz static enum gpio_level do_get_value(struct gpio_chip *chip, uint32_t gpio)
184cd495a5aSJorge Ramirez-Ortiz {
185cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip *p = container_of(chip,
186cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip, chip);
187*a080490cSClément Léger return versal_gpio_get_value(p, gpio);
188cd495a5aSJorge Ramirez-Ortiz }
189cd495a5aSJorge Ramirez-Ortiz
do_set_value(struct gpio_chip * chip,uint32_t gpio,enum gpio_level val)190cd495a5aSJorge Ramirez-Ortiz static void do_set_value(struct gpio_chip *chip, uint32_t gpio,
191cd495a5aSJorge Ramirez-Ortiz enum gpio_level val)
192cd495a5aSJorge Ramirez-Ortiz {
193cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip *p = container_of(chip,
194cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip, chip);
195*a080490cSClément Léger return versal_gpio_set_value(p, gpio, val);
196cd495a5aSJorge Ramirez-Ortiz }
197cd495a5aSJorge Ramirez-Ortiz
do_set_dir(struct gpio_chip * chip,uint32_t gpio,enum gpio_dir direction)198cd495a5aSJorge Ramirez-Ortiz static void do_set_dir(struct gpio_chip *chip, uint32_t gpio,
199cd495a5aSJorge Ramirez-Ortiz enum gpio_dir direction)
200cd495a5aSJorge Ramirez-Ortiz {
201cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip *p = container_of(chip,
202cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip, chip);
203*a080490cSClément Léger return versal_gpio_set_direction(p, gpio, direction);
204cd495a5aSJorge Ramirez-Ortiz }
205cd495a5aSJorge Ramirez-Ortiz
do_get_dir(struct gpio_chip * chip,uint32_t gpio)206cd495a5aSJorge Ramirez-Ortiz static enum gpio_dir do_get_dir(struct gpio_chip *chip, uint32_t gpio)
207cd495a5aSJorge Ramirez-Ortiz {
208cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip *p = container_of(chip,
209cd495a5aSJorge Ramirez-Ortiz struct versal_gpio_chip, chip);
210*a080490cSClément Léger return versal_gpio_get_direction(p, gpio);
211cd495a5aSJorge Ramirez-Ortiz }
212cd495a5aSJorge Ramirez-Ortiz
213cd495a5aSJorge Ramirez-Ortiz static const struct gpio_ops versal_gpio_ops = {
214cd495a5aSJorge Ramirez-Ortiz .get_direction = do_get_dir,
215cd495a5aSJorge Ramirez-Ortiz .set_direction = do_set_dir,
216cd495a5aSJorge Ramirez-Ortiz .get_value = do_get_value,
217cd495a5aSJorge Ramirez-Ortiz .set_value = do_set_value,
218cd495a5aSJorge Ramirez-Ortiz .get_interrupt = NULL,
219cd495a5aSJorge Ramirez-Ortiz .set_interrupt = NULL,
220cd495a5aSJorge Ramirez-Ortiz };
221cd495a5aSJorge Ramirez-Ortiz
versal_gpio_pmc_init(struct versal_gpio_chip * chip)222cd495a5aSJorge Ramirez-Ortiz TEE_Result versal_gpio_pmc_init(struct versal_gpio_chip *chip)
223cd495a5aSJorge Ramirez-Ortiz {
224cd495a5aSJorge Ramirez-Ortiz if (chip->base)
225cd495a5aSJorge Ramirez-Ortiz return TEE_SUCCESS;
226cd495a5aSJorge Ramirez-Ortiz
227cd495a5aSJorge Ramirez-Ortiz chip->plat.p_data = &versal_gpio_pmc_def;
228cd495a5aSJorge Ramirez-Ortiz chip->plat.base = VERSAL_GPIO_PMC_BASE;
229cd495a5aSJorge Ramirez-Ortiz chip->chip.ops = &versal_gpio_ops;
230cd495a5aSJorge Ramirez-Ortiz
231cd495a5aSJorge Ramirez-Ortiz chip->base = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC,
232cd495a5aSJorge Ramirez-Ortiz VERSAL_GPIO_PMC_BASE,
233cd495a5aSJorge Ramirez-Ortiz VERSAL_GPIO_LEN);
234cd495a5aSJorge Ramirez-Ortiz if (!chip->base) {
235cd495a5aSJorge Ramirez-Ortiz EMSG("Failed to map gpio");
236cd495a5aSJorge Ramirez-Ortiz chip->chip.ops = NULL;
237cd495a5aSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
238cd495a5aSJorge Ramirez-Ortiz }
239cd495a5aSJorge Ramirez-Ortiz
240cd495a5aSJorge Ramirez-Ortiz return TEE_SUCCESS;
241cd495a5aSJorge Ramirez-Ortiz }
242cd495a5aSJorge Ramirez-Ortiz
versal_gpio_ps_init(struct versal_gpio_chip * chip)243cd495a5aSJorge Ramirez-Ortiz TEE_Result versal_gpio_ps_init(struct versal_gpio_chip *chip)
244cd495a5aSJorge Ramirez-Ortiz {
245cd495a5aSJorge Ramirez-Ortiz if (chip->base)
246cd495a5aSJorge Ramirez-Ortiz return TEE_SUCCESS;
247cd495a5aSJorge Ramirez-Ortiz
248cd495a5aSJorge Ramirez-Ortiz chip->plat.p_data = &versal_gpio_ps_def;
249cd495a5aSJorge Ramirez-Ortiz chip->plat.base = VERSAL_GPIO_PS_BASE;
250cd495a5aSJorge Ramirez-Ortiz chip->chip.ops = &versal_gpio_ops;
251cd495a5aSJorge Ramirez-Ortiz
252cd495a5aSJorge Ramirez-Ortiz chip->base = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC,
253cd495a5aSJorge Ramirez-Ortiz VERSAL_GPIO_PS_BASE,
254cd495a5aSJorge Ramirez-Ortiz VERSAL_GPIO_LEN);
255cd495a5aSJorge Ramirez-Ortiz if (!chip->base) {
256cd495a5aSJorge Ramirez-Ortiz EMSG("Failed to map gpio");
257cd495a5aSJorge Ramirez-Ortiz chip->chip.ops = NULL;
258cd495a5aSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
259cd495a5aSJorge Ramirez-Ortiz }
260cd495a5aSJorge Ramirez-Ortiz
261cd495a5aSJorge Ramirez-Ortiz return TEE_SUCCESS;
262cd495a5aSJorge Ramirez-Ortiz }
263