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

Cache object: 4b35e97401598c38044bed63222487ad


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