uboot/drivers/gpio/octeon_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier:    GPL-2.0
   2/*
   3 * Copyright (C) 2018 Marvell International Ltd.
   4 *
   5 * (C) Copyright 2011
   6 * eInfochips Ltd. <www.einfochips.com>
   7 * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
   8 *
   9 * (C) Copyright 2010
  10 * Marvell Semiconductor <www.marvell.com>
  11 */
  12
  13#include <dm.h>
  14#include <pci.h>
  15#include <pci_ids.h>
  16#include <asm/gpio.h>
  17#include <asm/io.h>
  18#include <linux/bitfield.h>
  19#include <linux/compat.h>
  20#include <dt-bindings/gpio/gpio.h>
  21
  22/* Returns the bit value to write or read based on the offset */
  23#define GPIO_BIT(x)             BIT_ULL((x) & 0x3f)
  24
  25#define GPIO_RX_DAT             0x00
  26#define GPIO_TX_SET             0x08
  27#define GPIO_TX_CLR             0x10
  28#define GPIO_CONST              0x90    /* OcteonTX only */
  29
  30/* Offset to register-set for 2nd GPIOs (> 63), OcteonTX only */
  31#define GPIO1_OFFSET            0x1400
  32
  33/* GPIO_CONST register bits */
  34#define GPIO_CONST_GPIOS_MASK   GENMASK_ULL(7, 0)
  35
  36/* GPIO_BIT_CFG register bits */
  37#define GPIO_BIT_CFG_TX_OE      BIT_ULL(0)
  38#define GPIO_BIT_CFG_PIN_XOR    BIT_ULL(1)
  39#define GPIO_BIT_CFG_INT_EN     BIT_ULL(2)
  40#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK_ULL(26, 16)
  41
  42enum {
  43        PROBE_PCI = 0,          /* PCI based probing */
  44        PROBE_DT,               /* DT based probing */
  45};
  46
  47struct octeon_gpio_data {
  48        int probe;
  49        u32 reg_offs;
  50        u32 gpio_bit_cfg_offs;
  51};
  52
  53struct octeon_gpio {
  54        void __iomem *base;
  55        const struct octeon_gpio_data *data;
  56};
  57
  58/* Returns the offset to the output register based on the offset and value */
  59static u32 gpio_tx_reg(int offset, int value)
  60{
  61        u32 ret;
  62
  63        ret = value ? GPIO_TX_SET : GPIO_TX_CLR;
  64        if (offset > 63)
  65                ret += GPIO1_OFFSET;
  66
  67        return ret;
  68}
  69
  70/* Returns the offset to the input data register based on the offset */
  71static u32 gpio_rx_dat_reg(int offset)
  72{
  73        u32 ret;
  74
  75        ret = GPIO_RX_DAT;
  76        if (offset > 63)
  77                ret += GPIO1_OFFSET;
  78
  79        return ret;
  80}
  81
  82static int octeon_gpio_dir_input(struct udevice *dev, unsigned int offset)
  83{
  84        struct octeon_gpio *gpio = dev_get_priv(dev);
  85
  86        debug("%s(%s, %u)\n", __func__, dev->name, offset);
  87        clrbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
  88                   GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_PIN_XOR |
  89                   GPIO_BIT_CFG_INT_EN | GPIO_BIT_CFG_PIN_SEL_MASK);
  90
  91        return 0;
  92}
  93
  94static int octeon_gpio_dir_output(struct udevice *dev, unsigned int offset,
  95                                  int value)
  96{
  97        struct octeon_gpio *gpio = dev_get_priv(dev);
  98
  99        debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
 100        writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
 101               gpio_tx_reg(offset, value));
 102
 103        clrsetbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
 104                      GPIO_BIT_CFG_PIN_SEL_MASK | GPIO_BIT_CFG_INT_EN,
 105                      GPIO_BIT_CFG_TX_OE);
 106
 107        return 0;
 108}
 109
 110static int octeon_gpio_get_value(struct udevice *dev, unsigned int offset)
 111{
 112        struct octeon_gpio *gpio = dev_get_priv(dev);
 113        u64 reg = readq(gpio->base + gpio->data->reg_offs +
 114                        gpio_rx_dat_reg(offset));
 115
 116        debug("%s(%s, %u): value: %d\n", __func__, dev->name, offset,
 117              !!(reg & GPIO_BIT(offset)));
 118
 119        return !!(reg & GPIO_BIT(offset));
 120}
 121
 122static int octeon_gpio_set_value(struct udevice *dev,
 123                                 unsigned int offset, int value)
 124{
 125        struct octeon_gpio *gpio = dev_get_priv(dev);
 126
 127        debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
 128        writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
 129               gpio_tx_reg(offset, value));
 130
 131        return 0;
 132}
 133
 134static int octeon_gpio_get_function(struct udevice *dev, unsigned int offset)
 135{
 136        struct octeon_gpio *gpio = dev_get_priv(dev);
 137        u64 val = readq(gpio->base + gpio->data->gpio_bit_cfg_offs +
 138                        8 * offset);
 139        int pin_sel;
 140
 141        debug("%s(%s, %u): GPIO_BIT_CFG: 0x%llx\n", __func__, dev->name,
 142              offset, val);
 143        pin_sel = FIELD_GET(GPIO_BIT_CFG_PIN_SEL_MASK, val);
 144        if (pin_sel)
 145                return GPIOF_FUNC;
 146        else if (val & GPIO_BIT_CFG_TX_OE)
 147                return GPIOF_OUTPUT;
 148        else
 149                return GPIOF_INPUT;
 150}
 151
 152static int octeon_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
 153                             struct ofnode_phandle_args *args)
 154{
 155        if (args->args_count < 1)
 156                return -EINVAL;
 157
 158        desc->offset = args->args[0];
 159        desc->flags = 0;
 160        if (args->args_count > 1) {
 161                if (args->args[1] & GPIO_ACTIVE_LOW)
 162                        desc->flags |= GPIOD_ACTIVE_LOW;
 163                /* In the future add tri-state flag support */
 164        }
 165        return 0;
 166}
 167
 168static const struct dm_gpio_ops octeon_gpio_ops = {
 169        .direction_input        = octeon_gpio_dir_input,
 170        .direction_output       = octeon_gpio_dir_output,
 171        .get_value              = octeon_gpio_get_value,
 172        .set_value              = octeon_gpio_set_value,
 173        .get_function           = octeon_gpio_get_function,
 174        .xlate                  = octeon_gpio_xlate,
 175};
 176
 177static int octeon_gpio_probe(struct udevice *dev)
 178{
 179        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 180        struct octeon_gpio *priv = dev_get_priv(dev);
 181        char *end;
 182
 183        priv->data = (const struct octeon_gpio_data *)dev_get_driver_data(dev);
 184
 185        if (priv->data->probe == PROBE_PCI) {
 186                priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
 187                                            PCI_REGION_MEM);
 188                uc_priv->gpio_count = readq(priv->base +
 189                                            priv->data->reg_offs + GPIO_CONST) &
 190                        GPIO_CONST_GPIOS_MASK;
 191        } else {
 192                priv->base = dev_remap_addr(dev);
 193                uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev),
 194                                                              "nr-gpios", 32);
 195        }
 196
 197        if (!priv->base) {
 198                debug("%s(%s): Could not get base address\n",
 199                      __func__, dev->name);
 200                return -ENODEV;
 201        }
 202
 203        uc_priv->bank_name  = strdup(dev->name);
 204        end = strchr(uc_priv->bank_name, '@');
 205        end[0] = 'A' + dev_seq(dev);
 206        end[1] = '\0';
 207
 208        debug("%s(%s): base address: %p, pin count: %d\n",
 209              __func__, dev->name, priv->base, uc_priv->gpio_count);
 210
 211        return 0;
 212}
 213
 214static const struct octeon_gpio_data gpio_octeon_data = {
 215        .probe = PROBE_DT,
 216        .reg_offs = 0x80,
 217        .gpio_bit_cfg_offs = 0x100,
 218};
 219
 220static const struct octeon_gpio_data gpio_octeontx_data = {
 221        .probe = PROBE_PCI,
 222        .reg_offs = 0x00,
 223        .gpio_bit_cfg_offs = 0x400,
 224};
 225
 226static const struct udevice_id octeon_gpio_ids[] = {
 227        { .compatible = "cavium,thunder-8890-gpio",
 228          .data = (ulong)&gpio_octeontx_data },
 229        { .compatible = "cavium,octeon-7890-gpio",
 230          .data = (ulong)&gpio_octeon_data },
 231        { }
 232};
 233
 234U_BOOT_DRIVER(octeon_gpio) = {
 235        .name   = "octeon_gpio",
 236        .id     = UCLASS_GPIO,
 237        .of_match = of_match_ptr(octeon_gpio_ids),
 238        .probe = octeon_gpio_probe,
 239        .priv_auto      = sizeof(struct octeon_gpio),
 240        .ops    = &octeon_gpio_ops,
 241        .flags  = DM_FLAG_PRE_RELOC,
 242};
 243