1/*- 2 * Copyright (C) 2009-2012 Semihalf 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* Integrated NAND controller driver */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/proc.h> 35#include <sys/bus.h> 36#include <sys/conf.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <sys/malloc.h> 40#include <sys/rman.h> 41#include <sys/lock.h> 42#include <sys/mutex.h> 43#include <sys/time.h> 44 45#include <machine/bus.h> 46#include <machine/fdt.h> 47#include <arm/mv/mvvar.h> 48#include <arm/mv/mvwin.h> 49 50#include <dev/ofw/ofw_bus.h> 51#include <dev/ofw/ofw_bus_subr.h> 52 53#include <dev/nand/nand.h> 54#include <dev/nand/nandbus.h> 55#include "nfc_if.h" 56 57#define MV_NAND_DATA (0x00) 58#define MV_NAND_COMMAND (0x01) 59#define MV_NAND_ADDRESS (0x02) 60 61struct mv_nand_softc { 62 struct nand_softc nand_dev; 63 bus_space_handle_t sc_handle; 64 bus_space_tag_t sc_tag; 65 struct resource *res; 66 int rid; 67}; 68 69static int mv_nand_attach(device_t); 70static int mv_nand_probe(device_t); 71static int mv_nand_send_command(device_t, uint8_t); 72static int mv_nand_send_address(device_t, uint8_t); 73static uint8_t mv_nand_read_byte(device_t); 74static void mv_nand_read_buf(device_t, void *, uint32_t); 75static void mv_nand_write_buf(device_t, void *, uint32_t); 76static int mv_nand_select_cs(device_t, uint8_t); 77static int mv_nand_read_rnb(device_t); 78 79static device_method_t mv_nand_methods[] = { 80 DEVMETHOD(device_probe, mv_nand_probe), 81 DEVMETHOD(device_attach, mv_nand_attach), 82 83 DEVMETHOD(nfc_send_command, mv_nand_send_command), 84 DEVMETHOD(nfc_send_address, mv_nand_send_address), 85 DEVMETHOD(nfc_read_byte, mv_nand_read_byte), 86 DEVMETHOD(nfc_read_buf, mv_nand_read_buf), 87 DEVMETHOD(nfc_write_buf, mv_nand_write_buf), 88 DEVMETHOD(nfc_select_cs, mv_nand_select_cs), 89 DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), 90 91 { 0, 0 }, 92}; 93 94static driver_t mv_nand_driver = { 95 "nand", 96 mv_nand_methods, 97 sizeof(struct mv_nand_softc), 98}; 99 100static devclass_t mv_nand_devclass; 101DRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); 102 103static int 104mv_nand_probe(device_t dev) 105{ 106 107 if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) 108 return (ENXIO); 109 110 device_set_desc(dev, "Marvell NAND controller"); 111 return (BUS_PROBE_DEFAULT); 112} 113 114static int 115mv_nand_attach(device_t dev) 116{ 117 struct mv_nand_softc *sc; 118 int err; 119 120 sc = device_get_softc(dev); 121 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, 122 RF_ACTIVE); 123 if (sc->res == NULL) { 124 device_printf(dev, "could not allocate resources!\n"); 125 return (ENXIO); 126 } 127 128 sc->sc_tag = rman_get_bustag(sc->res); 129 sc->sc_handle = rman_get_bushandle(sc->res); 130 131 nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); 132 133 err = nandbus_create(dev); 134 135 return (err); 136} 137 138static int 139mv_nand_send_command(device_t dev, uint8_t command) 140{ 141 struct mv_nand_softc *sc; 142 143 nand_debug(NDBG_DRV,"mv_nand: send command %x", command); 144 145 sc = device_get_softc(dev); 146 bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); 147 return (0); 148} 149 150static int 151mv_nand_send_address(device_t dev, uint8_t addr) 152{ 153 struct mv_nand_softc *sc; 154 155 nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); 156 157 sc = device_get_softc(dev); 158 bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); 159 return (0); 160} 161 162static uint8_t 163mv_nand_read_byte(device_t dev) 164{ 165 struct mv_nand_softc *sc; 166 uint8_t data; 167 168 sc = device_get_softc(dev); 169 data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); 170 171 nand_debug(NDBG_DRV,"mv_nand: read %x", data); 172 173 return (data); 174} 175 176static void 177mv_nand_read_buf(device_t dev, void* buf, uint32_t len) 178{ 179 struct mv_nand_softc *sc; 180 int i; 181 uint8_t *b = (uint8_t*)buf; 182 183 sc = device_get_softc(dev); 184 185 for (i = 0; i < len; i++) { 186 b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, 187 MV_NAND_DATA); 188#ifdef NAND_DEBUG 189 if (!(i % 16)) 190 printf("%s", i == 0 ? "mv_nand:\n" : "\n"); 191 printf(" %x", b[i]); 192 if (i == len - 1) 193 printf("\n"); 194#endif 195 } 196} 197 198static void 199mv_nand_write_buf(device_t dev, void* buf, uint32_t len) 200{ 201 struct mv_nand_softc *sc; 202 int i; 203 uint8_t *b = (uint8_t*)buf; 204 205 sc = device_get_softc(dev); 206 207 for (i = 0; i < len; i++) { 208#ifdef NAND_DEBUG 209 if (!(i % 16)) 210 printf("%s", i == 0 ? "mv_nand:\n" : "\n"); 211 printf(" %x", b[i]); 212 if (i == len - 1) 213 printf("\n"); 214#endif 215 bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, 216 b[i]); 217 } 218} 219 220static int 221mv_nand_select_cs(device_t dev, uint8_t cs) 222{ 223 224 if (cs > 0) 225 return (ENODEV); 226 227 return (0); 228} 229 230static int 231mv_nand_read_rnb(device_t dev) 232{ 233 234 /* no-op */ 235 return (0); /* ready */ 236} 237