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