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/arm64/rockchip/rk_spi.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) 2019 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/lock.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 #include <sys/rman.h>
   41 #include <sys/resource.h>
   42 #include <machine/bus.h>
   43 
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_bus_subr.h>
   46 
   47 #include <dev/spibus/spi.h>
   48 #include <dev/spibus/spibusvar.h>
   49 
   50 #include <dev/extres/clk/clk.h>
   51 #include <dev/extres/hwreset/hwreset.h>
   52 
   53 #include "spibus_if.h"
   54 
   55 #define RK_SPI_CTRLR0           0x0000
   56 #define         CTRLR0_OPM_MASTER       (0 << 20)
   57 #define         CTRLR0_XFM_TR           (0 << 18)
   58 #define         CTRLR0_FRF_MOTO         (0 << 16)
   59 #define         CTRLR0_BHT_8BIT         (1 << 13)
   60 #define         CTRLR0_EM_BIG           (1 << 11)
   61 #define         CTRLR0_SSD_ONE          (1 << 10)
   62 #define         CTRLR0_SCPOL            (1 <<  7)
   63 #define         CTRLR0_SCPH             (1 <<  6)
   64 #define         CTRLR0_DFS_8BIT         (1 <<  0)
   65 #define RK_SPI_CTRLR1           0x0004
   66 #define RK_SPI_ENR              0x0008
   67 #define RK_SPI_SER              0x000c
   68 #define RK_SPI_BAUDR            0x0010
   69 #define RK_SPI_TXFTLR           0x0014
   70 #define RK_SPI_RXFTLR           0x0018
   71 #define RK_SPI_TXFLR            0x001c
   72 #define RK_SPI_RXFLR            0x0020
   73 #define RK_SPI_SR               0x0024
   74 #define         SR_BUSY                 (1 <<  0)
   75 #define RK_SPI_IPR              0x0028
   76 #define RK_SPI_IMR              0x002c
   77 #define         IMR_RFFIM               (1 <<  4)
   78 #define         IMR_TFEIM               (1 <<  0)
   79 #define RK_SPI_ISR              0x0030
   80 #define         ISR_RFFIS               (1 <<  4)
   81 #define         ISR_TFEIS               (1 <<  0)
   82 #define RK_SPI_RISR             0x0034
   83 #define RK_SPI_ICR              0x0038
   84 #define RK_SPI_DMACR            0x003c
   85 #define RK_SPI_DMATDLR          0x0040
   86 #define RK_SPI_DMARDLR          0x0044
   87 #define RK_SPI_TXDR             0x0400
   88 #define RK_SPI_RXDR             0x0800
   89 
   90 #define CS_MAX                  1
   91 
   92 static struct ofw_compat_data compat_data[] = {
   93         { "rockchip,rk3328-spi",                1 },
   94         { "rockchip,rk3399-spi",                1 },
   95         { "rockchip,rk3568-spi",                1 },
   96         { NULL,                                 0 }
   97 };
   98 
   99 static struct resource_spec rk_spi_spec[] = {
  100         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  101         { SYS_RES_IRQ,          0,      RF_ACTIVE | RF_SHAREABLE },
  102         { -1, 0 }
  103 };
  104 
  105 struct rk_spi_softc {
  106         device_t        dev;
  107         device_t        spibus;
  108         struct resource *res[2];
  109         struct mtx      mtx;
  110         clk_t           clk_apb;
  111         clk_t           clk_spi;
  112         void *          intrhand;
  113         int             transfer;
  114         uint32_t        fifo_size;
  115         uint64_t        max_freq;
  116 
  117         uint32_t        intreg;
  118         uint8_t         *rxbuf;
  119         uint32_t        rxidx;
  120         uint8_t         *txbuf;
  121         uint32_t        txidx;
  122         uint32_t        txlen;
  123         uint32_t        rxlen;
  124 };
  125 
  126 #define RK_SPI_LOCK(sc)                 mtx_lock(&(sc)->mtx)
  127 #define RK_SPI_UNLOCK(sc)               mtx_unlock(&(sc)->mtx)
  128 #define RK_SPI_READ_4(sc, reg)          bus_read_4((sc)->res[0], (reg))
  129 #define RK_SPI_WRITE_4(sc, reg, val)    bus_write_4((sc)->res[0], (reg), (val))
  130 
  131 static int rk_spi_probe(device_t dev);
  132 static int rk_spi_attach(device_t dev);
  133 static int rk_spi_detach(device_t dev);
  134 static void rk_spi_intr(void *arg);
  135 
  136 static void
  137 rk_spi_enable_chip(struct rk_spi_softc *sc, int enable)
  138 {
  139 
  140         RK_SPI_WRITE_4(sc, RK_SPI_ENR, enable ? 1 : 0);
  141 }
  142 
  143 static int
  144 rk_spi_set_cs(struct rk_spi_softc *sc, uint32_t cs, bool active)
  145 {
  146         uint32_t reg;
  147 
  148         if (cs & SPIBUS_CS_HIGH) {
  149                 device_printf(sc->dev, "SPIBUS_CS_HIGH is not supported\n");
  150                 return (EINVAL);
  151         }
  152 
  153         if (cs > CS_MAX)
  154                 return (EINVAL);
  155 
  156         reg = RK_SPI_READ_4(sc, RK_SPI_SER);
  157         if (active)
  158                 reg |= (1 << cs);
  159         else
  160                 reg &= ~(1 << cs);
  161         RK_SPI_WRITE_4(sc, RK_SPI_SER, reg);
  162 
  163         return (0);
  164 }
  165 
  166 static void
  167 rk_spi_hw_setup(struct rk_spi_softc *sc, uint32_t mode, uint32_t freq)
  168 {
  169         uint32_t cr0;
  170         uint32_t div;
  171 
  172         cr0 =  CTRLR0_OPM_MASTER | CTRLR0_XFM_TR | CTRLR0_FRF_MOTO |
  173             CTRLR0_BHT_8BIT | CTRLR0_EM_BIG | CTRLR0_SSD_ONE |
  174             CTRLR0_DFS_8BIT;
  175 
  176         if (mode & SPIBUS_MODE_CPHA)
  177                 cr0 |= CTRLR0_SCPH;
  178         if (mode & SPIBUS_MODE_CPOL)
  179                 cr0 |= CTRLR0_SCPOL;
  180 
  181         /* minimum divider is 2 */
  182         if (sc->max_freq < freq*2) {
  183                 clk_set_freq(sc->clk_spi, 2 * freq, CLK_SET_ROUND_DOWN);
  184                 clk_get_freq(sc->clk_spi, &sc->max_freq);
  185         }
  186 
  187         div = ((sc->max_freq + freq - 1) / freq);
  188         div = (div + 1) & 0xfffe;
  189         RK_SPI_WRITE_4(sc, RK_SPI_BAUDR, div);
  190 
  191         RK_SPI_WRITE_4(sc, RK_SPI_CTRLR0, cr0);
  192 }
  193 
  194 static uint32_t
  195 rk_spi_fifo_size(struct rk_spi_softc *sc)
  196 {
  197         uint32_t txftlr, reg;
  198 
  199         for (txftlr = 2; txftlr < 32; txftlr++) {
  200                 RK_SPI_WRITE_4(sc, RK_SPI_TXFTLR, txftlr);
  201                 reg = RK_SPI_READ_4(sc, RK_SPI_TXFTLR);
  202                 if (reg != txftlr)
  203                         break;
  204         }
  205         RK_SPI_WRITE_4(sc, RK_SPI_TXFTLR, 0);
  206 
  207         if (txftlr == 31)
  208                 return 0;
  209 
  210         return txftlr;
  211 }
  212 
  213 static void
  214 rk_spi_empty_rxfifo(struct rk_spi_softc *sc)
  215 {
  216         uint32_t rxlevel;
  217         rxlevel = RK_SPI_READ_4(sc, RK_SPI_RXFLR);
  218         while (sc->rxidx < sc->rxlen &&
  219             (rxlevel-- > 0)) {
  220                 sc->rxbuf[sc->rxidx++] = (uint8_t)RK_SPI_READ_4(sc, RK_SPI_RXDR);
  221         }
  222 }
  223 
  224 static void
  225 rk_spi_fill_txfifo(struct rk_spi_softc *sc)
  226 {
  227         uint32_t txlevel;
  228         txlevel = RK_SPI_READ_4(sc, RK_SPI_TXFLR);
  229 
  230         while (sc->txidx < sc->txlen && txlevel < sc->fifo_size) {
  231                 RK_SPI_WRITE_4(sc, RK_SPI_TXDR, sc->txbuf[sc->txidx++]);
  232                 txlevel++;
  233         }
  234 
  235         if (sc->txidx != sc->txlen)
  236                 sc->intreg |= (IMR_TFEIM  | IMR_RFFIM);
  237 }
  238 
  239 static int
  240 rk_spi_xfer_buf(struct rk_spi_softc *sc, void *rxbuf, void *txbuf, uint32_t len)
  241 {
  242         int err;
  243 
  244         if (len == 0)
  245                 return (0);
  246 
  247         sc->rxbuf = rxbuf;
  248         sc->rxlen = len;
  249         sc->rxidx = 0;
  250         sc->txbuf = txbuf;
  251         sc->txlen = len;
  252         sc->txidx = 0;
  253         sc->intreg = 0;
  254         rk_spi_fill_txfifo(sc);
  255 
  256         RK_SPI_WRITE_4(sc, RK_SPI_IMR, sc->intreg);
  257 
  258         err = 0;
  259         while (err == 0 && sc->intreg != 0)
  260                 err = msleep(sc, &sc->mtx, 0, "rk_spi", 10 * hz);
  261 
  262         while (err == 0 && sc->rxidx != sc->txidx) {
  263                 /* read residual data from RX fifo */
  264                 rk_spi_empty_rxfifo(sc);
  265         }
  266 
  267         if (sc->rxidx != sc->rxlen || sc->txidx != sc->txlen)
  268                 err = EIO;
  269 
  270         return (err);
  271 }
  272 
  273 static int
  274 rk_spi_probe(device_t dev)
  275 {
  276         if (!ofw_bus_status_okay(dev))
  277                 return (ENXIO);
  278 
  279         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  280                 return (ENXIO);
  281 
  282         device_set_desc(dev, "Rockchip SPI");
  283         return (BUS_PROBE_DEFAULT);
  284 }
  285 
  286 static int
  287 rk_spi_attach(device_t dev)
  288 {
  289         struct rk_spi_softc *sc;
  290         int error;
  291 
  292         sc = device_get_softc(dev);
  293         sc->dev = dev;
  294 
  295         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  296 
  297         if (bus_alloc_resources(dev, rk_spi_spec, sc->res) != 0) {
  298                 device_printf(dev, "cannot allocate resources for device\n");
  299                 error = ENXIO;
  300                 goto fail;
  301         }
  302 
  303         if (bus_setup_intr(dev, sc->res[1],
  304             INTR_TYPE_MISC | INTR_MPSAFE, NULL, rk_spi_intr, sc,
  305             &sc->intrhand)) {
  306                 bus_release_resources(dev, rk_spi_spec, sc->res);
  307                 device_printf(dev, "cannot setup interrupt handler\n");
  308                 return (ENXIO);
  309         }
  310 
  311         /* Activate the module clock. */
  312         error = clk_get_by_ofw_name(dev, 0, "apb_pclk", &sc->clk_apb);
  313         if (error != 0) {
  314                 device_printf(dev, "cannot get apb_pclk clock\n");
  315                 goto fail;
  316         }
  317         error = clk_get_by_ofw_name(dev, 0, "spiclk", &sc->clk_spi);
  318         if (error != 0) {
  319                 device_printf(dev, "cannot get spiclk clock\n");
  320                 goto fail;
  321         }
  322         error = clk_enable(sc->clk_apb);
  323         if (error != 0) {
  324                 device_printf(dev, "cannot enable ahb clock\n");
  325                 goto fail;
  326         }
  327         error = clk_enable(sc->clk_spi);
  328         if (error != 0) {
  329                 device_printf(dev, "cannot enable spiclk clock\n");
  330                 goto fail;
  331         }
  332         clk_get_freq(sc->clk_spi, &sc->max_freq);
  333 
  334         sc->fifo_size = rk_spi_fifo_size(sc);
  335         if (sc->fifo_size == 0) {
  336                 device_printf(dev, "failed to get fifo size\n");
  337                 goto fail;
  338         }
  339 
  340         sc->spibus = device_add_child(dev, "spibus", -1);
  341 
  342         RK_SPI_WRITE_4(sc, RK_SPI_IMR, 0);
  343         RK_SPI_WRITE_4(sc, RK_SPI_TXFTLR, sc->fifo_size/2 - 1);
  344         RK_SPI_WRITE_4(sc, RK_SPI_RXFTLR, sc->fifo_size/2 - 1);
  345 
  346         return (bus_generic_attach(dev));
  347 
  348 fail:
  349         rk_spi_detach(dev);
  350         return (error);
  351 }
  352 
  353 static int
  354 rk_spi_detach(device_t dev)
  355 {
  356         struct rk_spi_softc *sc;
  357 
  358         sc = device_get_softc(dev);
  359 
  360         bus_generic_detach(sc->dev);
  361         if (sc->spibus != NULL)
  362                 device_delete_child(dev, sc->spibus);
  363 
  364         if (sc->clk_spi != NULL)
  365                 clk_release(sc->clk_spi);
  366         if (sc->clk_apb)
  367                 clk_release(sc->clk_apb);
  368 
  369         if (sc->intrhand != NULL)
  370                 bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand);
  371 
  372         bus_release_resources(dev, rk_spi_spec, sc->res);
  373         mtx_destroy(&sc->mtx);
  374 
  375         return (0);
  376 }
  377 
  378 static void
  379 rk_spi_intr(void *arg)
  380 {
  381         struct rk_spi_softc *sc;
  382         uint32_t intreg, isr;
  383 
  384         sc = arg;
  385 
  386         RK_SPI_LOCK(sc);
  387         intreg = RK_SPI_READ_4(sc, RK_SPI_IMR);
  388         isr = RK_SPI_READ_4(sc, RK_SPI_ISR);
  389         RK_SPI_WRITE_4(sc, RK_SPI_ICR, isr);
  390 
  391         if (isr & ISR_RFFIS)
  392                 rk_spi_empty_rxfifo(sc);
  393 
  394         if (isr & ISR_TFEIS)
  395                 rk_spi_fill_txfifo(sc);
  396 
  397         /* no bytes left, disable interrupt */
  398         if (sc->txidx == sc->txlen) {
  399                 sc->intreg = 0;
  400                 wakeup(sc);
  401         }
  402 
  403         if (sc->intreg != intreg) {
  404                 (void)RK_SPI_WRITE_4(sc, RK_SPI_IMR, sc->intreg);
  405                 (void)RK_SPI_READ_4(sc, RK_SPI_IMR);
  406         }
  407 
  408         RK_SPI_UNLOCK(sc);
  409 }
  410 
  411 static phandle_t
  412 rk_spi_get_node(device_t bus, device_t dev)
  413 {
  414 
  415         return ofw_bus_get_node(bus);
  416 }
  417 
  418 static int
  419 rk_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  420 {
  421         struct rk_spi_softc *sc;
  422         uint32_t cs, mode, clock;
  423         int err = 0;
  424 
  425         sc = device_get_softc(dev);
  426 
  427         spibus_get_cs(child, &cs);
  428         spibus_get_clock(child, &clock);
  429         spibus_get_mode(child, &mode);
  430 
  431         RK_SPI_LOCK(sc);
  432         rk_spi_hw_setup(sc, mode, clock);
  433         rk_spi_enable_chip(sc, 1);
  434         err = rk_spi_set_cs(sc, cs, true);
  435         if (err != 0) {
  436                 rk_spi_enable_chip(sc, 0);
  437                 RK_SPI_UNLOCK(sc);
  438                 return (err);
  439         }
  440 
  441         /* Transfer command then data bytes. */
  442         err = 0;
  443         if (cmd->tx_cmd_sz > 0)
  444                 err = rk_spi_xfer_buf(sc, cmd->rx_cmd, cmd->tx_cmd,
  445                     cmd->tx_cmd_sz);
  446         if (cmd->tx_data_sz > 0 && err == 0)
  447                 err = rk_spi_xfer_buf(sc, cmd->rx_data, cmd->tx_data,
  448                     cmd->tx_data_sz);
  449 
  450         rk_spi_set_cs(sc, cs, false);
  451         rk_spi_enable_chip(sc, 0);
  452         RK_SPI_UNLOCK(sc);
  453 
  454         return (err);
  455 }
  456 
  457 static device_method_t rk_spi_methods[] = {
  458         /* Device interface */
  459         DEVMETHOD(device_probe,         rk_spi_probe),
  460         DEVMETHOD(device_attach,        rk_spi_attach),
  461         DEVMETHOD(device_detach,        rk_spi_detach),
  462 
  463         /* spibus_if  */
  464         DEVMETHOD(spibus_transfer,      rk_spi_transfer),
  465 
  466         /* ofw_bus_if */
  467         DEVMETHOD(ofw_bus_get_node,     rk_spi_get_node),
  468 
  469         DEVMETHOD_END
  470 };
  471 
  472 static driver_t rk_spi_driver = {
  473         "spi",
  474         rk_spi_methods,
  475         sizeof(struct rk_spi_softc),
  476 };
  477 
  478 DRIVER_MODULE(rk_spi, simplebus, rk_spi_driver, 0, 0);
  479 DRIVER_MODULE(ofw_spibus, rk_spi, ofw_spibus_driver, 0, 0);
  480 MODULE_DEPEND(rk_spi, ofw_spibus, 1, 1, 1);
  481 OFWBUS_PNP_INFO(compat_data);

Cache object: cdfc3698d740b971e6be41591700c3f5


[ 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.