1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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); 280