dpdk/drivers/raw/ifpga/base/opae_spi.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2019 Intel Corporation
   3 */
   4
   5#include "opae_osdep.h"
   6#include "opae_spi.h"
   7
   8static int nios_spi_indirect_read(struct altera_spi_device *dev, u32 reg,
   9                u32 *val)
  10{
  11        u64 ctrl = 0;
  12        u64 stat = 0;
  13        int loops = SPI_MAX_RETRY;
  14
  15        ctrl = NIOS_SPI_RD | ((u64)reg << 32);
  16        opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL);
  17
  18        stat = opae_readq(dev->regs + NIOS_SPI_STAT);
  19        while (!(stat & NIOS_SPI_VALID) && --loops)
  20                stat = opae_readq(dev->regs + NIOS_SPI_STAT);
  21
  22        *val = stat & NIOS_SPI_READ_DATA;
  23
  24        return loops ? 0 : -ETIMEDOUT;
  25}
  26
  27static int nios_spi_indirect_write(struct altera_spi_device *dev, u32 reg,
  28                u32 value)
  29{
  30
  31        u64 ctrl = 0;
  32        u64 stat = 0;
  33        int loops = SPI_MAX_RETRY;
  34
  35        ctrl |= NIOS_SPI_WR | (u64)reg << 32;
  36        ctrl |= value & NIOS_SPI_WRITE_DATA;
  37
  38        opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL);
  39
  40        stat = opae_readq(dev->regs + NIOS_SPI_STAT);
  41        while (!(stat & NIOS_SPI_VALID) && --loops)
  42                stat = opae_readq(dev->regs + NIOS_SPI_STAT);
  43
  44        return loops ? 0 : -ETIMEDOUT;
  45}
  46
  47static int spi_indirect_write(struct altera_spi_device *dev, u32 reg,
  48                u32 value)
  49{
  50        u64 ctrl;
  51
  52        opae_writeq(value & WRITE_DATA_MASK, dev->regs + SPI_WRITE);
  53
  54        ctrl = CTRL_W | (reg >> 2);
  55        opae_writeq(ctrl, dev->regs + SPI_CTRL);
  56
  57        return 0;
  58}
  59
  60static int spi_indirect_read(struct altera_spi_device *dev, u32 reg,
  61                u32 *val)
  62{
  63        u64 tmp;
  64        u64 ctrl;
  65
  66        ctrl = CTRL_R | (reg >> 2);
  67        opae_writeq(ctrl, dev->regs + SPI_CTRL);
  68
  69        /**
  70         *  FIXME: Read one more time to avoid HW timing issue. This is
  71         *  a short term workaround solution, and must be removed once
  72         *  hardware fixing is done.
  73         */
  74        tmp = opae_readq(dev->regs + SPI_READ);
  75
  76        *val = (u32)tmp;
  77
  78        return 0;
  79}
  80
  81int spi_reg_write(struct altera_spi_device *dev, u32 reg,
  82                u32 value)
  83{
  84        return dev->reg_write(dev, reg, value);
  85}
  86
  87int spi_reg_read(struct altera_spi_device *dev, u32 reg,
  88                u32 *val)
  89{
  90        return dev->reg_read(dev, reg, val);
  91}
  92
  93void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select)
  94{
  95        spi_reg_write(dev, ALTERA_SPI_SLAVE_SEL, 1 << chip_select);
  96        spi_reg_write(dev, ALTERA_SPI_CONTROL, ALTERA_SPI_CONTROL_SSO_MSK);
  97}
  98
  99void spi_cs_deactivate(struct altera_spi_device *dev)
 100{
 101        spi_reg_write(dev, ALTERA_SPI_CONTROL, 0);
 102}
 103
 104static int spi_flush_rx(struct altera_spi_device *dev)
 105{
 106        u32 val = 0;
 107        int ret;
 108
 109        ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &val);
 110        if (ret)
 111                return ret;
 112
 113        if (val & ALTERA_SPI_STATUS_RRDY_MSK) {
 114                ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &val);
 115                if (ret)
 116                        return ret;
 117        }
 118
 119        return 0;
 120}
 121
 122static unsigned int spi_write_bytes(struct altera_spi_device *dev, int count)
 123{
 124        unsigned int val = 0;
 125        u16 *p16;
 126        u32 *p32;
 127
 128        if (dev->txbuf) {
 129                switch (dev->data_width) {
 130                case 1:
 131                        val = dev->txbuf[count];
 132                        break;
 133                case 2:
 134                        p16 = (u16 *)(dev->txbuf + 2*count);
 135                        val = *p16;
 136                        if (dev->endian == SPI_BIG_ENDIAN)
 137                                val = cpu_to_be16(val);
 138                        break;
 139                case 4:
 140                        p32 = (u32 *)(dev->txbuf + 4*count);
 141                        val = *p32;
 142                        break;
 143                }
 144        }
 145
 146        return val;
 147}
 148
 149static void spi_fill_readbuffer(struct altera_spi_device *dev,
 150                unsigned int value, int count)
 151{
 152        u16 *p16;
 153        u32 *p32;
 154
 155        if (dev->rxbuf) {
 156                switch (dev->data_width) {
 157                case 1:
 158                        dev->rxbuf[count] = value;
 159                        break;
 160                case 2:
 161                        p16 = (u16 *)(dev->rxbuf + 2*count);
 162                        if (dev->endian == SPI_BIG_ENDIAN)
 163                                *p16 = cpu_to_be16((u16)value);
 164                        else
 165                                *p16 = (u16)value;
 166                        break;
 167                case 4:
 168                        p32 = (u32 *)(dev->rxbuf + 4*count);
 169                        if (dev->endian == SPI_BIG_ENDIAN)
 170                                *p32 = cpu_to_be32(value);
 171                        else
 172                                *p32 = value;
 173                        break;
 174                }
 175        }
 176}
 177
 178static int spi_txrx(struct altera_spi_device *dev)
 179{
 180        unsigned int count = 0;
 181        u32 rxd;
 182        unsigned int tx_data;
 183        u32 status;
 184        int ret;
 185
 186        while (count < dev->len) {
 187                tx_data = spi_write_bytes(dev, count);
 188                spi_reg_write(dev, ALTERA_SPI_TXDATA, tx_data);
 189
 190                while (1) {
 191                        ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &status);
 192                        if (ret)
 193                                return -EIO;
 194                        if (status & ALTERA_SPI_STATUS_RRDY_MSK)
 195                                break;
 196                }
 197
 198                ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &rxd);
 199                if (ret)
 200                        return -EIO;
 201
 202                spi_fill_readbuffer(dev, rxd, count);
 203
 204                count++;
 205        }
 206
 207        return 0;
 208}
 209
 210int spi_command(struct altera_spi_device *dev, unsigned int chip_select,
 211                unsigned int wlen, void *wdata,
 212                unsigned int rlen, void *rdata)
 213{
 214        if (((wlen > 0) && !wdata) || ((rlen > 0) && !rdata)) {
 215                dev_err(dev, "error on spi command checking\n");
 216                return -EINVAL;
 217        }
 218
 219        wlen = wlen / dev->data_width;
 220        rlen = rlen / dev->data_width;
 221
 222        /* flush rx buffer */
 223        spi_flush_rx(dev);
 224
 225        spi_cs_activate(dev, chip_select);
 226        if (wlen) {
 227                dev->txbuf = wdata;
 228                dev->rxbuf = rdata;
 229                dev->len = wlen;
 230                spi_txrx(dev);
 231        }
 232        if (rlen) {
 233                dev->rxbuf = rdata;
 234                dev->txbuf = NULL;
 235                dev->len = rlen;
 236                spi_txrx(dev);
 237        }
 238        spi_cs_deactivate(dev);
 239        return 0;
 240}
 241
 242struct altera_spi_device *altera_spi_alloc(void *base, int type)
 243{
 244        struct altera_spi_device *spi_dev =
 245                opae_malloc(sizeof(struct altera_spi_device));
 246
 247        if (!spi_dev)
 248                return NULL;
 249
 250        spi_dev->regs = base;
 251
 252        switch (type) {
 253        case TYPE_SPI:
 254                spi_dev->reg_read = spi_indirect_read;
 255                spi_dev->reg_write = spi_indirect_write;
 256                break;
 257        case TYPE_NIOS_SPI:
 258                spi_dev->reg_read = nios_spi_indirect_read;
 259                spi_dev->reg_write = nios_spi_indirect_write;
 260                break;
 261        default:
 262                dev_err(dev, "%s: invalid SPI type\n", __func__);
 263                goto error;
 264        }
 265
 266        return spi_dev;
 267
 268error:
 269        altera_spi_release(spi_dev);
 270        return NULL;
 271}
 272
 273void altera_spi_init(struct altera_spi_device *spi_dev)
 274{
 275        spi_dev->spi_param.info = opae_readq(spi_dev->regs + SPI_CORE_PARAM);
 276
 277        spi_dev->data_width = spi_dev->spi_param.data_width / 8;
 278        spi_dev->endian = spi_dev->spi_param.endian;
 279        spi_dev->num_chipselect = spi_dev->spi_param.num_chipselect;
 280        dev_info(spi_dev, "spi param: type=%d, data width:%d, endian:%d, clock_polarity=%d, clock=%dMHz, chips=%d, cpha=%d\n",
 281                        spi_dev->spi_param.type,
 282                        spi_dev->data_width, spi_dev->endian,
 283                        spi_dev->spi_param.clock_polarity,
 284                        spi_dev->spi_param.clock,
 285                        spi_dev->num_chipselect,
 286                        spi_dev->spi_param.clock_phase);
 287
 288        if (spi_dev->mutex)
 289                pthread_mutex_lock(spi_dev->mutex);
 290        /* clear */
 291        spi_reg_write(spi_dev, ALTERA_SPI_CONTROL, 0);
 292        spi_reg_write(spi_dev, ALTERA_SPI_STATUS, 0);
 293        /* flush rxdata */
 294        spi_flush_rx(spi_dev);
 295        if (spi_dev->mutex)
 296                pthread_mutex_unlock(spi_dev->mutex);
 297}
 298
 299void altera_spi_release(struct altera_spi_device *dev)
 300{
 301        if (dev)
 302                opae_free(dev);
 303}
 304