uboot/drivers/spi/bcm63xx_spi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
   4 *
   5 * Derived from linux/drivers/spi/spi-bcm63xx.c:
   6 *      Copyright (C) 2009-2012 Florian Fainelli <florian@openwrt.org>
   7 *      Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
   8 */
   9
  10#include <common.h>
  11#include <clk.h>
  12#include <dm.h>
  13#include <log.h>
  14#include <malloc.h>
  15#include <spi.h>
  16#include <reset.h>
  17#include <wait_bit.h>
  18#include <asm/io.h>
  19
  20/* BCM6348 SPI core */
  21#define SPI_6348_CLK                    0x06
  22#define SPI_6348_CMD                    0x00
  23#define SPI_6348_CTL                    0x40
  24#define SPI_6348_CTL_SHIFT              6
  25#define SPI_6348_FILL                   0x07
  26#define SPI_6348_IR_MASK                0x04
  27#define SPI_6348_IR_STAT                0x02
  28#define SPI_6348_RX                     0x80
  29#define SPI_6348_RX_SIZE                0x3f
  30#define SPI_6348_TX                     0x41
  31#define SPI_6348_TX_SIZE                0x3f
  32
  33/* BCM6358 SPI core */
  34#define SPI_6358_CLK                    0x706
  35#define SPI_6358_CMD                    0x700
  36#define SPI_6358_CTL                    0x000
  37#define SPI_6358_CTL_SHIFT              14
  38#define SPI_6358_FILL                   0x707
  39#define SPI_6358_IR_MASK                0x702
  40#define SPI_6358_IR_STAT                0x704
  41#define SPI_6358_RX                     0x400
  42#define SPI_6358_RX_SIZE                0x220
  43#define SPI_6358_TX                     0x002
  44#define SPI_6358_TX_SIZE                0x21e
  45
  46/* SPI Clock register */
  47#define SPI_CLK_SHIFT           0
  48#define SPI_CLK_20MHZ           (0 << SPI_CLK_SHIFT)
  49#define SPI_CLK_0_391MHZ        (1 << SPI_CLK_SHIFT)
  50#define SPI_CLK_0_781MHZ        (2 << SPI_CLK_SHIFT)
  51#define SPI_CLK_1_563MHZ        (3 << SPI_CLK_SHIFT)
  52#define SPI_CLK_3_125MHZ        (4 << SPI_CLK_SHIFT)
  53#define SPI_CLK_6_250MHZ        (5 << SPI_CLK_SHIFT)
  54#define SPI_CLK_12_50MHZ        (6 << SPI_CLK_SHIFT)
  55#define SPI_CLK_25MHZ           (7 << SPI_CLK_SHIFT)
  56#define SPI_CLK_MASK            (7 << SPI_CLK_SHIFT)
  57#define SPI_CLK_SSOFF_SHIFT     3
  58#define SPI_CLK_SSOFF_2         (2 << SPI_CLK_SSOFF_SHIFT)
  59#define SPI_CLK_SSOFF_MASK      (7 << SPI_CLK_SSOFF_SHIFT)
  60#define SPI_CLK_BSWAP_SHIFT     7
  61#define SPI_CLK_BSWAP_MASK      (1 << SPI_CLK_BSWAP_SHIFT)
  62
  63/* SPI Command register */
  64#define SPI_CMD_OP_SHIFT        0
  65#define SPI_CMD_OP_START        (0x3 << SPI_CMD_OP_SHIFT)
  66#define SPI_CMD_SLAVE_SHIFT     4
  67#define SPI_CMD_SLAVE_MASK      (0xf << SPI_CMD_SLAVE_SHIFT)
  68#define SPI_CMD_PREPEND_SHIFT   8
  69#define SPI_CMD_PREPEND_BYTES   0xf
  70#define SPI_CMD_3WIRE_SHIFT     12
  71#define SPI_CMD_3WIRE_MASK      (1 << SPI_CMD_3WIRE_SHIFT)
  72
  73/* SPI Control register */
  74#define SPI_CTL_TYPE_FD_RW      0
  75#define SPI_CTL_TYPE_HD_W       1
  76#define SPI_CTL_TYPE_HD_R       2
  77
  78/* SPI Interrupt registers */
  79#define SPI_IR_DONE_SHIFT       0
  80#define SPI_IR_DONE_MASK        (1 << SPI_IR_DONE_SHIFT)
  81#define SPI_IR_RXOVER_SHIFT     1
  82#define SPI_IR_RXOVER_MASK      (1 << SPI_IR_RXOVER_SHIFT)
  83#define SPI_IR_TXUNDER_SHIFT    2
  84#define SPI_IR_TXUNDER_MASK     (1 << SPI_IR_TXUNDER_SHIFT)
  85#define SPI_IR_TXOVER_SHIFT     3
  86#define SPI_IR_TXOVER_MASK      (1 << SPI_IR_TXOVER_SHIFT)
  87#define SPI_IR_RXUNDER_SHIFT    4
  88#define SPI_IR_RXUNDER_MASK     (1 << SPI_IR_RXUNDER_SHIFT)
  89#define SPI_IR_CLEAR_MASK       (SPI_IR_DONE_MASK |\
  90                                 SPI_IR_RXOVER_MASK |\
  91                                 SPI_IR_TXUNDER_MASK |\
  92                                 SPI_IR_TXOVER_MASK |\
  93                                 SPI_IR_RXUNDER_MASK)
  94
  95enum bcm63xx_regs_spi {
  96        SPI_CLK,
  97        SPI_CMD,
  98        SPI_CTL,
  99        SPI_CTL_SHIFT,
 100        SPI_FILL,
 101        SPI_IR_MASK,
 102        SPI_IR_STAT,
 103        SPI_RX,
 104        SPI_RX_SIZE,
 105        SPI_TX,
 106        SPI_TX_SIZE,
 107};
 108
 109struct bcm63xx_spi_priv {
 110        const unsigned long *regs;
 111        void __iomem *base;
 112        size_t tx_bytes;
 113        uint8_t num_cs;
 114};
 115
 116#define SPI_CLK_CNT             8
 117static const unsigned bcm63xx_spi_freq_table[SPI_CLK_CNT][2] = {
 118        { 25000000, SPI_CLK_25MHZ },
 119        { 20000000, SPI_CLK_20MHZ },
 120        { 12500000, SPI_CLK_12_50MHZ },
 121        {  6250000, SPI_CLK_6_250MHZ },
 122        {  3125000, SPI_CLK_3_125MHZ },
 123        {  1563000, SPI_CLK_1_563MHZ },
 124        {   781000, SPI_CLK_0_781MHZ },
 125        {   391000, SPI_CLK_0_391MHZ }
 126};
 127
 128static int bcm63xx_spi_cs_info(struct udevice *bus, uint cs,
 129                           struct spi_cs_info *info)
 130{
 131        struct bcm63xx_spi_priv *priv = dev_get_priv(bus);
 132
 133        if (cs >= priv->num_cs) {
 134                printf("no cs %u\n", cs);
 135                return -EINVAL;
 136        }
 137
 138        return 0;
 139}
 140
 141static int bcm63xx_spi_set_mode(struct udevice *bus, uint mode)
 142{
 143        struct bcm63xx_spi_priv *priv = dev_get_priv(bus);
 144        const unsigned long *regs = priv->regs;
 145
 146        if (mode & SPI_LSB_FIRST)
 147                setbits_8(priv->base + regs[SPI_CLK], SPI_CLK_BSWAP_MASK);
 148        else
 149                clrbits_8(priv->base + regs[SPI_CLK], SPI_CLK_BSWAP_MASK);
 150
 151        return 0;
 152}
 153
 154static int bcm63xx_spi_set_speed(struct udevice *bus, uint speed)
 155{
 156        struct bcm63xx_spi_priv *priv = dev_get_priv(bus);
 157        const unsigned long *regs = priv->regs;
 158        uint8_t clk_cfg;
 159        int i;
 160
 161        /* default to lowest clock configuration */
 162        clk_cfg = SPI_CLK_0_391MHZ;
 163
 164        /* find the closest clock configuration */
 165        for (i = 0; i < SPI_CLK_CNT; i++) {
 166                if (speed >= bcm63xx_spi_freq_table[i][0]) {
 167                        clk_cfg = bcm63xx_spi_freq_table[i][1];
 168                        break;
 169                }
 170        }
 171
 172        /* write clock configuration */
 173        clrsetbits_8(priv->base + regs[SPI_CLK],
 174                     SPI_CLK_SSOFF_MASK | SPI_CLK_MASK,
 175                     clk_cfg | SPI_CLK_SSOFF_2);
 176
 177        return 0;
 178}
 179
 180/*
 181 * BCM63xx SPI driver doesn't allow keeping CS active between transfers since
 182 * they are HW controlled.
 183 * However, it provides a mechanism to prepend write transfers prior to read
 184 * transfers (with a maximum prepend of 15 bytes), which is usually enough for
 185 * SPI-connected flashes since reading requires prepending a write transfer of
 186 * 5 bytes.
 187 *
 188 * This implementation takes advantage of the prepend mechanism and combines
 189 * multiple transfers into a single one where possible (single/multiple write
 190 * transfer(s) followed by a final read/write transfer).
 191 * However, it's not possible to buffer reads, which means that read transfers
 192 * should always be done as the final ones.
 193 * On the other hand, take into account that combining write transfers into
 194 * a single one is just buffering and doesn't require prepend mechanism.
 195 */
 196static int bcm63xx_spi_xfer(struct udevice *dev, unsigned int bitlen,
 197                const void *dout, void *din, unsigned long flags)
 198{
 199        struct bcm63xx_spi_priv *priv = dev_get_priv(dev->parent);
 200        const unsigned long *regs = priv->regs;
 201        size_t data_bytes = bitlen / 8;
 202
 203        if (flags & SPI_XFER_BEGIN) {
 204                /* clear prepends */
 205                priv->tx_bytes = 0;
 206
 207                /* initialize hardware */
 208                writeb_be(0, priv->base + regs[SPI_IR_MASK]);
 209        }
 210
 211        if (din) {
 212                /* buffering reads not possible since cs is hw controlled */
 213                if (!(flags & SPI_XFER_END)) {
 214                        printf("unable to buffer reads\n");
 215                        return -EINVAL;
 216                }
 217
 218                /* check rx size */
 219                 if (data_bytes > regs[SPI_RX_SIZE]) {
 220                        printf("max rx bytes exceeded\n");
 221                        return -EMSGSIZE;
 222                }
 223        }
 224
 225        if (dout) {
 226                /* check tx size */
 227                if (priv->tx_bytes + data_bytes > regs[SPI_TX_SIZE]) {
 228                        printf("max tx bytes exceeded\n");
 229                        return -EMSGSIZE;
 230                }
 231
 232                /* copy tx data */
 233                memcpy_toio(priv->base + regs[SPI_TX] + priv->tx_bytes,
 234                            dout, data_bytes);
 235                priv->tx_bytes += data_bytes;
 236        }
 237
 238        if (flags & SPI_XFER_END) {
 239                struct dm_spi_slave_plat *plat =
 240                        dev_get_parent_plat(dev);
 241                uint16_t val, cmd;
 242                int ret;
 243
 244                /* determine control config */
 245                if (dout && !din) {
 246                        /* buffered write transfers */
 247                        val = priv->tx_bytes;
 248                        val |= (SPI_CTL_TYPE_HD_W << regs[SPI_CTL_SHIFT]);
 249                        priv->tx_bytes = 0;
 250                } else {
 251                        if (dout && din && (flags & SPI_XFER_ONCE)) {
 252                                /* full duplex read/write */
 253                                val = data_bytes;
 254                                val |= (SPI_CTL_TYPE_FD_RW <<
 255                                        regs[SPI_CTL_SHIFT]);
 256                                priv->tx_bytes = 0;
 257                        } else {
 258                                /* prepended write transfer */
 259                                val = data_bytes;
 260                                val |= (SPI_CTL_TYPE_HD_R <<
 261                                        regs[SPI_CTL_SHIFT]);
 262                                if (priv->tx_bytes > SPI_CMD_PREPEND_BYTES) {
 263                                        printf("max prepend bytes exceeded\n");
 264                                        return -EMSGSIZE;
 265                                }
 266                        }
 267                }
 268
 269                if (regs[SPI_CTL_SHIFT] >= 8)
 270                        writew_be(val, priv->base + regs[SPI_CTL]);
 271                else
 272                        writeb_be(val, priv->base + regs[SPI_CTL]);
 273
 274                /* clear interrupts */
 275                writeb_be(SPI_IR_CLEAR_MASK, priv->base + regs[SPI_IR_STAT]);
 276
 277                /* issue the transfer */
 278                cmd = SPI_CMD_OP_START;
 279                cmd |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK;
 280                cmd |= (priv->tx_bytes << SPI_CMD_PREPEND_SHIFT);
 281                if (plat->mode & SPI_3WIRE)
 282                        cmd |= SPI_CMD_3WIRE_MASK;
 283                writew_be(cmd, priv->base + regs[SPI_CMD]);
 284
 285                /* enable interrupts */
 286                writeb_be(SPI_IR_DONE_MASK, priv->base + regs[SPI_IR_MASK]);
 287
 288                ret = wait_for_bit_8(priv->base + regs[SPI_IR_STAT],
 289                                     SPI_IR_DONE_MASK, true, 1000, false);
 290                if (ret) {
 291                        printf("interrupt timeout\n");
 292                        return ret;
 293                }
 294
 295                /* copy rx data */
 296                if (din)
 297                        memcpy_fromio(din, priv->base + regs[SPI_RX],
 298                                      data_bytes);
 299        }
 300
 301        return 0;
 302}
 303
 304static const struct dm_spi_ops bcm63xx_spi_ops = {
 305        .cs_info = bcm63xx_spi_cs_info,
 306        .set_mode = bcm63xx_spi_set_mode,
 307        .set_speed = bcm63xx_spi_set_speed,
 308        .xfer = bcm63xx_spi_xfer,
 309};
 310
 311static const unsigned long bcm6348_spi_regs[] = {
 312        [SPI_CLK] = SPI_6348_CLK,
 313        [SPI_CMD] = SPI_6348_CMD,
 314        [SPI_CTL] = SPI_6348_CTL,
 315        [SPI_CTL_SHIFT] = SPI_6348_CTL_SHIFT,
 316        [SPI_FILL] = SPI_6348_FILL,
 317        [SPI_IR_MASK] = SPI_6348_IR_MASK,
 318        [SPI_IR_STAT] = SPI_6348_IR_STAT,
 319        [SPI_RX] = SPI_6348_RX,
 320        [SPI_RX_SIZE] = SPI_6348_RX_SIZE,
 321        [SPI_TX] = SPI_6348_TX,
 322        [SPI_TX_SIZE] = SPI_6348_TX_SIZE,
 323};
 324
 325static const unsigned long bcm6358_spi_regs[] = {
 326        [SPI_CLK] = SPI_6358_CLK,
 327        [SPI_CMD] = SPI_6358_CMD,
 328        [SPI_CTL] = SPI_6358_CTL,
 329        [SPI_CTL_SHIFT] = SPI_6358_CTL_SHIFT,
 330        [SPI_FILL] = SPI_6358_FILL,
 331        [SPI_IR_MASK] = SPI_6358_IR_MASK,
 332        [SPI_IR_STAT] = SPI_6358_IR_STAT,
 333        [SPI_RX] = SPI_6358_RX,
 334        [SPI_RX_SIZE] = SPI_6358_RX_SIZE,
 335        [SPI_TX] = SPI_6358_TX,
 336        [SPI_TX_SIZE] = SPI_6358_TX_SIZE,
 337};
 338
 339static const struct udevice_id bcm63xx_spi_ids[] = {
 340        {
 341                .compatible = "brcm,bcm6348-spi",
 342                .data = (ulong)&bcm6348_spi_regs,
 343        }, {
 344                .compatible = "brcm,bcm6358-spi",
 345                .data = (ulong)&bcm6358_spi_regs,
 346        }, { /* sentinel */ }
 347};
 348
 349static int bcm63xx_spi_child_pre_probe(struct udevice *dev)
 350{
 351        struct bcm63xx_spi_priv *priv = dev_get_priv(dev->parent);
 352        const unsigned long *regs = priv->regs;
 353        struct spi_slave *slave = dev_get_parent_priv(dev);
 354        struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
 355
 356        /* check cs */
 357        if (plat->cs >= priv->num_cs) {
 358                printf("no cs %u\n", plat->cs);
 359                return -ENODEV;
 360        }
 361
 362        /* max read/write sizes */
 363        slave->max_read_size = regs[SPI_RX_SIZE];
 364        slave->max_write_size = regs[SPI_TX_SIZE];
 365
 366        return 0;
 367}
 368
 369static int bcm63xx_spi_probe(struct udevice *dev)
 370{
 371        struct bcm63xx_spi_priv *priv = dev_get_priv(dev);
 372        const unsigned long *regs =
 373                (const unsigned long *)dev_get_driver_data(dev);
 374        struct reset_ctl rst_ctl;
 375        struct clk clk;
 376        int ret;
 377
 378        priv->base = dev_remap_addr(dev);
 379        if (!priv->base)
 380                return -EINVAL;
 381
 382        priv->regs = regs;
 383        priv->num_cs = dev_read_u32_default(dev, "num-cs", 8);
 384
 385        /* enable clock */
 386        ret = clk_get_by_index(dev, 0, &clk);
 387        if (ret < 0)
 388                return ret;
 389
 390        ret = clk_enable(&clk);
 391        if (ret < 0)
 392                return ret;
 393
 394        ret = clk_free(&clk);
 395        if (ret < 0)
 396                return ret;
 397
 398        /* perform reset */
 399        ret = reset_get_by_index(dev, 0, &rst_ctl);
 400        if (ret < 0)
 401                return ret;
 402
 403        ret = reset_deassert(&rst_ctl);
 404        if (ret < 0)
 405                return ret;
 406
 407        ret = reset_free(&rst_ctl);
 408        if (ret < 0)
 409                return ret;
 410
 411        /* initialize hardware */
 412        writeb_be(0, priv->base + regs[SPI_IR_MASK]);
 413
 414        /* set fill register */
 415        writeb_be(0xff, priv->base + regs[SPI_FILL]);
 416
 417        return 0;
 418}
 419
 420U_BOOT_DRIVER(bcm63xx_spi) = {
 421        .name = "bcm63xx_spi",
 422        .id = UCLASS_SPI,
 423        .of_match = bcm63xx_spi_ids,
 424        .ops = &bcm63xx_spi_ops,
 425        .priv_auto      = sizeof(struct bcm63xx_spi_priv),
 426        .child_pre_probe = bcm63xx_spi_child_pre_probe,
 427        .probe = bcm63xx_spi_probe,
 428};
 429