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/dev/bhnd/cores/chipc/chipc_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) 2016 Michael Zhilin <mizhka@gmail.com>
    5  * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
    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, this list of conditions and the following disclaimer,
   13  *    without modification.
   14  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   15  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   16  *    redistribution must be conditioned upon including a substantially
   17  *    similar Disclaimer requirement for further binary redistribution.
   18  *
   19  * NO WARRANTY
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   22  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   23  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   24  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   25  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   28  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   30  * THE POSSIBILITY OF SUCH DAMAGES.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/errno.h>
   41 #include <sys/rman.h>
   42 #include <sys/bus.h>
   43 
   44 #include <machine/bus.h>
   45 
   46 #include <dev/bhnd/bhndvar.h>
   47 
   48 #include <dev/spibus/spi.h>
   49 
   50 #include "bhnd_chipc_if.h"
   51 
   52 #include "spibus_if.h"
   53 
   54 #include "chipcreg.h"
   55 #include "chipcvar.h"
   56 #include "chipc_slicer.h"
   57 
   58 #include "chipc_spi.h"
   59 
   60 static int      chipc_spi_probe(device_t dev);
   61 static int      chipc_spi_attach(device_t dev);
   62 static int      chipc_spi_detach(device_t dev);
   63 static int      chipc_spi_transfer(device_t dev, device_t child,
   64                     struct spi_command *cmd);
   65 static int      chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t in,
   66                     uint8_t* out);
   67 static int      chipc_spi_wait(struct chipc_spi_softc *sc);
   68 
   69 static int
   70 chipc_spi_probe(device_t dev)
   71 {
   72         device_set_desc(dev, "Broadcom ChipCommon SPI");
   73         return (BUS_PROBE_NOWILDCARD);
   74 }
   75 
   76 static int
   77 chipc_spi_attach(device_t dev)
   78 {
   79         struct chipc_spi_softc  *sc;
   80         struct chipc_caps       *ccaps;
   81         device_t                 flash_dev;
   82         device_t                 spibus;
   83         const char              *flash_name;
   84         int                      error;
   85 
   86         sc = device_get_softc(dev);
   87 
   88         /* Allocate SPI controller registers */
   89         sc->sc_rid = 1;
   90         sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
   91             RF_ACTIVE);
   92         if (sc->sc_res == NULL) {
   93                 device_printf(dev, "failed to allocate device registers\n");
   94                 return (ENXIO);
   95         }
   96 
   97         /* Allocate flash shadow region */
   98         sc->sc_flash_rid = 0;
   99         sc->sc_flash_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  100             &sc->sc_flash_rid, RF_ACTIVE);
  101         if (sc->sc_flash_res == NULL) {
  102                 device_printf(dev, "failed to allocate flash region\n");
  103                 error = ENXIO;
  104                 goto failed;
  105         }
  106 
  107         /* 
  108          * Add flash device
  109          * 
  110          * XXX: This should be replaced with a DEVICE_IDENTIFY implementation
  111          * in chipc-specific subclasses of the mx25l and at45d drivers.
  112          */
  113         if ((spibus = device_add_child(dev, "spibus", -1)) == NULL) {
  114                 device_printf(dev, "failed to add spibus\n");
  115                 error = ENXIO;
  116                 goto failed;
  117         }
  118 
  119         /* Let spibus perform full attach before we try to call
  120          * BUS_ADD_CHILD() */
  121         if ((error = bus_generic_attach(dev)))
  122                 goto failed;
  123 
  124         /* Determine flash type and add the flash child */
  125         ccaps = BHND_CHIPC_GET_CAPS(device_get_parent(dev));
  126         flash_name = chipc_sflash_device_name(ccaps->flash_type);
  127         if (flash_name != NULL) {
  128                 flash_dev = BUS_ADD_CHILD(spibus, 0, flash_name, -1);
  129                 if (flash_dev == NULL) {
  130                         device_printf(dev, "failed to add %s\n", flash_name);
  131                         error = ENXIO;
  132                         goto failed;
  133                 }
  134 
  135                 chipc_register_slicer(ccaps->flash_type);
  136 
  137                 if ((error = device_probe_and_attach(flash_dev))) {
  138                         device_printf(dev, "failed to attach %s: %d\n",
  139                             flash_name, error);
  140                         goto failed;
  141                 }
  142         }
  143 
  144         return (0);
  145 
  146 failed:
  147         device_delete_children(dev);
  148 
  149         if (sc->sc_res != NULL)
  150                 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid,
  151                     sc->sc_res);
  152 
  153         if (sc->sc_flash_res != NULL)
  154                 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid,
  155                     sc->sc_flash_res);
  156 
  157         return (error);
  158 }
  159 
  160 static int
  161 chipc_spi_detach(device_t dev)
  162 {
  163         struct chipc_spi_softc  *sc;
  164         int                      error;
  165 
  166         sc = device_get_softc(dev);
  167 
  168         if ((error = bus_generic_detach(dev)))
  169                 return (error);
  170 
  171         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
  172         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid,
  173             sc->sc_flash_res);
  174         return (0);
  175 }
  176 
  177 static int
  178 chipc_spi_wait(struct chipc_spi_softc *sc)
  179 {
  180         int i;
  181 
  182         for (i = CHIPC_SPI_MAXTRIES; i > 0; i--)
  183                 if (!(SPI_READ(sc, CHIPC_SPI_FLASHCTL) & CHIPC_SPI_FLASHCTL_START))
  184                         break;
  185 
  186         if (i > 0)
  187                 return (0);
  188 
  189         BHND_WARN_DEV(sc->sc_dev, "busy: CTL=0x%x DATA=0x%x",
  190             SPI_READ(sc, CHIPC_SPI_FLASHCTL),
  191             SPI_READ(sc, CHIPC_SPI_FLASHDATA));
  192         return (-1);
  193 }
  194 
  195 static int
  196 chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t out, uint8_t* in)
  197 {
  198         uint32_t ctl;
  199 
  200         ctl = CHIPC_SPI_FLASHCTL_START | CHIPC_SPI_FLASHCTL_CSACTIVE | out;
  201         SPI_BARRIER_WRITE(sc);
  202         SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, ctl);
  203         SPI_BARRIER_WRITE(sc);
  204 
  205         if (chipc_spi_wait(sc))
  206                 return (-1);
  207 
  208         *in = SPI_READ(sc, CHIPC_SPI_FLASHDATA) & 0xff;
  209         return (0);
  210 }
  211 
  212 static int
  213 chipc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  214 {
  215         struct chipc_spi_softc  *sc;
  216         uint8_t         *buf_in;
  217         uint8_t         *buf_out;
  218         int              i;
  219 
  220         sc = device_get_softc(dev);
  221         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
  222             ("TX/RX command sizes should be equal"));
  223         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
  224             ("TX/RX data sizes should be equal"));
  225 
  226         if (cmd->tx_cmd_sz == 0) {
  227                 BHND_DEBUG_DEV(child, "size of command is ZERO");
  228                 return (EIO);
  229         }
  230 
  231         SPI_BARRIER_WRITE(sc);
  232         SPI_WRITE(sc, CHIPC_SPI_FLASHADDR, 0);
  233         SPI_BARRIER_WRITE(sc);
  234 
  235         /*
  236          * Transfer command
  237          */
  238         buf_out = (uint8_t *)cmd->tx_cmd;
  239         buf_in = (uint8_t *)cmd->rx_cmd;
  240         for (i = 0; i < cmd->tx_cmd_sz; i++)
  241                  if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
  242                          return (EIO);
  243 
  244         /*
  245          * Receive/transmit data
  246          */
  247         buf_out = (uint8_t *)cmd->tx_data;
  248         buf_in = (uint8_t *)cmd->rx_data;
  249         for (i = 0; i < cmd->tx_data_sz; i++)
  250                 if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
  251                         return (EIO);
  252 
  253         /*
  254          * Clear CS bit and whole control register
  255          */
  256         SPI_BARRIER_WRITE(sc);
  257         SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, 0);
  258         SPI_BARRIER_WRITE(sc);
  259 
  260         return (0);
  261 }
  262 
  263 static device_method_t chipc_spi_methods[] = {
  264                 DEVMETHOD(device_probe,         chipc_spi_probe),
  265                 DEVMETHOD(device_attach,        chipc_spi_attach),
  266                 DEVMETHOD(device_detach,        chipc_spi_detach),
  267 
  268                 /* SPI */
  269                 DEVMETHOD(spibus_transfer,      chipc_spi_transfer),
  270                 DEVMETHOD_END
  271 };
  272 
  273 static driver_t chipc_spi_driver = {
  274         "spi",
  275         chipc_spi_methods,
  276         sizeof(struct chipc_spi_softc),
  277 };
  278 
  279 DRIVER_MODULE(chipc_spi, bhnd_chipc, chipc_spi_driver, 0, 0);

Cache object: 42b4f3736541c8384255daf301c268be


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