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