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/mips/mediatek/mtk_spi_v2.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  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
    3  * Copyright (c) 2011, Aleksandr Rybalko <ray@FreeBSD.org>
    4  * Copyright (c) 2013, Alexander A. Mityaev <sansan@adm.ua>
    5  * Copyright (c) 2016, Stanislav Galabov <sgalabov@gmail.com>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice unmodified, this list of conditions, and the following
   13  *    disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/11.0/sys/mips/mediatek/mtk_spi_v2.c 299155 2016-05-06 05:24:10Z sgalabov $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/rman.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/cpu.h>
   46 
   47 #include <dev/spibus/spi.h>
   48 #include <dev/spibus/spibusvar.h>
   49 #include "spibus_if.h"
   50 
   51 #include "opt_platform.h"
   52 
   53 #include <dev/ofw/openfirm.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <dev/ofw/ofw_bus_subr.h>
   56 
   57 #include <mips/mediatek/mtk_spi_v2.h>
   58 #include <dev/flash/mx25lreg.h>
   59 
   60 #undef MTK_SPI_DEBUG
   61 #ifdef MTK_SPI_DEBUG
   62 #define dprintf printf
   63 #else
   64 #define dprintf(x, arg...)
   65 #endif
   66 
   67 /*
   68  * register space access macros
   69  */
   70 #define SPI_WRITE(sc, reg, val) do {    \
   71                 bus_write_4(sc->sc_mem_res, (reg), (val)); \
   72         } while (0)
   73 
   74 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
   75 
   76 #define SPI_SET_BITS(sc, reg, bits)     \
   77         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
   78 
   79 #define SPI_CLEAR_BITS(sc, reg, bits)   \
   80         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
   81 
   82 struct mtk_spi_softc {
   83         device_t                sc_dev;
   84         struct resource         *sc_mem_res;
   85 };
   86 
   87 static int      mtk_spi_probe(device_t);
   88 static int      mtk_spi_attach(device_t);
   89 static int      mtk_spi_detach(device_t);
   90 static int      mtk_spi_wait(struct mtk_spi_softc *);
   91 static void     mtk_spi_chip_activate(struct mtk_spi_softc *);
   92 static void     mtk_spi_chip_deactivate(struct mtk_spi_softc *);
   93 static uint8_t  mtk_spi_txrx(struct mtk_spi_softc *, uint8_t *, int);
   94 static int      mtk_spi_transfer(device_t, device_t, struct spi_command *);
   95 static phandle_t mtk_spi_get_node(device_t, device_t);
   96 
   97 static struct ofw_compat_data compat_data[] = {
   98         { "ralink,mt7621-spi",          1 },
   99         { "ralink,mtk7628an-spi",       1 },
  100         { NULL,                         0 }
  101 };
  102 
  103 static int
  104 mtk_spi_probe(device_t dev)
  105 {
  106 
  107         if (!ofw_bus_status_okay(dev))
  108                 return (ENXIO);
  109 
  110         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  111                 return(ENXIO);
  112 
  113         device_set_desc(dev, "MTK SPI Controller (v2)");
  114 
  115         return (0);
  116 }
  117 
  118 static int
  119 mtk_spi_attach(device_t dev)
  120 {
  121         struct mtk_spi_softc *sc = device_get_softc(dev);
  122         uint32_t val;
  123         int rid;
  124 
  125         sc->sc_dev = dev;
  126         rid = 0;
  127         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  128             RF_ACTIVE);
  129         if (!sc->sc_mem_res) {
  130                 device_printf(dev, "Could not map memory\n");
  131                 return (ENXIO);
  132         }
  133 
  134         if (mtk_spi_wait(sc)) {
  135                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  136                 return (EBUSY);
  137         }
  138 
  139         val = SPI_READ(sc, MTK_SPIMASTER);
  140         val &= ~(0xfff << 16);
  141         val |= 13 << 16;
  142         val |= 7 << 29;
  143         val |= 1 << 2;
  144         SPI_WRITE(sc, MTK_SPIMASTER, val);
  145             /*
  146              * W25Q64CV max 104MHz, bus 120-192 MHz, so divide by 2.
  147              * Update: divide by 4, DEV2 to fast for flash.
  148              */
  149 
  150         device_add_child(dev, "spibus", 0);
  151         return (bus_generic_attach(dev));
  152 }
  153 
  154 static int
  155 mtk_spi_detach(device_t dev)
  156 {
  157         struct mtk_spi_softc *sc = device_get_softc(dev);
  158 
  159         if (sc->sc_mem_res)
  160                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  161 
  162         return (0);
  163 }
  164 
  165 static void
  166 mtk_spi_chip_activate(struct mtk_spi_softc *sc)
  167 {
  168         mtk_spi_wait(sc);
  169         /*
  170          * Put all CSx to low
  171          */
  172         SPI_SET_BITS(sc, MTK_SPIPOLAR, 1);
  173 }
  174 
  175 static void
  176 mtk_spi_chip_deactivate(struct mtk_spi_softc *sc)
  177 {
  178         mtk_spi_wait(sc);
  179         /*
  180          * Put all CSx to high
  181          */
  182         SPI_CLEAR_BITS(sc, MTK_SPIPOLAR, 1);
  183 }
  184 
  185 static int
  186 mtk_spi_wait(struct mtk_spi_softc *sc)
  187 {
  188         int i = 1000;
  189 
  190         while (i--) {
  191                 if (!(SPI_READ(sc, MTK_SPITRANS) & SPIBUSY))
  192                         break;
  193         }
  194         if (i == 0) {
  195                 return (1);
  196         }
  197 
  198         return (0);
  199 }
  200 
  201 static uint8_t
  202 mtk_spi_txrx(struct mtk_spi_softc *sc, uint8_t *data, int write)
  203 {
  204 
  205         if (mtk_spi_wait(sc))
  206                 return (0xff);
  207 
  208         if (write == MTK_SPI_WRITE) {
  209                 SPI_WRITE(sc, MTK_SPIOPCODE, (*data));
  210                 SPI_WRITE(sc, MTK_SPIMOREBUF, (8<<24));
  211         } else {
  212                 SPI_WRITE(sc, MTK_SPIMOREBUF, (8<<12));
  213         }
  214 
  215         SPI_SET_BITS(sc, MTK_SPITRANS, SPISTART);
  216 
  217         if (mtk_spi_wait(sc))
  218                 return (0xff);
  219 
  220         if (write == MTK_SPI_READ) {
  221                 *data = SPI_READ(sc, MTK_SPIDATA) & 0xff;
  222         }
  223 
  224         return (0);
  225 }
  226 
  227 static int
  228 mtk_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  229 {
  230         struct mtk_spi_softc *sc;
  231         uint8_t *buf, byte, *tx_buf;
  232         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  233         int i, sz, error, write = 0;
  234 
  235         sc = device_get_softc(dev);
  236 
  237         if (devi->cs != 0)
  238                 /* Only 1 CS */
  239                 return (ENXIO);
  240 
  241         /* There is always a command to transfer. */
  242         tx_buf = (uint8_t *)(cmd->tx_cmd);
  243 
  244         /* Perform some fixup because MTK dont support duplex SPI */
  245         switch(tx_buf[0]) {
  246                 case CMD_READ_IDENT:
  247                         cmd->tx_cmd_sz = 1;
  248                         cmd->rx_cmd_sz = 3;
  249                         break;
  250                 case CMD_ENTER_4B_MODE:
  251                 case CMD_EXIT_4B_MODE:
  252                 case CMD_WRITE_ENABLE:
  253                 case CMD_WRITE_DISABLE:
  254                         cmd->tx_cmd_sz = 1;
  255                         cmd->rx_cmd_sz = 0;
  256                         break;
  257                 case CMD_READ_STATUS:
  258                         cmd->tx_cmd_sz = 1;
  259                         cmd->rx_cmd_sz = 1;
  260                         break;
  261                 case CMD_READ:
  262                 case CMD_FAST_READ:
  263                         cmd->rx_cmd_sz = cmd->tx_data_sz = 0;
  264                         break;
  265                 case CMD_SECTOR_ERASE:
  266                         cmd->rx_cmd_sz = 0;
  267                         break;
  268                 case CMD_PAGE_PROGRAM:
  269                         cmd->rx_cmd_sz = cmd->rx_data_sz = 0;
  270                         break;
  271         }      
  272         
  273         mtk_spi_chip_activate(sc);
  274 
  275         if (cmd->tx_cmd_sz + cmd->rx_cmd_sz) {
  276                 buf = (uint8_t *)(cmd->rx_cmd);
  277                 tx_buf = (uint8_t *)(cmd->tx_cmd);
  278                 sz = cmd->tx_cmd_sz + cmd->rx_cmd_sz;
  279 
  280                 for (i = 0; i < sz; i++) {
  281                         if(i < cmd->tx_cmd_sz) {
  282                                 byte = tx_buf[i];
  283                                 error = mtk_spi_txrx(sc, &byte,
  284                                     MTK_SPI_WRITE);
  285                                 if (error)
  286                                         goto mtk_spi_transfer_fail;
  287                                 continue;
  288                         }
  289                         error = mtk_spi_txrx(sc, &byte,
  290                             MTK_SPI_READ);
  291                         if (error)
  292                                 goto mtk_spi_transfer_fail;
  293                         buf[i] = byte;
  294                 }
  295         }
  296         
  297         /*
  298          * Transfer/Receive data
  299          */
  300         
  301         if (cmd->tx_data_sz + cmd->rx_data_sz) {
  302                 write = (cmd->tx_data_sz > 0)?1:0;
  303                 buf = (uint8_t *)(write ? cmd->tx_data : cmd->rx_data);
  304                 sz = write ? cmd->tx_data_sz : cmd->rx_data_sz;
  305 
  306                 for (i = 0; i < sz; i++) {
  307                         byte = buf[i];
  308                         error = mtk_spi_txrx(sc, &byte,
  309                             write ? MTK_SPI_WRITE : MTK_SPI_READ);
  310                         if (error)
  311                                 goto mtk_spi_transfer_fail;
  312                         buf[i] = byte;
  313                 }
  314         }
  315 mtk_spi_transfer_fail:
  316         mtk_spi_chip_deactivate(sc);
  317 
  318         return (0);
  319 }
  320 
  321 static phandle_t
  322 mtk_spi_get_node(device_t bus, device_t dev)
  323 {
  324 
  325         /* We only have one child, the SPI bus, which needs our own node. */
  326         return (ofw_bus_get_node(bus));
  327 }
  328 
  329 static device_method_t mtk_spi_methods[] = {
  330         /* Device interface */
  331         DEVMETHOD(device_probe,         mtk_spi_probe),
  332         DEVMETHOD(device_attach,        mtk_spi_attach),
  333         DEVMETHOD(device_detach,        mtk_spi_detach),
  334 
  335         DEVMETHOD(spibus_transfer,      mtk_spi_transfer),
  336 
  337         /* ofw_bus interface */
  338         DEVMETHOD(ofw_bus_get_node,     mtk_spi_get_node),
  339 
  340         DEVMETHOD_END
  341 };
  342 
  343 static driver_t mtk_spi_driver = {
  344         .name = "spi",
  345         .methods = mtk_spi_methods,
  346         .size = sizeof(struct mtk_spi_softc),
  347 };
  348 
  349 static devclass_t mtk_spi_devclass;
  350 
  351 DRIVER_MODULE(mtk_spi_v2, simplebus, mtk_spi_driver, mtk_spi_devclass, 0, 0);

Cache object: 1f31998bf204cda790b63ae4de7e16f6


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