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 77e61fc00fSSandeep Tripathy static void iproc_gpio_set(unsigned int gpio, enum gpio_level val) 78e61fc00fSSandeep Tripathy { 79e61fc00fSSandeep Tripathy if (val == GPIO_LEVEL_HIGH) 80e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio); 81e61fc00fSSandeep Tripathy else 82e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio); 83e61fc00fSSandeep Tripathy } 84e61fc00fSSandeep Tripathy 85e61fc00fSSandeep Tripathy static enum gpio_level iproc_gpio_get(unsigned int gpio) 86e61fc00fSSandeep Tripathy { 87e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_DATA_IN_OFFSET); 88e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio); 89e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio); 90e61fc00fSSandeep Tripathy 91e61fc00fSSandeep Tripathy assert(gc); 92e61fc00fSSandeep Tripathy 93e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift)) 94e61fc00fSSandeep Tripathy return GPIO_LEVEL_HIGH; 95e61fc00fSSandeep Tripathy else 96e61fc00fSSandeep Tripathy return GPIO_LEVEL_LOW; 97e61fc00fSSandeep Tripathy } 98e61fc00fSSandeep Tripathy 99e61fc00fSSandeep Tripathy static void iproc_gpio_set_dir(unsigned int gpio, enum gpio_dir dir) 100e61fc00fSSandeep Tripathy { 101e61fc00fSSandeep Tripathy if (dir == GPIO_DIR_OUT) 102e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio); 103e61fc00fSSandeep Tripathy else 104e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio); 105e61fc00fSSandeep Tripathy } 106e61fc00fSSandeep Tripathy 107e61fc00fSSandeep Tripathy static enum gpio_dir iproc_gpio_get_dir(unsigned int gpio) 108e61fc00fSSandeep Tripathy { 109e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET); 110e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio); 111e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio); 112e61fc00fSSandeep Tripathy 113e61fc00fSSandeep Tripathy assert(gc); 114e61fc00fSSandeep Tripathy 115e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift)) 116e61fc00fSSandeep Tripathy return GPIO_DIR_OUT; 117e61fc00fSSandeep Tripathy else 118e61fc00fSSandeep Tripathy return GPIO_DIR_IN; 119e61fc00fSSandeep Tripathy } 120e61fc00fSSandeep Tripathy 121e61fc00fSSandeep Tripathy static enum gpio_interrupt iproc_gpio_get_itr(unsigned int gpio) 122e61fc00fSSandeep Tripathy { 123e61fc00fSSandeep Tripathy unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_INT_MSK_OFFSET); 124e61fc00fSSandeep Tripathy unsigned int shift = IPROC_GPIO_SHIFT(gpio); 125e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio); 126e61fc00fSSandeep Tripathy 127e61fc00fSSandeep Tripathy assert(gc); 128e61fc00fSSandeep Tripathy 129e61fc00fSSandeep Tripathy if (io_read32(gc->base + offset) & BIT(shift)) 130e61fc00fSSandeep Tripathy return GPIO_INTERRUPT_ENABLE; 131e61fc00fSSandeep Tripathy else 132e61fc00fSSandeep Tripathy return GPIO_INTERRUPT_DISABLE; 133e61fc00fSSandeep Tripathy } 134e61fc00fSSandeep Tripathy 135e61fc00fSSandeep Tripathy static void iproc_gpio_set_itr(unsigned int gpio, 136e61fc00fSSandeep Tripathy enum gpio_interrupt ena_dis) 137e61fc00fSSandeep Tripathy { 138e61fc00fSSandeep Tripathy if (ena_dis == GPIO_INTERRUPT_ENABLE) 139e61fc00fSSandeep Tripathy iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio); 140e61fc00fSSandeep Tripathy else 141e61fc00fSSandeep Tripathy iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio); 142e61fc00fSSandeep Tripathy } 143e61fc00fSSandeep Tripathy 144e61fc00fSSandeep Tripathy static const struct gpio_ops bcm_gpio_ops = { 145e61fc00fSSandeep Tripathy .get_direction = iproc_gpio_get_dir, 146e61fc00fSSandeep Tripathy .set_direction = iproc_gpio_set_dir, 147e61fc00fSSandeep Tripathy .get_value = iproc_gpio_get, 148e61fc00fSSandeep Tripathy .set_value = iproc_gpio_set, 149e61fc00fSSandeep Tripathy .get_interrupt = iproc_gpio_get_itr, 150e61fc00fSSandeep Tripathy .set_interrupt = iproc_gpio_set_itr, 151e61fc00fSSandeep Tripathy }; 152*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(bcm_gpio_ops); 153e61fc00fSSandeep Tripathy 1549246c1f6SSheetal Tigadoli void iproc_gpio_set_secure(int gpiopin) 1559246c1f6SSheetal Tigadoli { 1569246c1f6SSheetal Tigadoli vaddr_t regaddr = 0; 1579246c1f6SSheetal Tigadoli unsigned int shift = IPROC_GPIO_SHIFT(gpiopin); 1589246c1f6SSheetal Tigadoli vaddr_t baseaddr = (vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE, 1599246c1f6SSheetal Tigadoli MEM_AREA_IO_SEC); 1609246c1f6SSheetal Tigadoli 1619246c1f6SSheetal Tigadoli regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin); 1629246c1f6SSheetal Tigadoli 1639246c1f6SSheetal Tigadoli io_clrbits32(regaddr, BIT(shift)); 1649246c1f6SSheetal Tigadoli } 1659246c1f6SSheetal Tigadoli 166e61fc00fSSandeep Tripathy static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr, 167e61fc00fSSandeep Tripathy unsigned int gpio_base, unsigned int ngpios) 168e61fc00fSSandeep Tripathy { 169e61fc00fSSandeep Tripathy assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios)); 170e61fc00fSSandeep Tripathy 171e61fc00fSSandeep Tripathy gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC); 172e61fc00fSSandeep Tripathy gc->chip.ops = &bcm_gpio_ops; 173e61fc00fSSandeep Tripathy gc->gpio_base = gpio_base; 174e61fc00fSSandeep Tripathy gc->ngpios = ngpios; 175e61fc00fSSandeep Tripathy 176e61fc00fSSandeep Tripathy SLIST_INSERT_HEAD(&gclist, gc, link); 177e61fc00fSSandeep Tripathy 178e61fc00fSSandeep Tripathy DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios); 179e61fc00fSSandeep Tripathy } 180e61fc00fSSandeep Tripathy 181e61fc00fSSandeep Tripathy static TEE_Result bcm_gpio_init(void) 182e61fc00fSSandeep Tripathy { 183e61fc00fSSandeep Tripathy struct bcm_gpio_chip *gc = NULL; 184e61fc00fSSandeep Tripathy 185e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE0 186e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc)); 187e61fc00fSSandeep Tripathy if (gc == NULL) 188e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY; 189e61fc00fSSandeep Tripathy 190e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0); 191e61fc00fSSandeep Tripathy #endif 192e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE1 193e61fc00fSSandeep Tripathy gc = malloc(sizeof(*gc)); 194e61fc00fSSandeep Tripathy if (gc == NULL) 195e61fc00fSSandeep Tripathy return TEE_ERROR_OUT_OF_MEMORY; 196e61fc00fSSandeep Tripathy 197e61fc00fSSandeep Tripathy iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1); 198e61fc00fSSandeep Tripathy #endif 199e61fc00fSSandeep Tripathy return TEE_SUCCESS; 200e61fc00fSSandeep Tripathy } 201e61fc00fSSandeep Tripathy driver_init(bcm_gpio_init); 202