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