1*f29d1e0cSSheetal Tigadoli /* 2*f29d1e0cSSheetal Tigadoli * Copyright (c) 2019-2020, Broadcom 3*f29d1e0cSSheetal Tigadoli * 4*f29d1e0cSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause 5*f29d1e0cSSheetal Tigadoli */ 6*f29d1e0cSSheetal Tigadoli 7*f29d1e0cSSheetal Tigadoli #include <assert.h> 8*f29d1e0cSSheetal Tigadoli 9*f29d1e0cSSheetal Tigadoli #include <drivers/gpio.h> 10*f29d1e0cSSheetal Tigadoli #include <lib/mmio.h> 11*f29d1e0cSSheetal Tigadoli #include <plat/common/platform.h> 12*f29d1e0cSSheetal Tigadoli 13*f29d1e0cSSheetal Tigadoli #include <iproc_gpio.h> 14*f29d1e0cSSheetal Tigadoli #include <platform_def.h> 15*f29d1e0cSSheetal Tigadoli 16*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_DATA_IN_OFFSET 0x00 17*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_DATA_OUT_OFFSET 0x04 18*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_OUT_EN_OFFSET 0x08 19*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_PAD_RES_OFFSET 0x34 20*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_RES_EN_OFFSET 0x38 21*f29d1e0cSSheetal Tigadoli 22*f29d1e0cSSheetal Tigadoli #define PINMUX_OFFSET(gpio) ((gpio) * 4) 23*f29d1e0cSSheetal Tigadoli #define PINCONF_OFFSET(gpio) ((gpio) * 4) 24*f29d1e0cSSheetal Tigadoli #define PINCONF_PULL_UP BIT(4) 25*f29d1e0cSSheetal Tigadoli #define PINCONF_PULL_DOWN BIT(5) 26*f29d1e0cSSheetal Tigadoli 27*f29d1e0cSSheetal Tigadoli /* 28*f29d1e0cSSheetal Tigadoli * iProc GPIO bank is always 0x200 per bank, 29*f29d1e0cSSheetal Tigadoli * with each bank supporting 32 GPIOs. 30*f29d1e0cSSheetal Tigadoli */ 31*f29d1e0cSSheetal Tigadoli #define GPIO_BANK_SIZE 0x200 32*f29d1e0cSSheetal Tigadoli #define NGPIOS_PER_BANK 32 33*f29d1e0cSSheetal Tigadoli #define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK) 34*f29d1e0cSSheetal Tigadoli 35*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) 36*f29d1e0cSSheetal Tigadoli #define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK) 37*f29d1e0cSSheetal Tigadoli 38*f29d1e0cSSheetal Tigadoli #define MUX_GPIO_MODE 0x3 39*f29d1e0cSSheetal Tigadoli 40*f29d1e0cSSheetal Tigadoli /* 41*f29d1e0cSSheetal Tigadoli * @base: base address of the gpio controller 42*f29d1e0cSSheetal Tigadoli * @pinconf_base: base address of the pinconf 43*f29d1e0cSSheetal Tigadoli * @pinmux_base: base address of the mux controller 44*f29d1e0cSSheetal Tigadoli * @nr_gpios: maxinum number of GPIOs 45*f29d1e0cSSheetal Tigadoli */ 46*f29d1e0cSSheetal Tigadoli struct iproc_gpio { 47*f29d1e0cSSheetal Tigadoli uintptr_t base; 48*f29d1e0cSSheetal Tigadoli uintptr_t pinconf_base; 49*f29d1e0cSSheetal Tigadoli uintptr_t pinmux_base; 50*f29d1e0cSSheetal Tigadoli int nr_gpios; 51*f29d1e0cSSheetal Tigadoli }; 52*f29d1e0cSSheetal Tigadoli 53*f29d1e0cSSheetal Tigadoli static struct iproc_gpio iproc_gpio; 54*f29d1e0cSSheetal Tigadoli 55*f29d1e0cSSheetal Tigadoli static void gpio_set_bit(uintptr_t base, unsigned int reg, int gpio, bool set) 56*f29d1e0cSSheetal Tigadoli { 57*f29d1e0cSSheetal Tigadoli unsigned int offset = IPROC_GPIO_REG(gpio, reg); 58*f29d1e0cSSheetal Tigadoli unsigned int shift = IPROC_GPIO_SHIFT(gpio); 59*f29d1e0cSSheetal Tigadoli uint32_t val; 60*f29d1e0cSSheetal Tigadoli 61*f29d1e0cSSheetal Tigadoli val = mmio_read_32(base + offset); 62*f29d1e0cSSheetal Tigadoli if (set) 63*f29d1e0cSSheetal Tigadoli val |= BIT(shift); 64*f29d1e0cSSheetal Tigadoli else 65*f29d1e0cSSheetal Tigadoli val &= ~BIT(shift); 66*f29d1e0cSSheetal Tigadoli 67*f29d1e0cSSheetal Tigadoli mmio_write_32(base + offset, val); 68*f29d1e0cSSheetal Tigadoli } 69*f29d1e0cSSheetal Tigadoli 70*f29d1e0cSSheetal Tigadoli static bool gpio_get_bit(uintptr_t base, unsigned int reg, int gpio) 71*f29d1e0cSSheetal Tigadoli { 72*f29d1e0cSSheetal Tigadoli unsigned int offset = IPROC_GPIO_REG(gpio, reg); 73*f29d1e0cSSheetal Tigadoli unsigned int shift = IPROC_GPIO_SHIFT(gpio); 74*f29d1e0cSSheetal Tigadoli 75*f29d1e0cSSheetal Tigadoli return !!(mmio_read_32(base + offset) & BIT(shift)); 76*f29d1e0cSSheetal Tigadoli } 77*f29d1e0cSSheetal Tigadoli 78*f29d1e0cSSheetal Tigadoli static void mux_to_gpio(struct iproc_gpio *g, int gpio) 79*f29d1e0cSSheetal Tigadoli { 80*f29d1e0cSSheetal Tigadoli /* mux pad to GPIO if IOPAD configuration is mandatory */ 81*f29d1e0cSSheetal Tigadoli if (g->pinmux_base) 82*f29d1e0cSSheetal Tigadoli mmio_write_32(g->pinmux_base + PINMUX_OFFSET(gpio), 83*f29d1e0cSSheetal Tigadoli MUX_GPIO_MODE); 84*f29d1e0cSSheetal Tigadoli } 85*f29d1e0cSSheetal Tigadoli 86*f29d1e0cSSheetal Tigadoli static void set_direction(int gpio, int direction) 87*f29d1e0cSSheetal Tigadoli { 88*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 89*f29d1e0cSSheetal Tigadoli bool dir = (direction == GPIO_DIR_OUT) ? true : false; 90*f29d1e0cSSheetal Tigadoli 91*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 92*f29d1e0cSSheetal Tigadoli 93*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 94*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, dir); 95*f29d1e0cSSheetal Tigadoli } 96*f29d1e0cSSheetal Tigadoli 97*f29d1e0cSSheetal Tigadoli static int get_direction(int gpio) 98*f29d1e0cSSheetal Tigadoli { 99*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 100*f29d1e0cSSheetal Tigadoli int dir; 101*f29d1e0cSSheetal Tigadoli 102*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 103*f29d1e0cSSheetal Tigadoli 104*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 105*f29d1e0cSSheetal Tigadoli dir = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ? 106*f29d1e0cSSheetal Tigadoli GPIO_DIR_OUT : GPIO_DIR_IN; 107*f29d1e0cSSheetal Tigadoli 108*f29d1e0cSSheetal Tigadoli return dir; 109*f29d1e0cSSheetal Tigadoli } 110*f29d1e0cSSheetal Tigadoli 111*f29d1e0cSSheetal Tigadoli static int get_value(int gpio) 112*f29d1e0cSSheetal Tigadoli { 113*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 114*f29d1e0cSSheetal Tigadoli unsigned int offset; 115*f29d1e0cSSheetal Tigadoli 116*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 117*f29d1e0cSSheetal Tigadoli 118*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 119*f29d1e0cSSheetal Tigadoli 120*f29d1e0cSSheetal Tigadoli /* 121*f29d1e0cSSheetal Tigadoli * If GPIO is configured as output, read from the GPIO_OUT register; 122*f29d1e0cSSheetal Tigadoli * otherwise, read from the GPIO_IN register 123*f29d1e0cSSheetal Tigadoli */ 124*f29d1e0cSSheetal Tigadoli offset = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ? 125*f29d1e0cSSheetal Tigadoli IPROC_GPIO_DATA_OUT_OFFSET : IPROC_GPIO_DATA_IN_OFFSET; 126*f29d1e0cSSheetal Tigadoli 127*f29d1e0cSSheetal Tigadoli return gpio_get_bit(g->base, offset, gpio); 128*f29d1e0cSSheetal Tigadoli } 129*f29d1e0cSSheetal Tigadoli 130*f29d1e0cSSheetal Tigadoli static void set_value(int gpio, int val) 131*f29d1e0cSSheetal Tigadoli { 132*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 133*f29d1e0cSSheetal Tigadoli 134*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 135*f29d1e0cSSheetal Tigadoli 136*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 137*f29d1e0cSSheetal Tigadoli 138*f29d1e0cSSheetal Tigadoli /* make sure GPIO is configured to output, and then set the value */ 139*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, true); 140*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val)); 141*f29d1e0cSSheetal Tigadoli } 142*f29d1e0cSSheetal Tigadoli 143*f29d1e0cSSheetal Tigadoli static int get_pull(int gpio) 144*f29d1e0cSSheetal Tigadoli { 145*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 146*f29d1e0cSSheetal Tigadoli uint32_t val; 147*f29d1e0cSSheetal Tigadoli 148*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 149*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 150*f29d1e0cSSheetal Tigadoli 151*f29d1e0cSSheetal Tigadoli /* when there's a valid pinconf_base, use it */ 152*f29d1e0cSSheetal Tigadoli if (g->pinconf_base) { 153*f29d1e0cSSheetal Tigadoli val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio)); 154*f29d1e0cSSheetal Tigadoli 155*f29d1e0cSSheetal Tigadoli if (val & PINCONF_PULL_UP) 156*f29d1e0cSSheetal Tigadoli return GPIO_PULL_UP; 157*f29d1e0cSSheetal Tigadoli else if (val & PINCONF_PULL_DOWN) 158*f29d1e0cSSheetal Tigadoli return GPIO_PULL_DOWN; 159*f29d1e0cSSheetal Tigadoli else 160*f29d1e0cSSheetal Tigadoli return GPIO_PULL_NONE; 161*f29d1e0cSSheetal Tigadoli } 162*f29d1e0cSSheetal Tigadoli 163*f29d1e0cSSheetal Tigadoli /* no pinconf_base. fall back to GPIO internal pull control */ 164*f29d1e0cSSheetal Tigadoli if (!gpio_get_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio)) 165*f29d1e0cSSheetal Tigadoli return GPIO_PULL_NONE; 166*f29d1e0cSSheetal Tigadoli 167*f29d1e0cSSheetal Tigadoli return gpio_get_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio) ? 168*f29d1e0cSSheetal Tigadoli GPIO_PULL_UP : GPIO_PULL_DOWN; 169*f29d1e0cSSheetal Tigadoli } 170*f29d1e0cSSheetal Tigadoli 171*f29d1e0cSSheetal Tigadoli static void set_pull(int gpio, int pull) 172*f29d1e0cSSheetal Tigadoli { 173*f29d1e0cSSheetal Tigadoli struct iproc_gpio *g = &iproc_gpio; 174*f29d1e0cSSheetal Tigadoli uint32_t val; 175*f29d1e0cSSheetal Tigadoli 176*f29d1e0cSSheetal Tigadoli assert(gpio < g->nr_gpios); 177*f29d1e0cSSheetal Tigadoli mux_to_gpio(g, gpio); 178*f29d1e0cSSheetal Tigadoli 179*f29d1e0cSSheetal Tigadoli /* when there's a valid pinconf_base, use it */ 180*f29d1e0cSSheetal Tigadoli if (g->pinconf_base) { 181*f29d1e0cSSheetal Tigadoli val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio)); 182*f29d1e0cSSheetal Tigadoli 183*f29d1e0cSSheetal Tigadoli if (pull == GPIO_PULL_NONE) { 184*f29d1e0cSSheetal Tigadoli val &= ~(PINCONF_PULL_UP | PINCONF_PULL_DOWN); 185*f29d1e0cSSheetal Tigadoli } else if (pull == GPIO_PULL_UP) { 186*f29d1e0cSSheetal Tigadoli val |= PINCONF_PULL_UP; 187*f29d1e0cSSheetal Tigadoli val &= ~PINCONF_PULL_DOWN; 188*f29d1e0cSSheetal Tigadoli } else if (pull == GPIO_PULL_DOWN) { 189*f29d1e0cSSheetal Tigadoli val |= PINCONF_PULL_DOWN; 190*f29d1e0cSSheetal Tigadoli val &= ~PINCONF_PULL_UP; 191*f29d1e0cSSheetal Tigadoli } else { 192*f29d1e0cSSheetal Tigadoli return; 193*f29d1e0cSSheetal Tigadoli } 194*f29d1e0cSSheetal Tigadoli mmio_write_32(g->pinconf_base + PINCONF_OFFSET(gpio), val); 195*f29d1e0cSSheetal Tigadoli } 196*f29d1e0cSSheetal Tigadoli 197*f29d1e0cSSheetal Tigadoli /* no pinconf_base. fall back to GPIO internal pull control */ 198*f29d1e0cSSheetal Tigadoli if (pull == GPIO_PULL_NONE) { 199*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, false); 200*f29d1e0cSSheetal Tigadoli return; 201*f29d1e0cSSheetal Tigadoli } 202*f29d1e0cSSheetal Tigadoli 203*f29d1e0cSSheetal Tigadoli /* enable pad register and pull up or down */ 204*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, true); 205*f29d1e0cSSheetal Tigadoli gpio_set_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio, 206*f29d1e0cSSheetal Tigadoli !!(pull == GPIO_PULL_UP)); 207*f29d1e0cSSheetal Tigadoli } 208*f29d1e0cSSheetal Tigadoli 209*f29d1e0cSSheetal Tigadoli const gpio_ops_t iproc_gpio_ops = { 210*f29d1e0cSSheetal Tigadoli .get_direction = get_direction, 211*f29d1e0cSSheetal Tigadoli .set_direction = set_direction, 212*f29d1e0cSSheetal Tigadoli .get_value = get_value, 213*f29d1e0cSSheetal Tigadoli .set_value = set_value, 214*f29d1e0cSSheetal Tigadoli .get_pull = get_pull, 215*f29d1e0cSSheetal Tigadoli .set_pull = set_pull, 216*f29d1e0cSSheetal Tigadoli }; 217*f29d1e0cSSheetal Tigadoli 218*f29d1e0cSSheetal Tigadoli void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base, 219*f29d1e0cSSheetal Tigadoli uintptr_t pinconf_base) 220*f29d1e0cSSheetal Tigadoli { 221*f29d1e0cSSheetal Tigadoli iproc_gpio.base = base; 222*f29d1e0cSSheetal Tigadoli iproc_gpio.nr_gpios = nr_gpios; 223*f29d1e0cSSheetal Tigadoli 224*f29d1e0cSSheetal Tigadoli /* pinmux/pinconf base is optional for some SoCs */ 225*f29d1e0cSSheetal Tigadoli if (pinmux_base) 226*f29d1e0cSSheetal Tigadoli iproc_gpio.pinmux_base = pinmux_base; 227*f29d1e0cSSheetal Tigadoli 228*f29d1e0cSSheetal Tigadoli if (pinconf_base) 229*f29d1e0cSSheetal Tigadoli iproc_gpio.pinconf_base = pinconf_base; 230*f29d1e0cSSheetal Tigadoli 231*f29d1e0cSSheetal Tigadoli gpio_init(&iproc_gpio_ops); 232*f29d1e0cSSheetal Tigadoli } 233