1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <drivers/pl061_gpio.h> 8 #include <io.h> 9 #include <keep.h> 10 #include <trace.h> 11 #include <util.h> 12 13 #ifndef PLAT_PL061_MAX_GPIOS 14 # define PLAT_PL061_MAX_GPIOS 32 15 #endif /* PLAT_PL061_MAX_GPIOS */ 16 17 #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \ 18 (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061) 19 20 #define GPIOS_PER_PL061 8 21 22 /* gpio register offsets */ 23 #define GPIODIR 0x400 24 #define GPIOIS 0x404 25 #define GPIOIBE 0x408 26 #define GPIOIEV 0x40C 27 #define GPIOIE 0x410 28 #define GPIORIS 0x414 29 #define GPIOMIS 0x418 30 #define GPIOIC 0x41C 31 #define GPIOAFSEL 0x420 32 33 /* gpio register masks */ 34 #define GPIOIE_ENABLED SHIFT_U32(1, 0) 35 #define GPIOIE_MASKED SHIFT_U32(0, 0) 36 #define GPIOAFSEL_HW SHIFT_U32(1, 0) 37 #define GPIOAFSEL_SW SHIFT_U32(0, 0) 38 #define GPIODIR_OUT SHIFT_U32(1, 0) 39 #define GPIODIR_IN SHIFT_U32(0, 0) 40 41 static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES]; 42 43 static enum gpio_dir pl061_get_direction(unsigned int gpio_pin) 44 { 45 vaddr_t base_addr; 46 uint8_t data; 47 unsigned int offset; 48 49 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 50 51 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 52 offset = gpio_pin % GPIOS_PER_PL061; 53 data = io_read8(base_addr + GPIODIR); 54 if (data & BIT(offset)) 55 return GPIO_DIR_OUT; 56 return GPIO_DIR_IN; 57 } 58 59 static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction) 60 { 61 vaddr_t base_addr; 62 unsigned int offset; 63 64 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 65 66 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 67 offset = gpio_pin % GPIOS_PER_PL061; 68 if (direction == GPIO_DIR_OUT) 69 io_setbits8(base_addr + GPIODIR, BIT(offset)); 70 else 71 io_clrbits8(base_addr + GPIODIR, BIT(offset)); 72 } 73 74 /* 75 * The offset of GPIODATA register is 0. 76 * The values read from GPIODATA are determined for each bit, by the mask bit 77 * derived from the address used to access the data register, PADDR[9:2]. 78 * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA 79 * to be read, and bits that are 0 in the address mask cause the corresponding 80 * bits in GPIODATA to be read as 0, regardless of their value. 81 */ 82 static enum gpio_level pl061_get_value(unsigned int gpio_pin) 83 { 84 vaddr_t base_addr; 85 unsigned int offset; 86 87 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 88 89 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 90 offset = gpio_pin % GPIOS_PER_PL061; 91 if (io_read8(base_addr + BIT(offset + 2))) 92 return GPIO_LEVEL_HIGH; 93 return GPIO_LEVEL_LOW; 94 } 95 96 /* 97 * In order to write GPIODATA, the corresponding bits in the mask, resulting 98 * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values 99 * remain unchanged by the write. 100 */ 101 static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value) 102 { 103 vaddr_t base_addr; 104 unsigned int offset; 105 106 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 107 108 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 109 offset = gpio_pin % GPIOS_PER_PL061; 110 if (value == GPIO_LEVEL_HIGH) 111 io_write8(base_addr + BIT(offset + 2), BIT(offset)); 112 else 113 io_write8(base_addr + BIT(offset + 2), 0); 114 } 115 116 static enum gpio_interrupt pl061_get_interrupt(unsigned int gpio_pin) 117 { 118 vaddr_t base_addr; 119 uint8_t data; 120 unsigned int offset; 121 122 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 123 124 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 125 offset = gpio_pin % GPIOS_PER_PL061; 126 data = io_read8(base_addr + GPIOIE); 127 if (data & BIT(offset)) 128 return GPIO_INTERRUPT_ENABLE; 129 return GPIO_INTERRUPT_DISABLE; 130 } 131 132 static void pl061_set_interrupt(unsigned int gpio_pin, 133 enum gpio_interrupt ena_dis) 134 { 135 vaddr_t base_addr; 136 unsigned int offset; 137 138 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 139 140 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 141 offset = gpio_pin % GPIOS_PER_PL061; 142 if (ena_dis == GPIO_INTERRUPT_ENABLE) 143 io_setbits8(base_addr + GPIOIE, BIT(offset)); 144 else 145 io_clrbits8(base_addr + GPIOIE, BIT(offset)); 146 } 147 148 /* 149 * Register the PL061 GPIO controller with a base address and the offset 150 * of start pin in this GPIO controller. 151 * This function is called after pl061_init(). 152 */ 153 void pl061_register(vaddr_t base_addr, unsigned int gpio_dev) 154 { 155 assert(gpio_dev < MAX_GPIO_DEVICES); 156 157 pl061_reg_base[gpio_dev] = base_addr; 158 } 159 160 static const struct gpio_ops pl061_ops = { 161 .get_direction = pl061_get_direction, 162 .set_direction = pl061_set_direction, 163 .get_value = pl061_get_value, 164 .set_value = pl061_set_value, 165 .get_interrupt = pl061_get_interrupt, 166 .set_interrupt = pl061_set_interrupt, 167 }; 168 KEEP_PAGER(pl061_ops); 169 170 /* 171 * Initialize PL061 GPIO controller 172 */ 173 void pl061_init(struct pl061_data *pd) 174 { 175 COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0); 176 177 assert(pd); 178 pd->chip.ops = &pl061_ops; 179 } 180 181 enum pl061_mode_control pl061_get_mode_control(unsigned int gpio_pin) 182 { 183 vaddr_t base_addr; 184 uint8_t data; 185 unsigned int offset; 186 187 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 188 189 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 190 offset = gpio_pin % GPIOS_PER_PL061; 191 data = io_read8(base_addr + GPIOAFSEL); 192 if (data & BIT(offset)) 193 return PL061_MC_HW; 194 return PL061_MC_SW; 195 } 196 197 void pl061_set_mode_control(unsigned int gpio_pin, 198 enum pl061_mode_control hw_sw) 199 { 200 vaddr_t base_addr; 201 unsigned int offset; 202 203 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 204 205 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 206 offset = gpio_pin % GPIOS_PER_PL061; 207 if (hw_sw == PL061_MC_HW) 208 io_setbits8(base_addr + GPIOAFSEL, BIT(offset)); 209 else 210 io_clrbits8(base_addr + GPIOAFSEL, BIT(offset)); 211 } 212