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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: stable/12/sys/mips/mediatek/mtk_spi_v2.c 310229 2016-12-18 14:54:20Z manu $");
   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         uint32_t cs;
  233         int i, sz, error, write = 0;
  234 
  235         sc = device_get_softc(dev);
  236 
  237         spibus_get_cs(child, &cs);
  238 
  239         cs &= ~SPIBUS_CS_HIGH;
  240 
  241         if (cs != 0)
  242                 /* Only 1 CS */
  243                 return (ENXIO);
  244 
  245         /* There is always a command to transfer. */
  246         tx_buf = (uint8_t *)(cmd->tx_cmd);
  247 
  248         /* Perform some fixup because MTK dont support duplex SPI */
  249         switch(tx_buf[0]) {
  250                 case CMD_READ_IDENT:
  251                         cmd->tx_cmd_sz = 1;
  252                         cmd->rx_cmd_sz = 3;
  253                         break;
  254                 case CMD_ENTER_4B_MODE:
  255                 case CMD_EXIT_4B_MODE:
  256                 case CMD_WRITE_ENABLE:
  257                 case CMD_WRITE_DISABLE:
  258                         cmd->tx_cmd_sz = 1;
  259                         cmd->rx_cmd_sz = 0;
  260                         break;
  261                 case CMD_READ_STATUS:
  262                         cmd->tx_cmd_sz = 1;
  263                         cmd->rx_cmd_sz = 1;
  264                         break;
  265                 case CMD_READ:
  266                 case CMD_FAST_READ:
  267                         cmd->rx_cmd_sz = cmd->tx_data_sz = 0;
  268                         break;
  269                 case CMD_SECTOR_ERASE:
  270                         cmd->rx_cmd_sz = 0;
  271                         break;
  272                 case CMD_PAGE_PROGRAM:
  273                         cmd->rx_cmd_sz = cmd->rx_data_sz = 0;
  274                         break;
  275         }      
  276         
  277         mtk_spi_chip_activate(sc);
  278 
  279         if (cmd->tx_cmd_sz + cmd->rx_cmd_sz) {
  280                 buf = (uint8_t *)(cmd->rx_cmd);
  281                 tx_buf = (uint8_t *)(cmd->tx_cmd);
  282                 sz = cmd->tx_cmd_sz + cmd->rx_cmd_sz;
  283 
  284                 for (i = 0; i < sz; i++) {
  285                         if(i < cmd->tx_cmd_sz) {
  286                                 byte = tx_buf[i];
  287                                 error = mtk_spi_txrx(sc, &byte,
  288                                     MTK_SPI_WRITE);
  289                                 if (error)
  290                                         goto mtk_spi_transfer_fail;
  291                                 continue;
  292                         }
  293                         error = mtk_spi_txrx(sc, &byte,
  294                             MTK_SPI_READ);
  295                         if (error)
  296                                 goto mtk_spi_transfer_fail;
  297                         buf[i] = byte;
  298                 }
  299         }
  300         
  301         /*
  302          * Transfer/Receive data
  303          */
  304         
  305         if (cmd->tx_data_sz + cmd->rx_data_sz) {
  306                 write = (cmd->tx_data_sz > 0)?1:0;
  307                 buf = (uint8_t *)(write ? cmd->tx_data : cmd->rx_data);
  308                 sz = write ? cmd->tx_data_sz : cmd->rx_data_sz;
  309 
  310                 for (i = 0; i < sz; i++) {
  311                         byte = buf[i];
  312                         error = mtk_spi_txrx(sc, &byte,
  313                             write ? MTK_SPI_WRITE : MTK_SPI_READ);
  314                         if (error)
  315                                 goto mtk_spi_transfer_fail;
  316                         buf[i] = byte;
  317                 }
  318         }
  319 mtk_spi_transfer_fail:
  320         mtk_spi_chip_deactivate(sc);
  321 
  322         return (0);
  323 }
  324 
  325 static phandle_t
  326 mtk_spi_get_node(device_t bus, device_t dev)
  327 {
  328 
  329         /* We only have one child, the SPI bus, which needs our own node. */
  330         return (ofw_bus_get_node(bus));
  331 }
  332 
  333 static device_method_t mtk_spi_methods[] = {
  334         /* Device interface */
  335         DEVMETHOD(device_probe,         mtk_spi_probe),
  336         DEVMETHOD(device_attach,        mtk_spi_attach),
  337         DEVMETHOD(device_detach,        mtk_spi_detach),
  338 
  339         DEVMETHOD(spibus_transfer,      mtk_spi_transfer),
  340 
  341         /* ofw_bus interface */
  342         DEVMETHOD(ofw_bus_get_node,     mtk_spi_get_node),
  343 
  344         DEVMETHOD_END
  345 };
  346 
  347 static driver_t mtk_spi_driver = {
  348         .name = "spi",
  349         .methods = mtk_spi_methods,
  350         .size = sizeof(struct mtk_spi_softc),
  351 };
  352 
  353 static devclass_t mtk_spi_devclass;
  354 
  355 DRIVER_MODULE(mtk_spi_v2, simplebus, mtk_spi_driver, mtk_spi_devclass, 0, 0);

Cache object: 68daed0f60ee80fc3d63822bf58775f1


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