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