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 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 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 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 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 77*fc5d98e8SManish Tomar static void iproc_gpio_set(struct gpio_chip *chip __unused, unsigned int gpio, 78*fc5d98e8SManish 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 86*fc5d98e8SManish Tomar static enum gpio_level iproc_gpio_get(struct gpio_chip *chip __unused, 87*fc5d98e8SManish 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 101*fc5d98e8SManish Tomar static void iproc_gpio_set_dir(struct gpio_chip *chip __unused, 102*fc5d98e8SManish 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 110*fc5d98e8SManish Tomar static enum gpio_dir iproc_gpio_get_dir(struct gpio_chip *chip __unused, 111*fc5d98e8SManish 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 125*fc5d98e8SManish Tomar static enum gpio_interrupt iproc_gpio_get_itr(struct gpio_chip *chip __unused, 126*fc5d98e8SManish 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 140*fc5d98e8SManish Tomar static void iproc_gpio_set_itr(struct gpio_chip *chip __unused, 141*fc5d98e8SManish 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 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); 1639246c1f6SSheetal Tigadoli vaddr_t baseaddr = (vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE, 1649246c1f6SSheetal Tigadoli MEM_AREA_IO_SEC); 1659246c1f6SSheetal Tigadoli 1669246c1f6SSheetal Tigadoli regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin); 1679246c1f6SSheetal Tigadoli 1689246c1f6SSheetal Tigadoli io_clrbits32(regaddr, BIT(shift)); 1699246c1f6SSheetal Tigadoli } 1709246c1f6SSheetal Tigadoli 171e61fc00fSSandeep Tripathy static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr, 172e61fc00fSSandeep Tripathy unsigned int gpio_base, unsigned int ngpios) 173e61fc00fSSandeep Tripathy { 174e61fc00fSSandeep Tripathy assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios)); 175e61fc00fSSandeep Tripathy 176e61fc00fSSandeep Tripathy gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC); 177e61fc00fSSandeep Tripathy gc->chip.ops = &bcm_gpio_ops; 178e61fc00fSSandeep Tripathy gc->gpio_base = gpio_base; 179e61fc00fSSandeep Tripathy gc->ngpios = ngpios; 180e61fc00fSSandeep Tripathy 181e61fc00fSSandeep Tripathy SLIST_INSERT_HEAD(&gclist, gc, link); 182e61fc00fSSandeep Tripathy 183e61fc00fSSandeep Tripathy DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios); 184e61fc00fSSandeep Tripathy } 185e61fc00fSSandeep Tripathy 186e61fc00fSSandeep Tripathy static TEE_Result bcm_gpio_init(void) 187e61fc00fSSandeep Tripathy { 188e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = NULL; 189e61fc00fSSandeep Tripathy 190e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE0 191e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc)); 192e61fc00fSSandeep Tripathy if (gc == NULL) 193e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY; 194e61fc00fSSandeep Tripathy 195e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0); 196e61fc00fSSandeep Tripathy #endif 197e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE1 198e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc)); 199e61fc00fSSandeep Tripathy if (gc == NULL) 200e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY; 201e61fc00fSSandeep Tripathy 202e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1); 203e61fc00fSSandeep Tripathy #endif 204e61fc00fSSandeep Tripathy return TEE_SUCCESS; 205e61fc00fSSandeep Tripathy } 206e61fc00fSSandeep Tripathy driver_init(bcm_gpio_init); 207