1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * 6*91f16700Schasinglulu * ARM PL061 GPIO Driver. 7*91f16700Schasinglulu * Reference to ARM DDI 0190B document. 8*91f16700Schasinglulu * 9*91f16700Schasinglulu */ 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <assert.h> 12*91f16700Schasinglulu #include <errno.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include <common/debug.h> 15*91f16700Schasinglulu #include <drivers/arm/pl061_gpio.h> 16*91f16700Schasinglulu #include <drivers/gpio.h> 17*91f16700Schasinglulu #include <lib/cassert.h> 18*91f16700Schasinglulu #include <lib/mmio.h> 19*91f16700Schasinglulu #include <lib/utils.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #if !PLAT_PL061_MAX_GPIOS 22*91f16700Schasinglulu # define PLAT_PL061_MAX_GPIOS 32 23*91f16700Schasinglulu #endif /* PLAT_PL061_MAX_GPIOS */ 24*91f16700Schasinglulu 25*91f16700Schasinglulu CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios); 26*91f16700Schasinglulu 27*91f16700Schasinglulu #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \ 28*91f16700Schasinglulu (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061) 29*91f16700Schasinglulu 30*91f16700Schasinglulu #define PL061_GPIO_DIR 0x400 31*91f16700Schasinglulu 32*91f16700Schasinglulu #define GPIOS_PER_PL061 8 33*91f16700Schasinglulu 34*91f16700Schasinglulu static int pl061_get_direction(int gpio); 35*91f16700Schasinglulu static void pl061_set_direction(int gpio, int direction); 36*91f16700Schasinglulu static int pl061_get_value(int gpio); 37*91f16700Schasinglulu static void pl061_set_value(int gpio, int value); 38*91f16700Schasinglulu 39*91f16700Schasinglulu static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES]; 40*91f16700Schasinglulu 41*91f16700Schasinglulu static const gpio_ops_t pl061_gpio_ops = { 42*91f16700Schasinglulu .get_direction = pl061_get_direction, 43*91f16700Schasinglulu .set_direction = pl061_set_direction, 44*91f16700Schasinglulu .get_value = pl061_get_value, 45*91f16700Schasinglulu .set_value = pl061_set_value, 46*91f16700Schasinglulu }; 47*91f16700Schasinglulu 48*91f16700Schasinglulu static int pl061_get_direction(int gpio) 49*91f16700Schasinglulu { 50*91f16700Schasinglulu uintptr_t base_addr; 51*91f16700Schasinglulu unsigned int data, offset; 52*91f16700Schasinglulu 53*91f16700Schasinglulu assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); 54*91f16700Schasinglulu 55*91f16700Schasinglulu base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; 56*91f16700Schasinglulu offset = gpio % GPIOS_PER_PL061; 57*91f16700Schasinglulu data = mmio_read_8(base_addr + PL061_GPIO_DIR); 58*91f16700Schasinglulu if (data & BIT(offset)) 59*91f16700Schasinglulu return GPIO_DIR_OUT; 60*91f16700Schasinglulu return GPIO_DIR_IN; 61*91f16700Schasinglulu } 62*91f16700Schasinglulu 63*91f16700Schasinglulu static void pl061_set_direction(int gpio, int direction) 64*91f16700Schasinglulu { 65*91f16700Schasinglulu uintptr_t base_addr; 66*91f16700Schasinglulu unsigned int data, offset; 67*91f16700Schasinglulu 68*91f16700Schasinglulu assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); 69*91f16700Schasinglulu 70*91f16700Schasinglulu base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; 71*91f16700Schasinglulu offset = gpio % GPIOS_PER_PL061; 72*91f16700Schasinglulu if (direction == GPIO_DIR_OUT) { 73*91f16700Schasinglulu data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset); 74*91f16700Schasinglulu mmio_write_8(base_addr + PL061_GPIO_DIR, data); 75*91f16700Schasinglulu } else { 76*91f16700Schasinglulu data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset); 77*91f16700Schasinglulu mmio_write_8(base_addr + PL061_GPIO_DIR, data); 78*91f16700Schasinglulu } 79*91f16700Schasinglulu } 80*91f16700Schasinglulu 81*91f16700Schasinglulu /* 82*91f16700Schasinglulu * The offset of GPIODATA register is 0. 83*91f16700Schasinglulu * The values read from GPIODATA are determined for each bit, by the mask bit 84*91f16700Schasinglulu * derived from the address used to access the data register, PADDR[9:2]. 85*91f16700Schasinglulu * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA 86*91f16700Schasinglulu * to be read, and bits that are 0 in the address mask cause the corresponding 87*91f16700Schasinglulu * bits in GPIODATA to be read as 0, regardless of their value. 88*91f16700Schasinglulu */ 89*91f16700Schasinglulu static int pl061_get_value(int gpio) 90*91f16700Schasinglulu { 91*91f16700Schasinglulu uintptr_t base_addr; 92*91f16700Schasinglulu unsigned int offset; 93*91f16700Schasinglulu 94*91f16700Schasinglulu assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); 95*91f16700Schasinglulu 96*91f16700Schasinglulu base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; 97*91f16700Schasinglulu offset = gpio % GPIOS_PER_PL061; 98*91f16700Schasinglulu if (mmio_read_8(base_addr + BIT(offset + 2))) 99*91f16700Schasinglulu return GPIO_LEVEL_HIGH; 100*91f16700Schasinglulu return GPIO_LEVEL_LOW; 101*91f16700Schasinglulu } 102*91f16700Schasinglulu 103*91f16700Schasinglulu /* 104*91f16700Schasinglulu * In order to write GPIODATA, the corresponding bits in the mask, resulting 105*91f16700Schasinglulu * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values 106*91f16700Schasinglulu * remain unchanged by the write. 107*91f16700Schasinglulu */ 108*91f16700Schasinglulu static void pl061_set_value(int gpio, int value) 109*91f16700Schasinglulu { 110*91f16700Schasinglulu uintptr_t base_addr; 111*91f16700Schasinglulu int offset; 112*91f16700Schasinglulu 113*91f16700Schasinglulu assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); 114*91f16700Schasinglulu 115*91f16700Schasinglulu base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; 116*91f16700Schasinglulu offset = gpio % GPIOS_PER_PL061; 117*91f16700Schasinglulu if (value == GPIO_LEVEL_HIGH) 118*91f16700Schasinglulu mmio_write_8(base_addr + BIT(offset + 2), BIT(offset)); 119*91f16700Schasinglulu else 120*91f16700Schasinglulu mmio_write_8(base_addr + BIT(offset + 2), 0); 121*91f16700Schasinglulu } 122*91f16700Schasinglulu 123*91f16700Schasinglulu 124*91f16700Schasinglulu /* 125*91f16700Schasinglulu * Register the PL061 GPIO controller with a base address and the offset 126*91f16700Schasinglulu * of start pin in this GPIO controller. 127*91f16700Schasinglulu * This function is called after pl061_gpio_ops_init(). 128*91f16700Schasinglulu */ 129*91f16700Schasinglulu void pl061_gpio_register(uintptr_t base_addr, int gpio_dev) 130*91f16700Schasinglulu { 131*91f16700Schasinglulu assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES)); 132*91f16700Schasinglulu 133*91f16700Schasinglulu pl061_reg_base[gpio_dev] = base_addr; 134*91f16700Schasinglulu } 135*91f16700Schasinglulu 136*91f16700Schasinglulu /* 137*91f16700Schasinglulu * Initialize PL061 GPIO controller with the total GPIO numbers in SoC. 138*91f16700Schasinglulu */ 139*91f16700Schasinglulu void pl061_gpio_init(void) 140*91f16700Schasinglulu { 141*91f16700Schasinglulu gpio_init(&pl061_gpio_ops); 142*91f16700Schasinglulu } 143