diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c --- a/sys/arm64/rockchip/rk_gpio.c +++ b/sys/arm64/rockchip/rk_gpio.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot + * Copyright (c) 2021 Soren Schmidt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,20 +54,21 @@ #include "fdt_pinctrl_if.h" -#define RK_GPIO_SWPORTA_DR 0x00 /* Data register */ -#define RK_GPIO_SWPORTA_DDR 0x04 /* Data direction register */ - -#define RK_GPIO_INTEN 0x30 /* Interrupt enable register */ -#define RK_GPIO_INTMASK 0x34 /* Interrupt mask register */ -#define RK_GPIO_INTTYPE_LEVEL 0x38 /* Interrupt level register */ -#define RK_GPIO_INT_POLARITY 0x3C /* Interrupt polarity register */ -#define RK_GPIO_INT_STATUS 0x40 /* Interrupt status register */ -#define RK_GPIO_INT_RAWSTATUS 0x44 /* Raw Interrupt status register */ - -#define RK_GPIO_DEBOUNCE 0x48 /* Debounce enable register */ - -#define RK_GPIO_PORTA_EOI 0x4C /* Clear interrupt register */ -#define RK_GPIO_EXT_PORTA 0x50 /* External port register */ +enum gpio_regs { + RK_GPIO_SWPORTA_DR = 1, /* Data register */ + RK_GPIO_SWPORTA_DDR, /* Data direction register */ + RK_GPIO_INTEN, /* Interrupt enable register */ + RK_GPIO_INTMASK, /* Interrupt mask register */ + RK_GPIO_INTTYPE_LEVEL, /* Interrupt level register */ + RK_GPIO_INTTYPE_BOTH, /* Both rise and falling edge */ + RK_GPIO_INT_POLARITY, /* Interrupt polarity register */ + RK_GPIO_INT_STATUS, /* Interrupt status register */ + RK_GPIO_INT_RAWSTATUS, /* Raw Interrupt status register */ + RK_GPIO_DEBOUNCE, /* Debounce enable register */ + RK_GPIO_PORTA_EOI, /* Clear interrupt register */ + RK_GPIO_EXT_PORTA, /* External port register */ + RK_GPIO_REGNUM +}; #define RK_GPIO_LS_SYNC 0x60 /* Level sensitive syncronization enable register */ @@ -90,9 +92,9 @@ bus_space_handle_t sc_bsh; clk_t clk; device_t pinctrl; - uint32_t swporta; - uint32_t swporta_ddr; + uint32_t version; struct pin_cached pin_cached[RK_GPIO_MAX_PINS]; + uint8_t regs[RK_GPIO_REGNUM]; }; static struct ofw_compat_data compat_data[] = { @@ -106,6 +108,10 @@ { -1, 0 } }; +#define RK_GPIO_VERSION 0x78 +#define RK_GPIO_TYPE_V1 0x00000000 +#define RK_GPIO_TYPE_V2 0x01000c2b + static int rk_gpio_detach(device_t dev); #define RK_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) @@ -117,6 +123,80 @@ #define RK_GPIO_READ(_sc, _off) \ bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off) +static int +rk_gpio_read_bit(struct rk_gpio_softc *sc, int reg, int bit) +{ + int offset = sc->regs[reg]; + uint32_t value; + + RK_GPIO_LOCK(sc); + if (sc->version == RK_GPIO_TYPE_V1) { + value = RK_GPIO_READ(sc, offset); + value >>= bit; + } else { + value = RK_GPIO_READ(sc, bit > 15 ? offset + 4 : offset); + value >>= (bit % 16); + } + RK_GPIO_UNLOCK(sc); + return (value & 1); +} + +static void +rk_gpio_write_bit(struct rk_gpio_softc *sc, int reg, int bit, int data) +{ + int offset = sc->regs[reg]; + uint32_t value; + + RK_GPIO_LOCK(sc); + if (sc->version == RK_GPIO_TYPE_V1) { + value = RK_GPIO_READ(sc, offset); + if (data) + value |= (1 << bit); + else + value &= ~(1 << bit); + RK_GPIO_WRITE(sc, offset, value); + } else { + if (data) + value = (1 << (bit % 16)); + else + value = 0; + value |= (1 << ((bit % 16) + 16)); + RK_GPIO_WRITE(sc, bit > 15 ? offset + 4 : offset, value); + } + RK_GPIO_UNLOCK(sc); +} + +static uint32_t +rk_gpio_read_4(struct rk_gpio_softc *sc, int reg) +{ + int offset = sc->regs[reg]; + uint32_t value; + + RK_GPIO_LOCK(sc); + if (sc->version == RK_GPIO_TYPE_V1) + value = RK_GPIO_READ(sc, offset); + else + value = (RK_GPIO_READ(sc, offset) & 0xffff) | + (RK_GPIO_READ(sc, offset + 4) << 16); + RK_GPIO_UNLOCK(sc); + return (value); +} + +static void +rk_gpio_write_4(struct rk_gpio_softc *sc, int reg, uint32_t value) +{ + int offset = sc->regs[reg]; + + RK_GPIO_LOCK(sc); + if (sc->version == RK_GPIO_TYPE_V1) + RK_GPIO_WRITE(sc, offset, value); + else { + RK_GPIO_WRITE(sc, offset, (value & 0xffff) | 0xffff0000); + RK_GPIO_WRITE(sc, offset + 4, (value >> 16) | 0xffff0000); + } + RK_GPIO_UNLOCK(sc); +} + static int rk_gpio_probe(device_t dev) { @@ -171,6 +251,40 @@ return (ENXIO); } + switch ((sc->version = rk_gpio_read_4(sc, RK_GPIO_VERSION))) { + case RK_GPIO_TYPE_V1: + sc->regs[RK_GPIO_SWPORTA_DR] = 0x00; + sc->regs[RK_GPIO_SWPORTA_DDR] = 0x04; + sc->regs[RK_GPIO_INTEN] = 0x30; + sc->regs[RK_GPIO_INTMASK] = 0x34; + sc->regs[RK_GPIO_INTTYPE_LEVEL] = 0x38; + sc->regs[RK_GPIO_INT_POLARITY] = 0x3c; + sc->regs[RK_GPIO_INT_STATUS] = 0x40; + sc->regs[RK_GPIO_INT_RAWSTATUS] = 0x44; + sc->regs[RK_GPIO_DEBOUNCE] = 0x48; + sc->regs[RK_GPIO_PORTA_EOI] = 0x4c; + sc->regs[RK_GPIO_EXT_PORTA] = 0x50; + break; + case RK_GPIO_TYPE_V2: + sc->regs[RK_GPIO_SWPORTA_DR] = 0x00; + sc->regs[RK_GPIO_SWPORTA_DDR] = 0x08; + sc->regs[RK_GPIO_INTEN] = 0x10; + sc->regs[RK_GPIO_INTMASK] = 0x18; + sc->regs[RK_GPIO_INTTYPE_LEVEL] = 0x20; + sc->regs[RK_GPIO_INTTYPE_BOTH] = 0x30; + sc->regs[RK_GPIO_INT_POLARITY] = 0x28; + sc->regs[RK_GPIO_INT_STATUS] = 0x50; + sc->regs[RK_GPIO_INT_RAWSTATUS] = 0x58; + sc->regs[RK_GPIO_DEBOUNCE] = 0x38; + sc->regs[RK_GPIO_PORTA_EOI] = 0x60; + sc->regs[RK_GPIO_EXT_PORTA] = 0x70; + break; + default: + device_printf(dev, "Unknown gpio version %08x\n", sc->version); + rk_gpio_detach(dev); + return (ENXIO); + } + sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) { rk_gpio_detach(dev); @@ -181,11 +295,6 @@ for (i = 0; i < RK_GPIO_MAX_PINS; i++) sc->pin_cached[i].is_gpio = 2; - RK_GPIO_LOCK(sc); - sc->swporta = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR); - sc->swporta_ddr = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR); - RK_GPIO_UNLOCK(sc); - return (0); } @@ -267,7 +376,7 @@ return (rv); sc->pin_cached[pin].flags = *flags; - if (sc->swporta_ddr & (1 << pin)) + if (rk_gpio_read_bit(sc, RK_GPIO_SWPORTA_DDR, pin)) *flags |= GPIO_PIN_OUTPUT; else *flags |= GPIO_PIN_INPUT; @@ -279,6 +388,9 @@ rk_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { + if (pin >= RK_GPIO_MAX_PINS) + return EINVAL; + *caps = RK_GPIO_DEFAULT_CAPS; return (0); } @@ -291,6 +403,9 @@ sc = device_get_softc(dev); + if (pin >= RK_GPIO_MAX_PINS) + return (EINVAL); + if (__predict_false(sc->pin_cached[pin].is_gpio != 1)) { rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, (bool *)&sc->pin_cached[pin].is_gpio); if (rv != 0) @@ -306,14 +421,8 @@ return (rv); } - RK_GPIO_LOCK(sc); - if (flags & GPIO_PIN_INPUT) - sc->swporta_ddr &= ~(1 << pin); - else if (flags & GPIO_PIN_OUTPUT) - sc->swporta_ddr |= (1 << pin); - - RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, sc->swporta_ddr); - RK_GPIO_UNLOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, + (flags & GPIO_PIN_OUTPUT ? 1 : 0)); return (0); } @@ -322,16 +431,13 @@ rk_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct rk_gpio_softc *sc; - uint32_t reg; sc = device_get_softc(dev); - RK_GPIO_LOCK(sc); - reg = RK_GPIO_READ(sc, RK_GPIO_EXT_PORTA); - RK_GPIO_UNLOCK(sc); - - *val = reg & (1 << pin) ? 1 : 0; + if (pin >= RK_GPIO_MAX_PINS) + return (EINVAL); + *val = rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin); return (0); } @@ -342,14 +448,10 @@ sc = device_get_softc(dev); - RK_GPIO_LOCK(sc); - if (value) - sc->swporta |= (1 << pin); - else - sc->swporta &= ~(1 << pin); - RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, sc->swporta); - RK_GPIO_UNLOCK(sc); + if (pin >= RK_GPIO_MAX_PINS) + return (EINVAL); + rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DR, pin, value); return (0); } @@ -357,16 +459,15 @@ rk_gpio_pin_toggle(device_t dev, uint32_t pin) { struct rk_gpio_softc *sc; + int value; sc = device_get_softc(dev); - RK_GPIO_LOCK(sc); - if (sc->swporta & (1 << pin)) - sc->swporta &= ~(1 << pin); - else - sc->swporta |= (1 << pin); - RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, sc->swporta); - RK_GPIO_UNLOCK(sc); + if (pin >= RK_GPIO_MAX_PINS) + return (EINVAL); + + value = rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin); + rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DR, pin, !value); return (0); } @@ -380,17 +481,14 @@ sc = device_get_softc(dev); - RK_GPIO_LOCK(sc); - reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR); + reg = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DR); if (orig_pins) *orig_pins = reg; - sc->swporta = reg; if ((clear_pins | change_pins) != 0) { reg = (reg & ~clear_pins) ^ change_pins; - RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, reg); + rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DR, reg); } - RK_GPIO_UNLOCK(sc); return (0); } @@ -420,13 +518,10 @@ } } - RK_GPIO_LOCK(sc); - reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR); + reg = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DDR); reg &= ~mask; reg |= set; - RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, reg); - sc->swporta_ddr = reg; - RK_GPIO_UNLOCK(sc); + rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DDR, reg); return (0); }