blob: c4d28fc4747ce6e420e8ebfd6384ce3e830acd0b [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stddef.h>
#include <utils/arith.h>
#include <utils/fence.h>
#include <utils/attribute.h>
#include <platsupport/gpio.h>
#include <platsupport/plat/gpio.h>
#include "mux_gpio_priv.h"
#include "../../services.h"
/** @file GPIO driver for the TK1.
*
* Contains routines for manipulating GPIO pins on the TK1.
*
* PREREQUISITES:
* This driver currently assumes that the MMIO registers it accesses are mapped
* as strongly ordered and uncached. The driver makes no attempts whatsoever at
* managing the write buffer or managing ordering of reads and writes.
*/
#define GPIO_CONTROLLER1_ADDR_OFFSET 0
#define GPIO_CONTROLLER2_ADDR_OFFSET 0x100
#define GPIO_CONTROLLER3_ADDR_OFFSET 0x200
#define GPIO_CONTROLLER4_ADDR_OFFSET 0x300
#define GPIO_CONTROLLER5_ADDR_OFFSET 0x400
#define GPIO_CONTROLLER6_ADDR_OFFSET 0x500
#define GPIO_CONTROLLER7_ADDR_OFFSET 0x600
#define GPIO_CONTROLLER8_ADDR_OFFSET 0x700
#define PORT_NBITS (8)
#define REG_VALID_BITS_MASK (0xFF)
#define CNFREG_VALID_BITS_MASK (0xFFFF)
enum tk1_gpio_bank_regs {
GPIO_CNF = 0,
GPIO_OE,
GPIO_OUT,
GPIO_IN,
GPIO_INT_STA,
GPIO_INT_ENB,
GPIO_INT_LVL,
GPIO_INT_CLR,
GPIO_MSK_CNF,
GPIO_MSK_OE,
GPIO_MSK_OUT,
/* 0xB is invalid - no register exists there */
GPIO_REG_INVALID = 0xB,
GPIO_MSK_INT_STA,
GPIO_MSK_INT_ENB,
GPIO_MSK_INT_LVL,
TEGRA_GPIO_REGS
};
#define GPIO_PORT1 0x0
#define GPIO_PORT2 0x4
#define GPIO_PORT3 0x8
#define GPIO_PORT4 0xC
#define TEGRA_GPIO_PORTS 4
#define TEGRA_GPIO_BANKS 8
#define GPIO_BANK(x) ((x) >> 5)
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
#define GPIO_BIT(x) ((x) & 0x7)
#define GPIO_INT_LVL_MASK 0x010101
#define GPIO_INT_LVL_EDGE_RISING 0x000101
#define GPIO_INT_LVL_EDGE_FALLING 0x000100
#define GPIO_INT_LVL_EDGE_BOTH 0x010100
#define GPIO_INT_LVL_LEVEL_HIGH 0x000001
#define GPIO_INT_LVL_LEVEL_LOW 0x000000
/* Used for debug output */
static uint32_t tegra_gpio_controller[] = { GPIO_CONTROLLER1_ADDR_OFFSET,
GPIO_CONTROLLER2_ADDR_OFFSET,
GPIO_CONTROLLER3_ADDR_OFFSET,
GPIO_CONTROLLER4_ADDR_OFFSET,
GPIO_CONTROLLER5_ADDR_OFFSET,
GPIO_CONTROLLER6_ADDR_OFFSET,
GPIO_CONTROLLER7_ADDR_OFFSET,
GPIO_CONTROLLER8_ADDR_OFFSET
};
static uint32_t tegra_gpio_port[] = { GPIO_PORT1,
GPIO_PORT2,
GPIO_PORT3,
GPIO_PORT4
};
typedef struct tk1_gpio_ {
volatile uint32_t ports[TEGRA_GPIO_PORTS];
} tk1_gpio_ports_t;
static_assert(sizeof(tk1_gpio_ports_t) == 16, "Ports struct should be 16 bytes");
typedef struct tk1_gpio_bank_ {
tk1_gpio_ports_t regs[TEGRA_GPIO_REGS];
PAD_STRUCT_BETWEEN(0x0,
0x100,
tk1_gpio_ports_t[TEGRA_GPIO_REGS]);
} tk1_gpio_bank_t;
static_assert(sizeof(tk1_gpio_bank_t) == 256, "Banks should be 256 bytes each");
typedef struct tk1_gpio_regs_ {
tk1_gpio_bank_t bank[TEGRA_GPIO_BANKS];
} tk1_gpio_regs_t;
static_assert(sizeof(tk1_gpio_regs_t) == 256 * 8, "There are only 8 banks");
static inline tk1_gpio_regs_t *tk1_gpio_get_priv(gpio_sys_t *sys)
{
ZF_LOGF_IF(sys == NULL, "Invalid controller handle!");
return (tk1_gpio_regs_t *)sys->priv;
}
static inline tk1_gpio_regs_t *tk1_gpio_pin_get_priv(gpio_t *pin)
{
ZF_LOGF_IF(pin == NULL, "Invalid pin handle!");
return tk1_gpio_get_priv(pin->gpio_sys);
}
static inline tk1_gpio_bank_t *tk1_gpio_get_bank_by_pin(gpio_sys_t *sys, int pin)
{
return &tk1_gpio_get_priv(sys)->bank[GPIO_BANK(pin)];
}
static inline volatile uint32_t *get_controller_register(gpio_sys_t *gpio_sys,
enum gpio_pin gpio_num,
enum tk1_gpio_bank_regs gpio_register)
{
ZF_LOGF_IF(gpio_register == GPIO_REG_INVALID, "Invalid register index!");
ZF_LOGF_IF(gpio_register < 0 || gpio_register > GPIO_MSK_INT_LVL,
"Invalid register index!");
return &tk1_gpio_get_bank_by_pin(gpio_sys, gpio_num)->regs[gpio_register]
.ports[GPIO_PORT(gpio_num)];
}
/** For debugging.
*
* The lock bit determines whether or not it's possible to reconfigure the
* GPIO pins. This function does a scan and prints all those pins that have
* their lock bits set.
*/
UNUSED static void tk1_gpio_debug_print_locks(gpio_sys_t *gs)
{
volatile uint32_t *v_cnf;
int total = 0;
for (int i = 0; i <= GPIO_PFF7; i++) {
v_cnf = get_controller_register(gs, i, GPIO_CNF);
if (*v_cnf & BIT(GPIO_BIT(i))) {
total++;
ZF_LOGD("GPIO: Pin %d has its lock set: CNF lock: regval %x.\n",
i, *v_cnf);
}
}
ZF_LOGD("GPIO: lock scan: %d pins have their locks set.\n", total);
}
static int gpio_set_direction(gpio_sys_t *gpio_sys,
enum gpio_pin gpio, enum gpio_dir mode)
{
uint32_t val, cnf_val;
volatile uint32_t *cnf_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_CNF);;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_OE);
val = *reg_vaddr & REG_VALID_BITS_MASK;
cnf_val = *cnf_vaddr & CNFREG_VALID_BITS_MASK;
/* There are lock bits in the CNF register (TK1 SoC manual, sec 8.11.1).
* These lock bits enable and disable access to the CNF and OE registers.
*
* The CNF register has the bit that sets the pins to be either GPIO or
* SFIO mode.
* The OE register has the bit that sets the pins to be input or output
* mode.
*
* Unfortunately, if the lock bit is set therefore, we will be unable to
* actually change the configuration of the pin, because the lock bits can
* only be set up once during boot, and they are sticky after that:
*
* Section 8.11.1:
* "Lock bits are used to control the access to the CNF and OE registers.
* When set, no one can write to the CNF and OE bits. They can be
* programmed ONLY during Boot and get reset by chip reset only."
*
* So we must first test to see if the pin is already configured the way the
* user wants it. If it is, then we don't have to do anything.
*
* If the bit is NOT already configured to act the way the user is
* requesting, then we have to check the "lock" bit. If the lock bit is
* UNSET, then we can reconfigure the pin.
*
* If the "lock" bit is SET, then we cannot reconfigure the pin and we
* must return an error to the user.
*/
switch (mode) {
case GPIO_DIR_OUT_DEFAULT_HIGH:
case GPIO_DIR_OUT_DEFAULT_LOW:
if (val & BIT(GPIO_BIT(gpio))) {
/* If it's already how we want it, return success immediately. */
return 0;
}
if (cnf_val & BIT(GPIO_BIT(gpio) + PORT_NBITS)) {
/* If it's not how the user wants it already, and the lock bit is
* set, then we can't fulfill the user's request: return error
* immediately.
*/
ZF_LOGW("Bit %d: Unable to setup as output pin. Pin is locked.",
gpio);
return -1;
}
val |= BIT(GPIO_BIT(gpio));
break;
case GPIO_DIR_IN:
if ((val & BIT(GPIO_BIT(gpio))) == 0) {
return 0;
}
if (cnf_val & BIT(GPIO_BIT(gpio) + PORT_NBITS)) {
ZF_LOGW("Bit %d: Unable to setup as input pin. Pin is locked.",
gpio);
return -1;
}
val &= ~(BIT(GPIO_BIT(gpio)));
break;
default:
ZF_LOGF("gpio: %d, invalid mode %d.", gpio, mode);
}
*reg_vaddr = val;
assert(*reg_vaddr == val);
return 0;
}
static void gpio_set_interrupt_type(gpio_sys_t *gpio_sys,
enum gpio_pin gpio, enum gpio_dir dir)
{
uint32_t val, lvl_type = 0;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_INT_LVL);
val = *reg_vaddr & REG_VALID_BITS_MASK;
switch (dir) {
case GPIO_DIR_IRQ_RISE:
lvl_type = GPIO_INT_LVL_EDGE_RISING;
break;
case GPIO_DIR_IRQ_FALL:
lvl_type = GPIO_INT_LVL_EDGE_FALLING;
break;
case GPIO_DIR_IRQ_EDGE:
lvl_type = GPIO_INT_LVL_EDGE_BOTH;
break;
case GPIO_DIR_IRQ_HIGH:
lvl_type = GPIO_INT_LVL_LEVEL_HIGH;
break;
case GPIO_DIR_IRQ_LOW:
lvl_type = GPIO_INT_LVL_LEVEL_LOW;
break;
default:
ZF_LOGF("GPIO: %d, invalid pin direction/interrupt %d", gpio, dir);
}
val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
val |= lvl_type << GPIO_BIT(gpio);
*reg_vaddr = val;
assert(*reg_vaddr == val);
}
static void gpio_interrupt_enable(gpio_sys_t *gpio_sys,
enum gpio_pin gpio, bool enable)
{
uint32_t val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_INT_ENB);
val = *reg_vaddr & REG_VALID_BITS_MASK;
if (enable) {
val |= BIT(GPIO_BIT(gpio));
} else {
val &= ~(BIT(GPIO_BIT(gpio)));
}
*reg_vaddr = val;
assert(*reg_vaddr == val);
}
static int tegra_set_level(gpio_t *gpio, enum gpio_level level)
{
gpio_sys_t *gpio_sys = gpio->gpio_sys;
enum gpio_pin pin = gpio->id;
uint32_t val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
pin, GPIO_OUT);
ZF_LOGV("Offset: 0x%x (vaddr %x), controller offset: 0x%x, port offset: 0x%x, "
"GPIO_IN: 0x%x, gpio: %d, bank: %d, port: %d, gpio_bit: %d",
tegra_gpio_controller[GPIO_BANK(pin)]
+ tegra_gpio_port[GPIO_PORT(pin)]
+ GPIO_OUT,
reg_vaddr,
tegra_gpio_controller[GPIO_BANK(pin)],
tegra_gpio_port[GPIO_PORT(pin)],
GPIO_OUT, pin, GPIO_BANK(pin), GPIO_PORT(pin), GPIO_BIT(pin));
val = *reg_vaddr & REG_VALID_BITS_MASK;
if (level == GPIO_LEVEL_HIGH) {
val |= BIT(GPIO_BIT(pin));
} else {
val &= ~(BIT(GPIO_BIT(pin)));
}
*reg_vaddr = val;
assert(*reg_vaddr == val);
return 0;
}
static int tegra_read_level(gpio_t *gpio)
{
gpio_sys_t *gpio_sys = gpio->gpio_sys;
enum gpio_pin pin = gpio->id;
uint32_t val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
pin, GPIO_IN);
ZF_LOGV("Offset: 0x%x, controller offset: 0x%x, port offset: 0x%x, "
"GPIO_IN: 0x%x, gpio: %d, bank: %d, port: %d, gpio_bit: %d",
tegra_gpio_controller[GPIO_BANK(pin)]
+ tegra_gpio_port[GPIO_PORT(pin)]
+ GPIO_IN,
tegra_gpio_controller[GPIO_BANK(pin)],
tegra_gpio_port[GPIO_PORT(pin)],
GPIO_OUT, pin, GPIO_BANK(pin), GPIO_PORT(pin), GPIO_BIT(pin));
val = *reg_vaddr & REG_VALID_BITS_MASK;
ZF_LOGV("GPIO %d bit value: 0x%x\n", pin, val);
if (!!(val & BIT(GPIO_BIT(pin)))) {
return GPIO_LEVEL_HIGH;
}
return GPIO_LEVEL_LOW;
}
static void gpio_int_clear(gpio_sys_t *gpio_sys, enum gpio_pin gpio)
{
uint32_t val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_INT_CLR);
ZF_LOGV("offset: 0x%x, controller offset: 0x%x, port offset: 0x%x, "
"GPIO_IN: 0x%x, gpio: %d, bank: %d, port: %d, gpio_bit: %d",
tegra_gpio_controller[GPIO_BANK(gpio)]
+ tegra_gpio_port[GPIO_PORT(gpio)]
+ GPIO_INT_CLR,
tegra_gpio_controller[GPIO_BANK(gpio)],
tegra_gpio_port[GPIO_PORT(gpio)],
GPIO_OUT, gpio, GPIO_BANK(gpio), GPIO_PORT(gpio), GPIO_BIT(gpio));
val = *reg_vaddr & REG_VALID_BITS_MASK;
val |= BIT(GPIO_BIT(gpio));
*reg_vaddr = val;
}
static bool gpio_check_pending(gpio_sys_t *gpio_sys, enum gpio_pin gpio)
{
uint32_t val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_INT_STA);
val = *reg_vaddr & REG_VALID_BITS_MASK;
return !!(val & BIT(GPIO_BIT(gpio)));
}
static int tegra_pending_status(gpio_t *gpio, bool clear)
{
int pending;
if (gpio == NULL) {
return -ENOSYS;
}
if (gpio->gpio_sys == NULL) {
return -ENOSYS;
}
pending = gpio_check_pending(gpio->gpio_sys, gpio->id);
if (clear) {
gpio_int_clear(gpio->gpio_sys, gpio->id);
}
return pending;
}
static int tegra_gpio_init(gpio_sys_t *gpio_sys, int id, enum gpio_dir dir, gpio_t *gpio)
{
int error;
ZF_LOGV("Configuring GPIO pin %d", id);
gpio->id = id;
gpio->gpio_sys = gpio_sys;
error = gpio_set_pad_mode(gpio_sys, id, GPIO_MODE, dir);
if (error != 0) {
return error;
}
if (dir == GPIO_DIR_IN
|| dir == GPIO_DIR_OUT_DEFAULT_HIGH || dir == GPIO_DIR_OUT_DEFAULT_LOW) {
error = gpio_set_direction(gpio_sys, id, dir);
if (error != 0) {
return error;
}
} else {
gpio_set_interrupt_type(gpio_sys, id, dir);
}
/* Default to disabled IRQ state. The caller should have to call
* gpio_int_enable() explicitly to enable the IRQ signal for the pin, if the
* pin is configured to be an IRQ pin.
*
* The caller should also explicitly set the default output value if the pin
* is an input/output pin.
*/
gpio_interrupt_enable(gpio_sys, id, 0);
return 0;
}
static int tegra_gpio_int_enable_disable(gpio_t *gpio, bool enable)
{
gpio_interrupt_enable(gpio->gpio_sys, gpio->id, enable);
return 0;
}
int gpio_init(volatile void *vaddr, gpio_sys_t *gpio_sys)
{
if (gpio_sys == NULL) {
return -ENOSYS;
}
if (vaddr == NULL) {
return -ENOSYS;
}
ZF_LOGV("vaddr: %p", vaddr);
gpio_sys->set_level = &tegra_set_level;
gpio_sys->read_level = &tegra_read_level;
gpio_sys->pending_status = &tegra_pending_status;
gpio_sys->irq_enable_disable = &tegra_gpio_int_enable_disable;
gpio_sys->init = &tegra_gpio_init;
gpio_sys->priv = (void *)vaddr;
return 0;
}
int gpio_sys_init(ps_io_ops_t *io_ops, gpio_sys_t *gpio_sys)
{
if (io_ops == NULL) {
return -ENOSYS;
}
if (gpio_sys == NULL) {
return -ENOSYS;
}
MAP_IF_NULL(io_ops, TK1_GPIO, gpio_sys->priv);
if (gpio_sys->priv == NULL) {
ZF_LOGE("Failed to map TK1 GPIO frame.");
return -1;
}
return gpio_init(gpio_sys->priv, gpio_sys);
}
int gpio_set_pad_mode(gpio_sys_t *gpio_sys,
enum gpio_pin gpio, enum gpio_pad_mode mode, enum gpio_dir dir)
{
uint32_t val, out_val;
volatile uint32_t *reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_CNF);
volatile uint32_t *out_reg_vaddr = get_controller_register(gpio_sys,
gpio, GPIO_OUT);
ZF_LOGV("Offset: 0x%x, controller offset: 0x%x, port offset: 0x%x, "
"GPIO_CNF: 0x%x, gpio: %d, bank: %d, port: %d, gpio_bit: %d"
"Mode %d.\n",
tegra_gpio_controller[GPIO_BANK(gpio)]
+ tegra_gpio_port[GPIO_PORT(gpio)]
+ GPIO_CNF,
tegra_gpio_controller[GPIO_BANK(gpio)],
tegra_gpio_port[GPIO_PORT(gpio)],
GPIO_CNF, gpio, GPIO_BANK(gpio), GPIO_PORT(gpio), GPIO_BIT(gpio),
mode);
/* See the comment in gpio_set_direction() above: ability to change the
* mode of a pin from SFIO to GPIO mode requires us to change bits in the
* CNF register. But the CNF register is locked off if the "lock" bit is
* set.
*
* So we must first test the lock bit to know if we can fulfill the user's
* request at all. If we can't, we return early with an error.
*/
val = *reg_vaddr & CNFREG_VALID_BITS_MASK;
switch (mode) {
case GPIO_MODE:
/* We need to support a transition to GPIO mode while ensuring that
* the initialization preserves a certain output value (DEFAULT_HIGH vs
* DEFAULT_LOW).
*/
out_val = *out_reg_vaddr & REG_VALID_BITS_MASK;
switch (dir) {
case GPIO_DIR_OUT_DEFAULT_HIGH:
out_val |= BIT(GPIO_BIT(gpio));
break;
case GPIO_DIR_OUT_DEFAULT_LOW:
out_val &= ~(BIT(GPIO_BIT(gpio)));
break;
default:
break;
}
*out_reg_vaddr = out_val;
if (val & BIT(GPIO_BIT(gpio))) {
/* If it's already setup the way the user requested, just return
* success early.
*/
return 0;
}
if (val & BIT(GPIO_BIT(gpio) + PORT_NBITS)) {
/* If it's not setup the way the user wants, but the lock bit is
* also set, then we cannot reconfigure the pin. Return error.
*/
ZF_LOGW("Pin %d: Failed to set to GPIO mode. Pin is locked.", gpio);
return -1;
}
val |= BIT(GPIO_BIT(gpio));
break;
case SFIO_MODE:
if ((val & BIT(GPIO_BIT(gpio))) == 0) {
return 0;
}
if (val & BIT(GPIO_BIT(gpio) + PORT_NBITS)) {
ZF_LOGW("Pin %d: Failed to set to GPIO mode. Pin is locked.", gpio);
return -1;
}
val &= ~(BIT(GPIO_BIT(gpio)));
break;
default:
ZF_LOGF("GPIO: pin %d, invalid mode %d", gpio, mode);
}
ZF_LOGV("Reg value: 0x%x", val);
*reg_vaddr = val;
assert(*reg_vaddr == val);
return 0;
}