1e61fc00fSSandeep Tripathy // SPDX-License-Identifier: BSD-2-Clause
2e61fc00fSSandeep Tripathy /*
3e61fc00fSSandeep Tripathy * Copyright 2019 Broadcom.
4e61fc00fSSandeep Tripathy */
5e61fc00fSSandeep Tripathy #include <assert.h>
6e61fc00fSSandeep Tripathy #include <drivers/bcm_gpio.h>
7e61fc00fSSandeep Tripathy #include <initcall.h>
8e61fc00fSSandeep Tripathy #include <io.h>
9e61fc00fSSandeep Tripathy #include <mm/core_memprot.h>
10e61fc00fSSandeep Tripathy #include <platform_config.h>
11e61fc00fSSandeep Tripathy #include <trace.h>
12e61fc00fSSandeep Tripathy
13e61fc00fSSandeep Tripathy #define IPROC_GPIO_DATA_IN_OFFSET 0x00
14e61fc00fSSandeep Tripathy #define IPROC_GPIO_DATA_OUT_OFFSET 0x04
15e61fc00fSSandeep Tripathy #define IPROC_GPIO_OUT_EN_OFFSET 0x08
16e61fc00fSSandeep Tripathy #define IPROC_GPIO_INT_MSK_OFFSET 0x18
17e61fc00fSSandeep Tripathy
18e61fc00fSSandeep Tripathy #define GPIO_BANK_SIZE 0x200
19e61fc00fSSandeep Tripathy #define NGPIOS_PER_BANK 32
20e61fc00fSSandeep Tripathy #define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
21e61fc00fSSandeep Tripathy
22e61fc00fSSandeep Tripathy #define IPROC_GPIO_REG(pin, reg) ((reg) + \
23e61fc00fSSandeep Tripathy GPIO_BANK(pin) * GPIO_BANK_SIZE)
24e61fc00fSSandeep Tripathy
25e61fc00fSSandeep Tripathy #define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
26e61fc00fSSandeep Tripathy
279246c1f6SSheetal Tigadoli #define GPIO_BANK_CNT 5
289246c1f6SSheetal Tigadoli #define SEC_GPIO_SIZE 0x4
299246c1f6SSheetal Tigadoli #define IPROC_GPIO_SEC_CFG_REG(pin) \
309246c1f6SSheetal Tigadoli (((GPIO_BANK_CNT - 1) - GPIO_BANK(pin)) * SEC_GPIO_SIZE)
319246c1f6SSheetal Tigadoli
32e61fc00fSSandeep Tripathy static SLIST_HEAD(, bcm_gpio_chip) gclist = SLIST_HEAD_INITIALIZER(gclist);
33e61fc00fSSandeep Tripathy
bcm_gpio_pin_to_chip(unsigned int pin)34e61fc00fSSandeep Tripathy struct bcm_gpio_chip *bcm_gpio_pin_to_chip(unsigned int pin)
35e61fc00fSSandeep Tripathy {
36e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = NULL;
37e61fc00fSSandeep Tripathy
38e61fc00fSSandeep Tripathy SLIST_FOREACH(gc, &gclist, link)
39e61fc00fSSandeep Tripathy if ((pin >= gc->gpio_base) &&
40e61fc00fSSandeep Tripathy (pin < (gc->gpio_base + gc->ngpios)))
41e61fc00fSSandeep Tripathy return gc;
42e61fc00fSSandeep Tripathy return NULL;
43e61fc00fSSandeep Tripathy }
44e61fc00fSSandeep Tripathy
gpio_is_range_overlap(unsigned int start,unsigned int end)45e61fc00fSSandeep Tripathy static bool __maybe_unused gpio_is_range_overlap(unsigned int start,
46e61fc00fSSandeep Tripathy unsigned int end)
47e61fc00fSSandeep Tripathy {
48e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = NULL;
49e61fc00fSSandeep Tripathy
50e61fc00fSSandeep Tripathy SLIST_FOREACH(gc, &gclist, link)
51e61fc00fSSandeep Tripathy if ((start < (gc->gpio_base + gc->ngpios)) &&
52e61fc00fSSandeep Tripathy (end > gc->gpio_base))
53e61fc00fSSandeep Tripathy return true;
54e61fc00fSSandeep Tripathy return false;
55e61fc00fSSandeep Tripathy }
56e61fc00fSSandeep Tripathy
iproc_set_bit(unsigned int reg,unsigned int gpio)57e61fc00fSSandeep Tripathy static void iproc_set_bit(unsigned int reg, unsigned int gpio)
58e61fc00fSSandeep Tripathy {
59e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, reg);
60e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio);
61e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
62e61fc00fSSandeep Tripathy
63e61fc00fSSandeep Tripathy assert(gc);
64e61fc00fSSandeep Tripathy io_setbits32(gc->base + offset, BIT(shift));
65e61fc00fSSandeep Tripathy }
66e61fc00fSSandeep Tripathy
iproc_clr_bit(unsigned int reg,unsigned int gpio)67e61fc00fSSandeep Tripathy static void iproc_clr_bit(unsigned int reg, unsigned int gpio)
68e61fc00fSSandeep Tripathy {
69e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, reg);
70e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio);
71e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
72e61fc00fSSandeep Tripathy
73e61fc00fSSandeep Tripathy assert(gc);
74e61fc00fSSandeep Tripathy io_clrbits32(gc->base + offset, BIT(shift));
75e61fc00fSSandeep Tripathy }
76e61fc00fSSandeep Tripathy
iproc_gpio_set(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_level val)77fc5d98e8SManish Tomar static void iproc_gpio_set(struct gpio_chip *chip __unused, unsigned int gpio,
78fc5d98e8SManish Tomar enum gpio_level val)
79e61fc00fSSandeep Tripathy {
80e61fc00fSSandeep Tripathy if (val == GPIO_LEVEL_HIGH)
81e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
82e61fc00fSSandeep Tripathy else
83e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
84e61fc00fSSandeep Tripathy }
85e61fc00fSSandeep Tripathy
iproc_gpio_get(struct gpio_chip * chip __unused,unsigned int gpio)86fc5d98e8SManish Tomar static enum gpio_level iproc_gpio_get(struct gpio_chip *chip __unused,
87fc5d98e8SManish Tomar unsigned int gpio)
88e61fc00fSSandeep Tripathy {
89e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_DATA_IN_OFFSET);
90e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio);
91e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
92e61fc00fSSandeep Tripathy
93e61fc00fSSandeep Tripathy assert(gc);
94e61fc00fSSandeep Tripathy
95e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift))
96e61fc00fSSandeep Tripathy return GPIO_LEVEL_HIGH;
97e61fc00fSSandeep Tripathy else
98e61fc00fSSandeep Tripathy return GPIO_LEVEL_LOW;
99e61fc00fSSandeep Tripathy }
100e61fc00fSSandeep Tripathy
iproc_gpio_set_dir(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_dir dir)101fc5d98e8SManish Tomar static void iproc_gpio_set_dir(struct gpio_chip *chip __unused,
102fc5d98e8SManish Tomar unsigned int gpio, enum gpio_dir dir)
103e61fc00fSSandeep Tripathy {
104e61fc00fSSandeep Tripathy if (dir == GPIO_DIR_OUT)
105e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
106e61fc00fSSandeep Tripathy else
107e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
108e61fc00fSSandeep Tripathy }
109e61fc00fSSandeep Tripathy
iproc_gpio_get_dir(struct gpio_chip * chip __unused,unsigned int gpio)110fc5d98e8SManish Tomar static enum gpio_dir iproc_gpio_get_dir(struct gpio_chip *chip __unused,
111fc5d98e8SManish Tomar unsigned int gpio)
112e61fc00fSSandeep Tripathy {
113e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
114e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio);
115e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
116e61fc00fSSandeep Tripathy
117e61fc00fSSandeep Tripathy assert(gc);
118e61fc00fSSandeep Tripathy
119e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift))
120e61fc00fSSandeep Tripathy return GPIO_DIR_OUT;
121e61fc00fSSandeep Tripathy else
122e61fc00fSSandeep Tripathy return GPIO_DIR_IN;
123e61fc00fSSandeep Tripathy }
124e61fc00fSSandeep Tripathy
iproc_gpio_get_itr(struct gpio_chip * chip __unused,unsigned int gpio)125fc5d98e8SManish Tomar static enum gpio_interrupt iproc_gpio_get_itr(struct gpio_chip *chip __unused,
126fc5d98e8SManish Tomar unsigned int gpio)
127e61fc00fSSandeep Tripathy {
128e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_INT_MSK_OFFSET);
129e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio);
130e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
131e61fc00fSSandeep Tripathy
132e61fc00fSSandeep Tripathy assert(gc);
133e61fc00fSSandeep Tripathy
134e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift))
135e61fc00fSSandeep Tripathy return GPIO_INTERRUPT_ENABLE;
136e61fc00fSSandeep Tripathy else
137e61fc00fSSandeep Tripathy return GPIO_INTERRUPT_DISABLE;
138e61fc00fSSandeep Tripathy }
139e61fc00fSSandeep Tripathy
iproc_gpio_set_itr(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_interrupt ena_dis)140fc5d98e8SManish Tomar static void iproc_gpio_set_itr(struct gpio_chip *chip __unused,
141fc5d98e8SManish Tomar unsigned int gpio, enum gpio_interrupt ena_dis)
142e61fc00fSSandeep Tripathy {
143e61fc00fSSandeep Tripathy if (ena_dis == GPIO_INTERRUPT_ENABLE)
144e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
145e61fc00fSSandeep Tripathy else
146e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
147e61fc00fSSandeep Tripathy }
148e61fc00fSSandeep Tripathy
149e61fc00fSSandeep Tripathy static const struct gpio_ops bcm_gpio_ops = {
150e61fc00fSSandeep Tripathy .get_direction = iproc_gpio_get_dir,
151e61fc00fSSandeep Tripathy .set_direction = iproc_gpio_set_dir,
152e61fc00fSSandeep Tripathy .get_value = iproc_gpio_get,
153e61fc00fSSandeep Tripathy .set_value = iproc_gpio_set,
154e61fc00fSSandeep Tripathy .get_interrupt = iproc_gpio_get_itr,
155e61fc00fSSandeep Tripathy .set_interrupt = iproc_gpio_set_itr,
156e61fc00fSSandeep Tripathy };
1573639b55fSJerome Forissier DECLARE_KEEP_PAGER(bcm_gpio_ops);
158e61fc00fSSandeep Tripathy
iproc_gpio_set_secure(int gpiopin)1599246c1f6SSheetal Tigadoli void iproc_gpio_set_secure(int gpiopin)
1609246c1f6SSheetal Tigadoli {
1619246c1f6SSheetal Tigadoli vaddr_t regaddr = 0;
1629246c1f6SSheetal Tigadoli unsigned int shift = IPROC_GPIO_SHIFT(gpiopin);
163*c2e4eb43SAnton Rybakov vaddr_t baseaddr =
164*c2e4eb43SAnton Rybakov (vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE,
165*c2e4eb43SAnton Rybakov MEM_AREA_IO_SEC,
166*c2e4eb43SAnton Rybakov IPROC_GPIO_SEC_CFG_REG(gpiopin) +
167*c2e4eb43SAnton Rybakov sizeof(uint32_t));
1689246c1f6SSheetal Tigadoli
1699246c1f6SSheetal Tigadoli regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin);
1709246c1f6SSheetal Tigadoli
1719246c1f6SSheetal Tigadoli io_clrbits32(regaddr, BIT(shift));
1729246c1f6SSheetal Tigadoli }
1739246c1f6SSheetal Tigadoli
iproc_gpio_init(struct bcm_gpio_chip * gc,unsigned int paddr,unsigned int gpio_base,unsigned int ngpios)174e61fc00fSSandeep Tripathy static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr,
175e61fc00fSSandeep Tripathy unsigned int gpio_base, unsigned int ngpios)
176e61fc00fSSandeep Tripathy {
177e61fc00fSSandeep Tripathy assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios));
178e61fc00fSSandeep Tripathy
179*c2e4eb43SAnton Rybakov gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC, 1);
180e61fc00fSSandeep Tripathy gc->chip.ops = &bcm_gpio_ops;
181e61fc00fSSandeep Tripathy gc->gpio_base = gpio_base;
182e61fc00fSSandeep Tripathy gc->ngpios = ngpios;
183e61fc00fSSandeep Tripathy
184e61fc00fSSandeep Tripathy SLIST_INSERT_HEAD(&gclist, gc, link);
185e61fc00fSSandeep Tripathy
186e61fc00fSSandeep Tripathy DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios);
187e61fc00fSSandeep Tripathy }
188e61fc00fSSandeep Tripathy
bcm_gpio_init(void)189e61fc00fSSandeep Tripathy static TEE_Result bcm_gpio_init(void)
190e61fc00fSSandeep Tripathy {
191e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = NULL;
192e61fc00fSSandeep Tripathy
193e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE0
194e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc));
195e61fc00fSSandeep Tripathy if (gc == NULL)
196e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY;
197e61fc00fSSandeep Tripathy
198e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0);
199e61fc00fSSandeep Tripathy #endif
200e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE1
201e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc));
202e61fc00fSSandeep Tripathy if (gc == NULL)
203e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY;
204e61fc00fSSandeep Tripathy
205e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1);
206e61fc00fSSandeep Tripathy #endif
207e61fc00fSSandeep Tripathy return TEE_SUCCESS;
208e61fc00fSSandeep Tripathy }
209e61fc00fSSandeep Tripathy driver_init(bcm_gpio_init);
210