1235537Sgber/*- 2235537Sgber * Copyright (C) 2009-2012 Semihalf 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber/* Integrated NAND controller driver */ 28235537Sgber 29235537Sgber#include <sys/cdefs.h> 30235537Sgber__FBSDID("$FreeBSD$"); 31235537Sgber 32235537Sgber#include <sys/param.h> 33235537Sgber#include <sys/systm.h> 34235537Sgber#include <sys/proc.h> 35235537Sgber#include <sys/bus.h> 36235537Sgber#include <sys/conf.h> 37235537Sgber#include <sys/kernel.h> 38235537Sgber#include <sys/module.h> 39235537Sgber#include <sys/malloc.h> 40235537Sgber#include <sys/rman.h> 41235537Sgber#include <sys/lock.h> 42235537Sgber#include <sys/mutex.h> 43235537Sgber#include <sys/time.h> 44235537Sgber 45235537Sgber#include <machine/bus.h> 46235537Sgber#include <machine/fdt.h> 47235537Sgber#include <arm/mv/mvvar.h> 48235537Sgber#include <arm/mv/mvwin.h> 49235537Sgber 50235537Sgber#include <dev/ofw/ofw_bus.h> 51235537Sgber#include <dev/ofw/ofw_bus_subr.h> 52235537Sgber 53235537Sgber#include <dev/nand/nand.h> 54235537Sgber#include <dev/nand/nandbus.h> 55235537Sgber#include "nfc_if.h" 56235537Sgber 57235537Sgber#define MV_NAND_DATA (0x00) 58235537Sgber#define MV_NAND_COMMAND (0x01) 59235537Sgber#define MV_NAND_ADDRESS (0x02) 60235537Sgber 61235537Sgberstruct mv_nand_softc { 62235537Sgber struct nand_softc nand_dev; 63235537Sgber bus_space_handle_t sc_handle; 64235537Sgber bus_space_tag_t sc_tag; 65235537Sgber struct resource *res; 66235537Sgber int rid; 67235537Sgber}; 68235537Sgber 69235537Sgberstatic int mv_nand_attach(device_t); 70235537Sgberstatic int mv_nand_probe(device_t); 71235537Sgberstatic int mv_nand_send_command(device_t, uint8_t); 72235537Sgberstatic int mv_nand_send_address(device_t, uint8_t); 73235537Sgberstatic uint8_t mv_nand_read_byte(device_t); 74235537Sgberstatic void mv_nand_read_buf(device_t, void *, uint32_t); 75235537Sgberstatic void mv_nand_write_buf(device_t, void *, uint32_t); 76235537Sgberstatic int mv_nand_select_cs(device_t, uint8_t); 77235537Sgberstatic int mv_nand_read_rnb(device_t); 78235537Sgber 79235537Sgberstatic device_method_t mv_nand_methods[] = { 80235537Sgber DEVMETHOD(device_probe, mv_nand_probe), 81235537Sgber DEVMETHOD(device_attach, mv_nand_attach), 82235537Sgber 83235537Sgber DEVMETHOD(nfc_send_command, mv_nand_send_command), 84235537Sgber DEVMETHOD(nfc_send_address, mv_nand_send_address), 85235537Sgber DEVMETHOD(nfc_read_byte, mv_nand_read_byte), 86235537Sgber DEVMETHOD(nfc_read_buf, mv_nand_read_buf), 87235537Sgber DEVMETHOD(nfc_write_buf, mv_nand_write_buf), 88235537Sgber DEVMETHOD(nfc_select_cs, mv_nand_select_cs), 89235537Sgber DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), 90235537Sgber 91235537Sgber { 0, 0 }, 92235537Sgber}; 93235537Sgber 94235537Sgberstatic driver_t mv_nand_driver = { 95235537Sgber "nand", 96235537Sgber mv_nand_methods, 97235537Sgber sizeof(struct mv_nand_softc), 98235537Sgber}; 99235537Sgber 100235537Sgberstatic devclass_t mv_nand_devclass; 101235537SgberDRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); 102235537Sgber 103235537Sgberstatic int 104235537Sgbermv_nand_probe(device_t dev) 105235537Sgber{ 106235537Sgber 107235537Sgber if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) 108235537Sgber return (ENXIO); 109235537Sgber 110235537Sgber device_set_desc(dev, "Marvell NAND controller"); 111235537Sgber return (BUS_PROBE_DEFAULT); 112235537Sgber} 113235537Sgber 114235537Sgberstatic int 115235537Sgbermv_nand_attach(device_t dev) 116235537Sgber{ 117235537Sgber struct mv_nand_softc *sc; 118235537Sgber int err; 119235537Sgber 120235537Sgber sc = device_get_softc(dev); 121235537Sgber sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, 122235537Sgber RF_ACTIVE); 123235537Sgber if (sc->res == NULL) { 124235537Sgber device_printf(dev, "could not allocate resources!\n"); 125235537Sgber return (ENXIO); 126235537Sgber } 127235537Sgber 128235537Sgber sc->sc_tag = rman_get_bustag(sc->res); 129235537Sgber sc->sc_handle = rman_get_bushandle(sc->res); 130235537Sgber 131235537Sgber nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); 132235537Sgber 133235537Sgber err = nandbus_create(dev); 134235537Sgber 135235537Sgber return (err); 136235537Sgber} 137235537Sgber 138235537Sgberstatic int 139235537Sgbermv_nand_send_command(device_t dev, uint8_t command) 140235537Sgber{ 141235537Sgber struct mv_nand_softc *sc; 142235537Sgber 143235537Sgber nand_debug(NDBG_DRV,"mv_nand: send command %x", command); 144235537Sgber 145235537Sgber sc = device_get_softc(dev); 146235537Sgber bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); 147235537Sgber return (0); 148235537Sgber} 149235537Sgber 150235537Sgberstatic int 151235537Sgbermv_nand_send_address(device_t dev, uint8_t addr) 152235537Sgber{ 153235537Sgber struct mv_nand_softc *sc; 154235537Sgber 155235537Sgber nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); 156235537Sgber 157235537Sgber sc = device_get_softc(dev); 158235537Sgber bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); 159235537Sgber return (0); 160235537Sgber} 161235537Sgber 162235537Sgberstatic uint8_t 163235537Sgbermv_nand_read_byte(device_t dev) 164235537Sgber{ 165235537Sgber struct mv_nand_softc *sc; 166235537Sgber uint8_t data; 167235537Sgber 168235537Sgber sc = device_get_softc(dev); 169235537Sgber data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); 170235537Sgber 171235537Sgber nand_debug(NDBG_DRV,"mv_nand: read %x", data); 172235537Sgber 173235537Sgber return (data); 174235537Sgber} 175235537Sgber 176235537Sgberstatic void 177235537Sgbermv_nand_read_buf(device_t dev, void* buf, uint32_t len) 178235537Sgber{ 179235537Sgber struct mv_nand_softc *sc; 180235537Sgber int i; 181235537Sgber uint8_t *b = (uint8_t*)buf; 182235537Sgber 183235537Sgber sc = device_get_softc(dev); 184235537Sgber 185235537Sgber for (i = 0; i < len; i++) { 186235537Sgber b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, 187235537Sgber MV_NAND_DATA); 188235537Sgber#ifdef NAND_DEBUG 189235537Sgber if (!(i % 16)) 190235537Sgber printf("%s", i == 0 ? "mv_nand:\n" : "\n"); 191235537Sgber printf(" %x", b[i]); 192235537Sgber if (i == len - 1) 193235537Sgber printf("\n"); 194235537Sgber#endif 195235537Sgber } 196235537Sgber} 197235537Sgber 198235537Sgberstatic void 199235537Sgbermv_nand_write_buf(device_t dev, void* buf, uint32_t len) 200235537Sgber{ 201235537Sgber struct mv_nand_softc *sc; 202235537Sgber int i; 203235537Sgber uint8_t *b = (uint8_t*)buf; 204235537Sgber 205235537Sgber sc = device_get_softc(dev); 206235537Sgber 207235537Sgber for (i = 0; i < len; i++) { 208235537Sgber#ifdef NAND_DEBUG 209235537Sgber if (!(i % 16)) 210235537Sgber printf("%s", i == 0 ? "mv_nand:\n" : "\n"); 211235537Sgber printf(" %x", b[i]); 212235537Sgber if (i == len - 1) 213235537Sgber printf("\n"); 214235537Sgber#endif 215235537Sgber bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, 216235537Sgber b[i]); 217235537Sgber } 218235537Sgber} 219235537Sgber 220235537Sgberstatic int 221235537Sgbermv_nand_select_cs(device_t dev, uint8_t cs) 222235537Sgber{ 223235537Sgber 224235537Sgber if (cs > 0) 225235537Sgber return (ENODEV); 226235537Sgber 227235537Sgber return (0); 228235537Sgber} 229235537Sgber 230235537Sgberstatic int 231235537Sgbermv_nand_read_rnb(device_t dev) 232235537Sgber{ 233235537Sgber 234235537Sgber /* no-op */ 235235537Sgber return (0); /* ready */ 236235537Sgber} 237