1 /* 2 * Copyright (c) 2016, Linaro Limited 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <assert.h> 29 #include <drivers/pl061_gpio.h> 30 #include <io.h> 31 #include <trace.h> 32 #include <util.h> 33 34 #ifndef PLAT_PL061_MAX_GPIOS 35 # define PLAT_PL061_MAX_GPIOS 32 36 #endif /* PLAT_PL061_MAX_GPIOS */ 37 38 #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \ 39 (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061) 40 41 #define GPIOS_PER_PL061 8 42 43 /* gpio register offsets */ 44 #define GPIODIR 0x400 45 #define GPIOIS 0x404 46 #define GPIOIBE 0x408 47 #define GPIOIEV 0x40C 48 #define GPIOIE 0x410 49 #define GPIORIS 0x414 50 #define GPIOMIS 0x418 51 #define GPIOIC 0x41C 52 #define GPIOAFSEL 0x420 53 54 /* gpio register masks */ 55 #define GPIOIE_ENABLED SHIFT_U32(1, 0) 56 #define GPIOIE_MASKED SHIFT_U32(0, 0) 57 #define GPIOAFSEL_HW SHIFT_U32(1, 0) 58 #define GPIOAFSEL_SW SHIFT_U32(0, 0) 59 #define GPIODIR_OUT SHIFT_U32(1, 0) 60 #define GPIODIR_IN SHIFT_U32(0, 0) 61 62 static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES]; 63 64 static enum gpio_dir pl061_get_direction(unsigned int gpio_pin) 65 { 66 vaddr_t base_addr; 67 uint8_t data; 68 unsigned int offset; 69 70 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 71 72 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 73 offset = gpio_pin % GPIOS_PER_PL061; 74 data = read8(base_addr + GPIODIR); 75 if (data & BIT(offset)) 76 return GPIO_DIR_OUT; 77 return GPIO_DIR_IN; 78 } 79 80 static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction) 81 { 82 vaddr_t base_addr; 83 uint8_t data; 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 (direction == GPIO_DIR_OUT) { 91 data = read8(base_addr + GPIODIR) | BIT(offset); 92 write8(data, base_addr + GPIODIR); 93 } else { 94 data = read8(base_addr + GPIODIR) & ~BIT(offset); 95 write8(data, base_addr + GPIODIR); 96 } 97 } 98 99 /* 100 * The offset of GPIODATA register is 0. 101 * The values read from GPIODATA are determined for each bit, by the mask bit 102 * derived from the address used to access the data register, PADDR[9:2]. 103 * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA 104 * to be read, and bits that are 0 in the address mask cause the corresponding 105 * bits in GPIODATA to be read as 0, regardless of their value. 106 */ 107 static enum gpio_level pl061_get_value(unsigned int gpio_pin) 108 { 109 vaddr_t base_addr; 110 unsigned int offset; 111 112 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 113 114 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 115 offset = gpio_pin % GPIOS_PER_PL061; 116 if (read8(base_addr + BIT(offset + 2))) 117 return GPIO_LEVEL_HIGH; 118 return GPIO_LEVEL_LOW; 119 } 120 121 /* 122 * In order to write GPIODATA, the corresponding bits in the mask, resulting 123 * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values 124 * remain unchanged by the write. 125 */ 126 static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value) 127 { 128 vaddr_t base_addr; 129 unsigned int offset; 130 131 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 132 133 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 134 offset = gpio_pin % GPIOS_PER_PL061; 135 if (value == GPIO_LEVEL_HIGH) 136 write8(BIT(offset), base_addr + BIT(offset + 2)); 137 else 138 write8(0, base_addr + BIT(offset + 2)); 139 } 140 141 142 /* 143 * Register the PL061 GPIO controller with a base address and the offset 144 * of start pin in this GPIO controller. 145 * This function is called after pl061_init(). 146 */ 147 void pl061_register(vaddr_t base_addr, unsigned int gpio_dev) 148 { 149 assert(gpio_dev < MAX_GPIO_DEVICES); 150 151 pl061_reg_base[gpio_dev] = base_addr; 152 } 153 154 static const struct gpio_ops pl061_ops = { 155 .get_direction = pl061_get_direction, 156 .set_direction = pl061_set_direction, 157 .get_value = pl061_get_value, 158 .set_value = pl061_set_value, 159 }; 160 161 /* 162 * Initialize PL061 GPIO controller 163 */ 164 void pl061_init(struct pl061_data *pd) 165 { 166 COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0); 167 168 assert(pd); 169 pd->chip.ops = &pl061_ops; 170 } 171