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 <trace.h> 30 #include <gpio.h> 31 #include <io.h> 32 #include <util.h> 33 #include <drivers/pl061_gpio.h> 34 35 #ifndef PLAT_PL061_MAX_GPIOS 36 # define PLAT_PL061_MAX_GPIOS 32 37 #endif /* PLAT_PL061_MAX_GPIOS */ 38 39 #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \ 40 (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061) 41 42 #define PL061_GPIO_DIR 0x400 43 44 #define GPIOS_PER_PL061 8 45 46 static enum gpio_dir pl061_get_direction(unsigned int gpio_pin); 47 static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction); 48 static enum gpio_level pl061_get_value(unsigned int gpio_pin); 49 static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value); 50 51 static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES]; 52 53 static const struct gpio_ops pl061_gpio_ops = { 54 .get_direction = pl061_get_direction, 55 .set_direction = pl061_set_direction, 56 .get_value = pl061_get_value, 57 .set_value = pl061_set_value, 58 }; 59 60 static enum gpio_dir pl061_get_direction(unsigned int gpio_pin) 61 { 62 vaddr_t base_addr; 63 uint8_t data; 64 unsigned int offset; 65 66 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 67 68 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 69 offset = gpio_pin % GPIOS_PER_PL061; 70 data = read8(base_addr + PL061_GPIO_DIR); 71 if (data & BIT(offset)) 72 return GPIO_DIR_OUT; 73 return GPIO_DIR_IN; 74 } 75 76 static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction) 77 { 78 vaddr_t base_addr; 79 uint8_t data; 80 unsigned int offset; 81 82 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 83 84 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 85 offset = gpio_pin % GPIOS_PER_PL061; 86 if (direction == GPIO_DIR_OUT) { 87 data = read8(base_addr + PL061_GPIO_DIR) | BIT(offset); 88 write8(data, base_addr + PL061_GPIO_DIR); 89 } else { 90 data = read8(base_addr + PL061_GPIO_DIR) & ~BIT(offset); 91 write8(data, base_addr + PL061_GPIO_DIR); 92 } 93 } 94 95 /* 96 * The offset of GPIODATA register is 0. 97 * The values read from GPIODATA are determined for each bit, by the mask bit 98 * derived from the address used to access the data register, PADDR[9:2]. 99 * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA 100 * to be read, and bits that are 0 in the address mask cause the corresponding 101 * bits in GPIODATA to be read as 0, regardless of their value. 102 */ 103 static enum gpio_level pl061_get_value(unsigned int gpio_pin) 104 { 105 vaddr_t base_addr; 106 unsigned int offset; 107 108 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 109 110 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 111 offset = gpio_pin % GPIOS_PER_PL061; 112 if (read8(base_addr + BIT(offset + 2))) 113 return GPIO_LEVEL_HIGH; 114 return GPIO_LEVEL_LOW; 115 } 116 117 /* 118 * In order to write GPIODATA, the corresponding bits in the mask, resulting 119 * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values 120 * remain unchanged by the write. 121 */ 122 static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value) 123 { 124 vaddr_t base_addr; 125 unsigned int offset; 126 127 assert(gpio_pin < PLAT_PL061_MAX_GPIOS); 128 129 base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061]; 130 offset = gpio_pin % GPIOS_PER_PL061; 131 if (value == GPIO_LEVEL_HIGH) 132 write8(BIT(offset), base_addr + BIT(offset + 2)); 133 else 134 write8(0, base_addr + BIT(offset + 2)); 135 } 136 137 138 /* 139 * Register the PL061 GPIO controller with a base address and the offset 140 * of start pin in this GPIO controller. 141 * This function is called after pl061_gpio_ops_init(). 142 */ 143 void pl061_gpio_register(vaddr_t base_addr, unsigned int gpio_dev) 144 { 145 assert(gpio_dev < MAX_GPIO_DEVICES); 146 147 pl061_reg_base[gpio_dev] = base_addr; 148 } 149 150 /* 151 * Initialize PL061 GPIO controller with the total GPIO numbers in SoC. 152 */ 153 void pl061_gpio_init(void) 154 { 155 COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0); 156 gpio_init(&pl061_gpio_ops); 157 } 158