The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/xilinx/zy7_qspi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018 Thomas Skibo <thomasskibo@yahoo.com>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * This is a driver for the Quad-SPI Flash Controller in the Xilinx
   34  * Zynq-7000 SoC.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/conf.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/lock.h>
   44 #include <sys/mutex.h>
   45 #include <sys/resource.h>
   46 #include <sys/rman.h>
   47 #include <sys/uio.h>
   48 
   49 #include <machine/bus.h>
   50 #include <machine/resource.h>
   51 #include <machine/stdarg.h>
   52 
   53 #include <dev/fdt/fdt_common.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <dev/ofw/ofw_bus_subr.h>
   56 
   57 #include <dev/spibus/spi.h>
   58 #include <dev/spibus/spibusvar.h>
   59 
   60 #include <dev/flash/mx25lreg.h>
   61 
   62 #include "spibus_if.h"
   63 
   64 static struct ofw_compat_data compat_data[] = {
   65         {"xlnx,zy7_qspi",               1},
   66         {"xlnx,zynq-qspi-1.0",          1},
   67         {NULL,                          0}
   68 };
   69 
   70 struct zy7_qspi_softc {
   71         device_t                dev;
   72         device_t                child;
   73         struct mtx              sc_mtx;
   74         struct resource         *mem_res;
   75         struct resource         *irq_res;
   76         void                    *intrhandle;
   77 
   78         uint32_t                cfg_reg_shadow;
   79         uint32_t                lqspi_cfg_shadow;
   80         uint32_t                spi_clock;
   81         uint32_t                ref_clock;
   82         unsigned int            spi_clk_real_freq;
   83         unsigned int            rx_overflows;
   84         unsigned int            tx_underflows;
   85         unsigned int            interrupts;
   86         unsigned int            stray_ints;
   87         struct spi_command      *cmd;
   88         int                     tx_bytes;       /* tx_cmd_sz + tx_data_sz */
   89         int                     tx_bytes_sent;
   90         int                     rx_bytes;       /* rx_cmd_sz + rx_data_sz */
   91         int                     rx_bytes_rcvd;
   92         int                     busy;
   93         int                     is_dual;
   94         int                     is_stacked;
   95         int                     is_dio;
   96 };
   97 
   98 #define ZY7_QSPI_DEFAULT_SPI_CLOCK      50000000
   99 
  100 #define QSPI_SC_LOCK(sc)                mtx_lock(&(sc)->sc_mtx)
  101 #define QSPI_SC_UNLOCK(sc)              mtx_unlock(&(sc)->sc_mtx)
  102 #define QSPI_SC_LOCK_INIT(sc) \
  103         mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), NULL, MTX_DEF)
  104 #define QSPI_SC_LOCK_DESTROY(sc)        mtx_destroy(&(sc)->sc_mtx)
  105 #define QSPI_SC_ASSERT_LOCKED(sc)       mtx_assert(&(sc)->sc_mtx, MA_OWNED)
  106 
  107 #define RD4(sc, off)            (bus_read_4((sc)->mem_res, (off)))
  108 #define WR4(sc, off, val)       (bus_write_4((sc)->mem_res, (off), (val)))
  109 
  110 /*
  111  * QSPI device registers.
  112  * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
  113  * (v1.12.2) July 1, 2018.  Xilinx doc UG585.
  114  */
  115 #define ZY7_QSPI_CONFIG_REG             0x0000
  116 #define   ZY7_QSPI_CONFIG_IFMODE                (1U << 31)
  117 #define   ZY7_QSPI_CONFIG_ENDIAN                (1 << 26)
  118 #define   ZY7_QSPI_CONFIG_HOLDB_DR              (1 << 19)
  119 #define   ZY7_QSPI_CONFIG_RSVD1                 (1 << 17) /* must be 1 */
  120 #define   ZY7_QSPI_CONFIG_MANSTRT               (1 << 16)
  121 #define   ZY7_QSPI_CONFIG_MANSTRTEN             (1 << 15)
  122 #define   ZY7_QSPI_CONFIG_SSFORCE               (1 << 14)
  123 #define   ZY7_QSPI_CONFIG_PCS                   (1 << 10)
  124 #define   ZY7_QSPI_CONFIG_REF_CLK               (1 << 8)
  125 #define   ZY7_QSPI_CONFIG_FIFO_WIDTH_MASK       (3 << 6)
  126 #define   ZY7_QSPI_CONFIG_FIFO_WIDTH32          (3 << 6)
  127 #define   ZY7_QSPI_CONFIG_BAUD_RATE_DIV_MASK    (7 << 3)
  128 #define   ZY7_QSPI_CONFIG_BAUD_RATE_DIV_SHIFT   3
  129 #define   ZY7_QSPI_CONFIG_BAUD_RATE_DIV(x)      ((x) << 3) /* divide by 2<<x */
  130 #define   ZY7_QSPI_CONFIG_CLK_PH                (1 << 2)   /* clock phase */
  131 #define   ZY7_QSPI_CONFIG_CLK_POL               (1 << 1)   /* clock polarity */
  132 #define   ZY7_QSPI_CONFIG_MODE_SEL              (1 << 0)   /* master enable */
  133 
  134 #define ZY7_QSPI_INTR_STAT_REG          0x0004
  135 #define ZY7_QSPI_INTR_EN_REG            0x0008
  136 #define ZY7_QSPI_INTR_DIS_REG           0x000c
  137 #define ZY7_QSPI_INTR_MASK_REG          0x0010
  138 #define   ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW       (1 << 6)
  139 #define   ZY7_QSPI_INTR_RX_FIFO_FULL            (1 << 5)
  140 #define   ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY       (1 << 4)
  141 #define   ZY7_QSPI_INTR_TX_FIFO_FULL            (1 << 3)
  142 #define   ZY7_QSPI_INTR_TX_FIFO_NOT_FULL        (1 << 2)
  143 #define   ZY7_QSPI_INTR_RX_OVERFLOW             (1 << 0)
  144 
  145 #define ZY7_QSPI_EN_REG                 0x0014
  146 #define   ZY7_SPI_ENABLE                        1
  147 
  148 #define ZY7_QSPI_DELAY_REG              0x0018
  149 #define   ZY7_QSPI_DELAY_NSS_MASK               (0xffU << 24)
  150 #define   ZY7_QSPI_DELAY_NSS_SHIFT              24
  151 #define   ZY7_QSPI_DELAY_NSS(x)                 ((x) << 24)
  152 #define   ZY7_QSPI_DELAY_BTWN_MASK              (0xff << 16)
  153 #define   ZY7_QSPI_DELAY_BTWN_SHIFT             16
  154 #define   ZY7_QSPI_DELAY_BTWN(x)                ((x) << 16)
  155 #define   ZY7_QSPI_DELAY_AFTER_MASK             (0xff << 8)
  156 #define   ZY7_QSPI_DELAY_AFTER_SHIFT            8
  157 #define   ZY7_QSPI_DELAY_AFTER(x)               ((x) << 8)
  158 #define   ZY7_QSPI_DELAY_INIT_MASK              0xff
  159 #define   ZY7_QSPI_DELAY_INIT_SHIFT             0
  160 #define   ZY7_QSPI_DELAY_INIT(x)                (x)
  161 
  162 #define ZY7_QSPI_TXD0_REG               0x001c
  163 #define ZY7_QSPI_RX_DATA_REG            0x0020
  164 
  165 #define ZY7_QSPI_SLV_IDLE_CT_REG        0x0024
  166 #define   ZY7_QSPI_SLV_IDLE_CT_MASK             0xff
  167 
  168 #define ZY7_QSPI_TX_THRESH_REG          0x0028
  169 #define ZY7_QSPI_RX_THRESH_REG          0x002c
  170 
  171 #define ZY7_QSPI_GPIO_REG               0x0030
  172 #define   ZY7_QSPI_GPIO_WP_N                    1
  173 
  174 #define ZY7_QSPI_LPBK_DLY_ADJ_REG       0x0038
  175 #define   ZY7_QSPI_LPBK_DLY_ADJ_LPBK_SEL        (1 << 8)
  176 #define   ZY7_QSPI_LPBK_DLY_ADJ_LPBK_PH         (1 << 7)
  177 #define   ZY7_QSPI_LPBK_DLY_ADJ_USE_LPBK        (1 << 5)
  178 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY1_MASK       (3 << 3)
  179 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY1_SHIFT      3
  180 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY1(x)         ((x) << 3)
  181 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY0_MASK       7
  182 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY0_SHIFT      0
  183 #define   ZY7_QSPI_LPBK_DLY_ADJ_DLY0(x)         (x)
  184 
  185 #define ZY7_QSPI_TXD1_REG               0x0080
  186 #define ZY7_QSPI_TXD2_REG               0x0084
  187 #define ZY7_QSPI_TXD3_REG               0x0088
  188 
  189 #define ZY7_QSPI_LQSPI_CFG_REG          0x00a0
  190 #define   ZY7_QSPI_LQSPI_CFG_LINEAR             (1U << 31)
  191 #define   ZY7_QSPI_LQSPI_CFG_TWO_MEM            (1 << 30)
  192 #define   ZY7_QSPI_LQSPI_CFG_SEP_BUS            (1 << 29)
  193 #define   ZY7_QSPI_LQSPI_CFG_U_PAGE             (1 << 28)
  194 #define   ZY7_QSPI_LQSPI_CFG_MODE_EN            (1 << 25)
  195 #define   ZY7_QSPI_LQSPI_CFG_MODE_ON            (1 << 24)
  196 #define   ZY7_QSPI_LQSPI_CFG_MODE_BITS_MASK     (0xff << 16)
  197 #define   ZY7_QSPI_LQSPI_CFG_MODE_BITS_SHIFT    16
  198 #define   ZY7_QSPI_LQSPI_CFG_MODE_BITS(x)       ((x) << 16)
  199 #define   ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES_MASK   (7 << 8)
  200 #define   ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES_SHIFT  8
  201 #define   ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES(x)     ((x) << 8)
  202 #define   ZY7_QSPI_LQSPI_CFG_INST_CODE_MASK     0xff
  203 #define   ZY7_QSPI_LQSPI_CFG_INST_CODE_SHIFT    0
  204 #define   ZY7_QSPI_LQSPI_CFG_INST_CODE(x)       (x)
  205 
  206 #define ZY7_QSPI_LQSPI_STS_REG          0x00a4
  207 #define   ZY7_QSPI_LQSPI_STS_D_FSM_ERR          (1 << 2)
  208 #define   ZY7_QSPI_LQSPI_STS_WR_RECVD           (1 << 1)
  209 
  210 #define ZY7_QSPI_MOD_ID_REG             0x00fc
  211 
  212 static int zy7_qspi_detach(device_t);
  213 
  214 /* Fill hardware fifo with command and data bytes. */
  215 static void
  216 zy7_qspi_write_fifo(struct zy7_qspi_softc *sc, int nbytes)
  217 {
  218         int n, nvalid;
  219         uint32_t data;
  220 
  221         while (nbytes > 0) {
  222                 nvalid = MIN(4, nbytes);
  223                 data = 0xffffffff;
  224 
  225                 /*
  226                  * A hardware bug forces us to wait until the tx fifo is
  227                  * empty before writing partial words.  We'll come back
  228                  * next tx interrupt.
  229                  */
  230                 if (nvalid < 4 && (RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
  231                     ZY7_QSPI_INTR_TX_FIFO_NOT_FULL) == 0)
  232                         return;
  233 
  234                 if (sc->tx_bytes_sent < sc->cmd->tx_cmd_sz) {
  235                         /* Writing command. */
  236                         n = MIN(nvalid, sc->cmd->tx_cmd_sz -
  237                             sc->tx_bytes_sent);
  238                         memcpy(&data, (uint8_t *)sc->cmd->tx_cmd +
  239                             sc->tx_bytes_sent, n);
  240 
  241                         if (nvalid > n) {
  242                                 /* Writing start of data. */
  243                                 memcpy((uint8_t *)&data + n,
  244                                     sc->cmd->tx_data, nvalid - n);
  245                         }
  246                 } else
  247                         /* Writing data. */
  248                         memcpy(&data, (uint8_t *)sc->cmd->tx_data +
  249                             (sc->tx_bytes_sent - sc->cmd->tx_cmd_sz), nvalid);
  250 
  251                 switch (nvalid) {
  252                 case 1:
  253                         WR4(sc, ZY7_QSPI_TXD1_REG, data);
  254                         break;
  255                 case 2:
  256                         WR4(sc, ZY7_QSPI_TXD2_REG, data);
  257                         break;
  258                 case 3:
  259                         WR4(sc, ZY7_QSPI_TXD3_REG, data);
  260                         break;
  261                 case 4:
  262                         WR4(sc, ZY7_QSPI_TXD0_REG, data);
  263                         break;
  264                 }
  265 
  266                 sc->tx_bytes_sent += nvalid;
  267                 nbytes -= nvalid;
  268         }
  269 }
  270 
  271 /* Read hardware fifo data into command response and data buffers. */
  272 static void
  273 zy7_qspi_read_fifo(struct zy7_qspi_softc *sc)
  274 {
  275         int n, nbytes;
  276         uint32_t data;
  277 
  278         do {
  279                 data = RD4(sc, ZY7_QSPI_RX_DATA_REG);
  280                 nbytes = MIN(4, sc->rx_bytes - sc->rx_bytes_rcvd);
  281 
  282                 /*
  283                  * Last word in non-word-multiple transfer is packed
  284                  * non-intuitively.
  285                  */
  286                 if (nbytes < 4)
  287                         data >>= 8 * (4 - nbytes);
  288 
  289                 if (sc->rx_bytes_rcvd < sc->cmd->rx_cmd_sz) {
  290                         /* Reading command. */
  291                         n = MIN(nbytes, sc->cmd->rx_cmd_sz -
  292                             sc->rx_bytes_rcvd);
  293                         memcpy((uint8_t *)sc->cmd->rx_cmd + sc->rx_bytes_rcvd,
  294                             &data, n);
  295                         sc->rx_bytes_rcvd += n;
  296                         nbytes -= n;
  297                         data >>= 8 * n;
  298                 }
  299 
  300                 if (nbytes > 0) {
  301                         /* Reading data. */
  302                         memcpy((uint8_t *)sc->cmd->rx_data +
  303                             (sc->rx_bytes_rcvd - sc->cmd->rx_cmd_sz),
  304                             &data, nbytes);
  305                         sc->rx_bytes_rcvd += nbytes;
  306                 }
  307 
  308         } while (sc->rx_bytes_rcvd < sc->rx_bytes &&
  309                  (RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
  310                   ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0);
  311 }
  312 
  313 /* End a transfer early by draining rx fifo and disabling interrupts. */
  314 static void
  315 zy7_qspi_abort_transfer(struct zy7_qspi_softc *sc)
  316 {
  317         /* Drain receive fifo. */
  318         while ((RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
  319                 ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0)
  320                 (void)RD4(sc, ZY7_QSPI_RX_DATA_REG);
  321 
  322         /* Shut down interrupts. */
  323         WR4(sc, ZY7_QSPI_INTR_DIS_REG,
  324             ZY7_QSPI_INTR_RX_OVERFLOW |
  325             ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY |
  326             ZY7_QSPI_INTR_TX_FIFO_NOT_FULL);
  327 }
  328 
  329 static void
  330 zy7_qspi_intr(void *arg)
  331 {
  332         struct zy7_qspi_softc *sc = (struct zy7_qspi_softc *)arg;
  333         uint32_t istatus;
  334 
  335         QSPI_SC_LOCK(sc);
  336 
  337         sc->interrupts++;
  338 
  339         istatus = RD4(sc, ZY7_QSPI_INTR_STAT_REG);
  340 
  341         /* Stray interrupts can happen if a transfer gets interrupted. */
  342         if (!sc->busy) {
  343                 sc->stray_ints++;
  344                 QSPI_SC_UNLOCK(sc);
  345                 return;
  346         }
  347 
  348         if ((istatus & ZY7_QSPI_INTR_RX_OVERFLOW) != 0) {
  349                 device_printf(sc->dev, "rx fifo overflow!\n");
  350                 sc->rx_overflows++;
  351 
  352                 /* Clear status bit. */
  353                 WR4(sc, ZY7_QSPI_INTR_STAT_REG,
  354                     ZY7_QSPI_INTR_RX_OVERFLOW);
  355         }
  356 
  357         /* Empty receive fifo before any more transmit data is sent. */
  358         if (sc->rx_bytes_rcvd < sc->rx_bytes &&
  359             (istatus & ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0) {
  360                 zy7_qspi_read_fifo(sc);
  361                 if (sc->rx_bytes_rcvd == sc->rx_bytes)
  362                         /* Disable receive interrupts. */
  363                         WR4(sc, ZY7_QSPI_INTR_DIS_REG,
  364                             ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY |
  365                             ZY7_QSPI_INTR_RX_OVERFLOW);
  366         }
  367 
  368         /*
  369          * Transmit underflows aren't really a bug because a hardware
  370          * bug forces us to allow the tx fifo to go empty between full
  371          * and partial fifo writes.  Why bother counting?
  372          */
  373         if ((istatus & ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW) != 0) {
  374                 sc->tx_underflows++;
  375 
  376                 /* Clear status bit. */
  377                 WR4(sc, ZY7_QSPI_INTR_STAT_REG,
  378                     ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW);
  379         }
  380 
  381         /* Fill transmit fifo. */
  382         if (sc->tx_bytes_sent < sc->tx_bytes &&
  383             (istatus & ZY7_QSPI_INTR_TX_FIFO_NOT_FULL) != 0) {
  384                 zy7_qspi_write_fifo(sc, MIN(240, sc->tx_bytes -
  385                         sc->tx_bytes_sent));
  386 
  387                 if (sc->tx_bytes_sent == sc->tx_bytes) {
  388                         /*
  389                          * Disable transmit FIFO interrupt, enable receive
  390                          * FIFO interrupt.
  391                          */
  392                         WR4(sc, ZY7_QSPI_INTR_DIS_REG,
  393                             ZY7_QSPI_INTR_TX_FIFO_NOT_FULL);
  394                         WR4(sc, ZY7_QSPI_INTR_EN_REG,
  395                             ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY);
  396                 }
  397         }
  398 
  399         /* Finished with transfer? */
  400         if (sc->tx_bytes_sent == sc->tx_bytes &&
  401             sc->rx_bytes_rcvd == sc->rx_bytes) {
  402                 /* De-assert CS. */
  403                 sc->cfg_reg_shadow |= ZY7_QSPI_CONFIG_PCS;
  404                 WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
  405 
  406                 wakeup(sc->dev);
  407         }
  408 
  409         QSPI_SC_UNLOCK(sc);
  410 }
  411 
  412 /* Initialize hardware. */
  413 static int
  414 zy7_qspi_init_hw(struct zy7_qspi_softc *sc)
  415 {
  416         uint32_t baud_div;
  417 
  418         /* Configure LQSPI Config register.  Disable linear mode. */
  419         sc->lqspi_cfg_shadow = RD4(sc, ZY7_QSPI_LQSPI_CFG_REG);
  420         sc->lqspi_cfg_shadow &= ~(ZY7_QSPI_LQSPI_CFG_LINEAR |
  421                                   ZY7_QSPI_LQSPI_CFG_TWO_MEM |
  422                                   ZY7_QSPI_LQSPI_CFG_SEP_BUS);
  423         if (sc->is_dual) {
  424                 sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_TWO_MEM;
  425                 if (sc->is_stacked) {
  426                         sc->lqspi_cfg_shadow &=
  427                             ~ZY7_QSPI_LQSPI_CFG_INST_CODE_MASK;
  428                         sc->lqspi_cfg_shadow |=
  429                             ZY7_QSPI_LQSPI_CFG_INST_CODE(sc->is_dio ?
  430                                 CMD_READ_DUAL_IO : CMD_READ_QUAD_OUTPUT);
  431                 } else
  432                         sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_SEP_BUS;
  433         }
  434         WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow);
  435 
  436         /* Find best clock divider. */
  437         baud_div = 0;
  438         while ((sc->ref_clock >> (baud_div + 1)) > sc->spi_clock &&
  439                baud_div < 8)
  440                 baud_div++;
  441         if (baud_div >= 8) {
  442                 device_printf(sc->dev, "cannot configure clock divider: ref=%d"
  443                     " spi=%d.\n", sc->ref_clock, sc->spi_clock);
  444                 return (EINVAL);
  445         }
  446         sc->spi_clk_real_freq = sc->ref_clock >> (baud_div + 1);
  447 
  448         /*
  449          * If divider is 2 (the max speed), use internal loopback master
  450          * clock for read data.  (See section 12.3.1 in ref man.)
  451          */
  452         if (baud_div == 0)
  453                 WR4(sc, ZY7_QSPI_LPBK_DLY_ADJ_REG,
  454                     ZY7_QSPI_LPBK_DLY_ADJ_USE_LPBK |
  455                     ZY7_QSPI_LPBK_DLY_ADJ_DLY1(0) |
  456                     ZY7_QSPI_LPBK_DLY_ADJ_DLY0(0));
  457         else
  458                 WR4(sc, ZY7_QSPI_LPBK_DLY_ADJ_REG, 0);
  459 
  460         /* Set up configuration register. */
  461         sc->cfg_reg_shadow =
  462                 ZY7_QSPI_CONFIG_IFMODE |
  463                 ZY7_QSPI_CONFIG_HOLDB_DR |
  464                 ZY7_QSPI_CONFIG_RSVD1 |
  465                 ZY7_QSPI_CONFIG_SSFORCE |
  466                 ZY7_QSPI_CONFIG_PCS |
  467                 ZY7_QSPI_CONFIG_FIFO_WIDTH32 |
  468                 ZY7_QSPI_CONFIG_BAUD_RATE_DIV(baud_div) |
  469                 ZY7_QSPI_CONFIG_MODE_SEL;
  470         WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
  471 
  472         /*
  473          * Set thresholds.  We must use 1 for tx threshold because there
  474          * is no fifo empty flag and we need one to implement a bug
  475          * workaround.
  476          */
  477         WR4(sc, ZY7_QSPI_TX_THRESH_REG, 1);
  478         WR4(sc, ZY7_QSPI_RX_THRESH_REG, 1);
  479 
  480         /* Clear and disable all interrupts. */
  481         WR4(sc, ZY7_QSPI_INTR_STAT_REG, ~0);
  482         WR4(sc, ZY7_QSPI_INTR_DIS_REG, ~0);
  483 
  484         /* Enable SPI. */
  485         WR4(sc, ZY7_QSPI_EN_REG, ZY7_SPI_ENABLE);
  486 
  487         return (0);
  488 }
  489 
  490 static void
  491 zy7_qspi_add_sysctls(device_t dev)
  492 {
  493         struct zy7_qspi_softc *sc = device_get_softc(dev);
  494         struct sysctl_ctx_list *ctx;
  495         struct sysctl_oid_list *child;
  496 
  497         ctx = device_get_sysctl_ctx(dev);
  498         child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
  499 
  500         SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "spi_clk_real_freq", CTLFLAG_RD,
  501             &sc->spi_clk_real_freq, 0, "SPI clock real frequency");
  502 
  503         SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overflows", CTLFLAG_RD,
  504             &sc->rx_overflows, 0, "RX FIFO overflow events");
  505 
  506         SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_underflows", CTLFLAG_RD,
  507             &sc->tx_underflows, 0, "TX FIFO underflow events");
  508 
  509         SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "interrupts", CTLFLAG_RD,
  510             &sc->interrupts, 0, "interrupt calls");
  511 
  512         SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "stray_ints", CTLFLAG_RD,
  513             &sc->stray_ints, 0, "stray interrupts");
  514 }
  515 
  516 static int
  517 zy7_qspi_probe(device_t dev)
  518 {
  519 
  520         if (!ofw_bus_status_okay(dev))
  521                 return (ENXIO);
  522 
  523         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  524                 return (ENXIO);
  525 
  526         device_set_desc(dev, "Zynq Quad-SPI Flash Controller");
  527 
  528         return (BUS_PROBE_DEFAULT);
  529 }
  530 
  531 static int
  532 zy7_qspi_attach(device_t dev)
  533 {
  534         struct zy7_qspi_softc *sc;
  535         int rid, err;
  536         phandle_t node;
  537         pcell_t cell;
  538 
  539         sc = device_get_softc(dev);
  540         sc->dev = dev;
  541 
  542         QSPI_SC_LOCK_INIT(sc);
  543 
  544         /* Get ref-clock, spi-clock, and other properties. */
  545         node = ofw_bus_get_node(dev);
  546         if (OF_getprop(node, "ref-clock", &cell, sizeof(cell)) > 0)
  547                 sc->ref_clock = fdt32_to_cpu(cell);
  548         else {
  549                 device_printf(dev, "must have ref-clock property\n");
  550                 return (ENXIO);
  551         }
  552         if (OF_getprop(node, "spi-clock", &cell, sizeof(cell)) > 0)
  553                 sc->spi_clock = fdt32_to_cpu(cell);
  554         else
  555                 sc->spi_clock = ZY7_QSPI_DEFAULT_SPI_CLOCK;
  556         if (OF_getprop(node, "is-stacked", &cell, sizeof(cell)) > 0 &&
  557             fdt32_to_cpu(cell) != 0) {
  558                 sc->is_dual = 1;
  559                 sc->is_stacked = 1;
  560         } else if (OF_getprop(node, "is-dual", &cell, sizeof(cell)) > 0 &&
  561                    fdt32_to_cpu(cell) != 0)
  562                 sc->is_dual = 1;
  563         if (OF_getprop(node, "is-dio", &cell, sizeof(cell)) > 0 &&
  564             fdt32_to_cpu(cell) != 0)
  565                 sc->is_dio = 1;
  566 
  567         /* Get memory resource. */
  568         rid = 0;
  569         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  570             RF_ACTIVE);
  571         if (sc->mem_res == NULL) {
  572                 device_printf(dev, "could not allocate memory resources.\n");
  573                 zy7_qspi_detach(dev);
  574                 return (ENOMEM);
  575         }
  576 
  577         /* Allocate IRQ. */
  578         rid = 0;
  579         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  580             RF_ACTIVE);
  581         if (sc->irq_res == NULL) {
  582                 device_printf(dev, "could not allocate IRQ resource.\n");
  583                 zy7_qspi_detach(dev);
  584                 return (ENOMEM);
  585         }
  586 
  587         /* Activate the interrupt. */
  588         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  589             NULL, zy7_qspi_intr, sc, &sc->intrhandle);
  590         if (err) {
  591                 device_printf(dev, "could not setup IRQ.\n");
  592                 zy7_qspi_detach(dev);
  593                 return (err);
  594         }
  595 
  596         /* Configure the device. */
  597         err = zy7_qspi_init_hw(sc);
  598         if (err) {
  599                 zy7_qspi_detach(dev);
  600                 return (err);
  601         }
  602 
  603         sc->child = device_add_child(dev, "spibus", -1);
  604 
  605         zy7_qspi_add_sysctls(dev);
  606 
  607         /* Attach spibus driver as a child later when interrupts work. */
  608         config_intrhook_oneshot((ich_func_t)bus_generic_attach, dev);
  609 
  610         return (0);
  611 }
  612 
  613 static int
  614 zy7_qspi_detach(device_t dev)
  615 {
  616         struct zy7_qspi_softc *sc = device_get_softc(dev);
  617 
  618         if (device_is_attached(dev))
  619                 bus_generic_detach(dev);
  620 
  621         /* Delete child bus. */
  622         if (sc->child)
  623                 device_delete_child(dev, sc->child);
  624 
  625         /* Disable hardware. */
  626         if (sc->mem_res != NULL) {
  627                 /* Disable SPI. */
  628                 WR4(sc, ZY7_QSPI_EN_REG, 0);
  629 
  630                 /* Clear and disable all interrupts. */
  631                 WR4(sc, ZY7_QSPI_INTR_STAT_REG, ~0);
  632                 WR4(sc, ZY7_QSPI_INTR_DIS_REG, ~0);
  633         }
  634 
  635         /* Teardown and release interrupt. */
  636         if (sc->irq_res != NULL) {
  637                 if (sc->intrhandle)
  638                         bus_teardown_intr(dev, sc->irq_res, sc->intrhandle);
  639                 bus_release_resource(dev, SYS_RES_IRQ,
  640                     rman_get_rid(sc->irq_res), sc->irq_res);
  641         }
  642 
  643         /* Release memory resource. */
  644         if (sc->mem_res != NULL)
  645                 bus_release_resource(dev, SYS_RES_MEMORY,
  646                     rman_get_rid(sc->mem_res), sc->mem_res);
  647 
  648         QSPI_SC_LOCK_DESTROY(sc);
  649 
  650         return (0);
  651 }
  652 
  653 static phandle_t
  654 zy7_qspi_get_node(device_t bus, device_t dev)
  655 {
  656 
  657         return (ofw_bus_get_node(bus));
  658 }
  659 
  660 static int
  661 zy7_qspi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  662 {
  663         struct zy7_qspi_softc *sc = device_get_softc(dev);
  664         int err = 0;
  665 
  666         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
  667             ("TX/RX command sizes should be equal"));
  668         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
  669             ("TX/RX data sizes should be equal"));
  670 
  671         if (sc->is_dual && cmd->tx_data_sz % 2 != 0) {
  672                 device_printf(dev, "driver does not support odd byte data "
  673                     "transfers in dual mode. (sz=%d)\n", cmd->tx_data_sz);
  674                 return (EINVAL);
  675         }
  676 
  677         QSPI_SC_LOCK(sc);
  678 
  679         /* Wait for controller available. */
  680         while (sc->busy != 0) {
  681                 err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi0", 0);
  682                 if (err) {
  683                         QSPI_SC_UNLOCK(sc);
  684                         return (err);
  685                 }
  686         }
  687 
  688         /* Start transfer. */
  689         sc->busy = 1;
  690         sc->cmd = cmd;
  691         sc->tx_bytes = sc->cmd->tx_cmd_sz + sc->cmd->tx_data_sz;
  692         sc->tx_bytes_sent = 0;
  693         sc->rx_bytes = sc->cmd->rx_cmd_sz + sc->cmd->rx_data_sz;
  694         sc->rx_bytes_rcvd = 0;
  695 
  696         /* Enable interrupts.  zy7_qspi_intr() will handle transfer. */
  697         WR4(sc, ZY7_QSPI_INTR_EN_REG,
  698             ZY7_QSPI_INTR_TX_FIFO_NOT_FULL |
  699             ZY7_QSPI_INTR_RX_OVERFLOW);
  700 
  701 #ifdef SPI_XFER_U_PAGE  /* XXX: future support for stacked memories. */
  702         if (sc->is_stacked) {
  703                 if ((cmd->flags & SPI_XFER_U_PAGE) != 0)
  704                         sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_U_PAGE;
  705                 else
  706                         sc->lqspi_cfg_shadow &= ~ZY7_QSPI_LQSPI_CFG_U_PAGE;
  707                 WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow);
  708         }
  709 #endif
  710 
  711         /* Assert CS. */
  712         sc->cfg_reg_shadow &= ~ZY7_QSPI_CONFIG_PCS;
  713         WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
  714 
  715         /* Wait for completion. */
  716         err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi1", hz * 2);
  717         if (err)
  718                 zy7_qspi_abort_transfer(sc);
  719 
  720         /* Release controller. */
  721         sc->busy = 0;
  722         wakeup_one(dev);
  723 
  724         QSPI_SC_UNLOCK(sc);
  725 
  726         return (err);
  727 }
  728 
  729 static device_method_t zy7_qspi_methods[] = {
  730         /* Device interface */
  731         DEVMETHOD(device_probe,         zy7_qspi_probe),
  732         DEVMETHOD(device_attach,        zy7_qspi_attach),
  733         DEVMETHOD(device_detach,        zy7_qspi_detach),
  734 
  735         /* SPI interface */
  736         DEVMETHOD(spibus_transfer,      zy7_qspi_transfer),
  737 
  738         /* ofw_bus interface */
  739         DEVMETHOD(ofw_bus_get_node,     zy7_qspi_get_node),
  740 
  741         DEVMETHOD_END
  742 };
  743 
  744 static driver_t zy7_qspi_driver = {
  745         "zy7_qspi",
  746         zy7_qspi_methods,
  747         sizeof(struct zy7_qspi_softc),
  748 };
  749 static devclass_t zy7_qspi_devclass;
  750 
  751 DRIVER_MODULE(zy7_qspi, simplebus, zy7_qspi_driver, zy7_qspi_devclass, 0, 0);
  752 DRIVER_MODULE(ofw_spibus, zy7_qspi, ofw_spibus_driver, ofw_spibus_devclass, 0, 0);
  753 SIMPLEBUS_PNP_INFO(compat_data);
  754 MODULE_DEPEND(zy7_qspi, ofw_spibus, 1, 1, 1);

Cache object: 3ada94a1ebe1f6c65bb7e3bb8ec09673


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.