uboot/board/renesas/ulcb/cpld.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ULCB board CPLD access support
   4 *
   5 * Copyright (C) 2017 Renesas Electronics Corporation
   6 * Copyright (C) 2017 Cogent Embedded, Inc.
   7 */
   8
   9#include <common.h>
  10#include <asm/gpio.h>
  11#include <asm/io.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <linux/err.h>
  15#include <sysreset.h>
  16
  17#define CPLD_ADDR_MODE          0x00 /* RW */
  18#define CPLD_ADDR_MUX           0x02 /* RW */
  19#define CPLD_ADDR_DIPSW6        0x08 /* R */
  20#define CPLD_ADDR_RESET         0x80 /* RW */
  21#define CPLD_ADDR_VERSION       0xFF /* R */
  22
  23struct renesas_ulcb_sysreset_priv {
  24        struct gpio_desc        miso;
  25        struct gpio_desc        mosi;
  26        struct gpio_desc        sck;
  27        struct gpio_desc        sstbz;
  28};
  29
  30static u32 cpld_read(struct udevice *dev, u8 addr)
  31{
  32        struct renesas_ulcb_sysreset_priv *priv = dev_get_priv(dev);
  33        u32 data = 0;
  34        int i;
  35
  36        for (i = 0; i < 8; i++) {
  37                dm_gpio_set_value(&priv->mosi, !!(addr & 0x80)); /* MSB first */
  38                dm_gpio_set_value(&priv->sck, 1);
  39                addr <<= 1;
  40                dm_gpio_set_value(&priv->sck, 0);
  41        }
  42
  43        dm_gpio_set_value(&priv->mosi, 0); /* READ */
  44        dm_gpio_set_value(&priv->sstbz, 0);
  45        dm_gpio_set_value(&priv->sck, 1);
  46        dm_gpio_set_value(&priv->sck, 0);
  47        dm_gpio_set_value(&priv->sstbz, 1);
  48
  49        for (i = 0; i < 32; i++) {
  50                dm_gpio_set_value(&priv->sck, 1);
  51                data <<= 1;
  52                data |= dm_gpio_get_value(&priv->miso); /* MSB first */
  53                dm_gpio_set_value(&priv->sck, 0);
  54        }
  55
  56        return data;
  57}
  58
  59static void cpld_write(struct udevice *dev, u8 addr, u32 data)
  60{
  61        struct renesas_ulcb_sysreset_priv *priv = dev_get_priv(dev);
  62        int i;
  63
  64        for (i = 0; i < 32; i++) {
  65                dm_gpio_set_value(&priv->mosi, data & (1 << 31)); /* MSB first */
  66                dm_gpio_set_value(&priv->sck, 1);
  67                data <<= 1;
  68                dm_gpio_set_value(&priv->sck, 0);
  69        }
  70
  71        for (i = 0; i < 8; i++) {
  72                dm_gpio_set_value(&priv->mosi, addr & 0x80); /* MSB first */
  73                dm_gpio_set_value(&priv->sck, 1);
  74                addr <<= 1;
  75                dm_gpio_set_value(&priv->sck, 0);
  76        }
  77
  78        dm_gpio_set_value(&priv->mosi, 1); /* WRITE */
  79        dm_gpio_set_value(&priv->sstbz, 0);
  80        dm_gpio_set_value(&priv->sck, 1);
  81        dm_gpio_set_value(&priv->sck, 0);
  82        dm_gpio_set_value(&priv->sstbz, 1);
  83}
  84
  85static int do_cpld(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  86{
  87        struct udevice *dev;
  88        u32 addr, val;
  89        int ret;
  90
  91        ret = uclass_get_device_by_driver(UCLASS_SYSRESET,
  92                                          DM_GET_DRIVER(sysreset_renesas_ulcb),
  93                                          &dev);
  94        if (ret)
  95                return ret;
  96
  97        if (argc == 2 && strcmp(argv[1], "info") == 0) {
  98                printf("CPLD version:\t\t\t0x%08x\n",
  99                       cpld_read(dev, CPLD_ADDR_VERSION));
 100                printf("H3 Mode setting (MD0..28):\t0x%08x\n",
 101                       cpld_read(dev, CPLD_ADDR_MODE));
 102                printf("Multiplexer settings:\t\t0x%08x\n",
 103                       cpld_read(dev, CPLD_ADDR_MUX));
 104                printf("DIPSW (SW6):\t\t\t0x%08x\n",
 105                       cpld_read(dev, CPLD_ADDR_DIPSW6));
 106                return 0;
 107        }
 108
 109        if (argc < 3)
 110                return CMD_RET_USAGE;
 111
 112        addr = simple_strtoul(argv[2], NULL, 16);
 113        if (!(addr == CPLD_ADDR_VERSION || addr == CPLD_ADDR_MODE ||
 114              addr == CPLD_ADDR_MUX || addr == CPLD_ADDR_DIPSW6 ||
 115              addr == CPLD_ADDR_RESET)) {
 116                printf("Invalid CPLD register address\n");
 117                return CMD_RET_USAGE;
 118        }
 119
 120        if (argc == 3 && strcmp(argv[1], "read") == 0) {
 121                printf("0x%x\n", cpld_read(dev, addr));
 122        } else if (argc == 4 && strcmp(argv[1], "write") == 0) {
 123                val = simple_strtoul(argv[3], NULL, 16);
 124                cpld_write(dev, addr, val);
 125        }
 126
 127        return 0;
 128}
 129
 130U_BOOT_CMD(
 131        cpld, 4, 1, do_cpld,
 132        "CPLD access",
 133        "info\n"
 134        "cpld read addr\n"
 135        "cpld write addr val\n"
 136);
 137
 138static int renesas_ulcb_sysreset_request(struct udevice *dev, enum sysreset_t type)
 139{
 140        cpld_write(dev, CPLD_ADDR_RESET, 1);
 141
 142        return -EINPROGRESS;
 143}
 144
 145static int renesas_ulcb_sysreset_probe(struct udevice *dev)
 146{
 147        struct renesas_ulcb_sysreset_priv *priv = dev_get_priv(dev);
 148
 149        if (gpio_request_by_name(dev, "gpio-miso", 0, &priv->miso,
 150                                 GPIOD_IS_IN))
 151                return -EINVAL;
 152
 153        if (gpio_request_by_name(dev, "gpio-sck", 0, &priv->sck,
 154                                 GPIOD_IS_OUT))
 155                return -EINVAL;
 156
 157        if (gpio_request_by_name(dev, "gpio-sstbz", 0, &priv->sstbz,
 158                                 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE))
 159                return -EINVAL;
 160
 161        if (gpio_request_by_name(dev, "gpio-mosi", 0, &priv->mosi,
 162                                 GPIOD_IS_OUT))
 163                return -EINVAL;
 164
 165        /* PULL-UP on MISO line */
 166        setbits_le32(PFC_PUEN5, PUEN_SSI_SDATA4);
 167
 168        /* Dummy read */
 169        cpld_read(dev, CPLD_ADDR_VERSION);
 170
 171        return 0;
 172}
 173
 174static struct sysreset_ops renesas_ulcb_sysreset = {
 175        .request        = renesas_ulcb_sysreset_request,
 176};
 177
 178static const struct udevice_id renesas_ulcb_sysreset_ids[] = {
 179        { .compatible = "renesas,ulcb-cpld" },
 180        { }
 181};
 182
 183U_BOOT_DRIVER(sysreset_renesas_ulcb) = {
 184        .name           = "renesas_ulcb_sysreset",
 185        .id             = UCLASS_SYSRESET,
 186        .ops            = &renesas_ulcb_sysreset,
 187        .probe          = renesas_ulcb_sysreset_probe,
 188        .of_match       = renesas_ulcb_sysreset_ids,
 189        .priv_auto_alloc_size = sizeof(struct renesas_ulcb_sysreset_priv),
 190};
 191