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/* Simulated 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/rman.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42#include <sys/time.h> 43 44#include <dev/nand/nand.h> 45#include <dev/nand/nandbus.h> 46#include <dev/nand/nandsim.h> 47#include <dev/nand/nandsim_log.h> 48#include <dev/nand/nandsim_chip.h> 49#include "nfc_if.h" 50 51#define ADDRESS_SIZE 5 52 53extern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; 54 55static void byte_corrupt(struct nandsim_chip *, uint8_t *); 56 57static int nandsim_attach(device_t); 58static int nandsim_detach(device_t); 59static int nandsim_probe(device_t); 60 61static uint8_t nandsim_read_byte(device_t); 62static uint16_t nandsim_read_word(device_t); 63static int nandsim_select_cs(device_t, uint8_t); 64static void nandsim_write_byte(device_t, uint8_t); 65static void nandsim_write_word(device_t, uint16_t); 66static void nandsim_read_buf(device_t, void *, uint32_t); 67static void nandsim_write_buf(device_t, void *, uint32_t); 68static int nandsim_send_command(device_t, uint8_t); 69static int nandsim_send_address(device_t, uint8_t); 70 71static device_method_t nandsim_methods[] = { 72 DEVMETHOD(device_probe, nandsim_probe), 73 DEVMETHOD(device_attach, nandsim_attach), 74 DEVMETHOD(device_detach, nandsim_detach), 75 76 DEVMETHOD(nfc_select_cs, nandsim_select_cs), 77 DEVMETHOD(nfc_send_command, nandsim_send_command), 78 DEVMETHOD(nfc_send_address, nandsim_send_address), 79 DEVMETHOD(nfc_read_byte, nandsim_read_byte), 80 DEVMETHOD(nfc_read_word, nandsim_read_word), 81 DEVMETHOD(nfc_write_byte, nandsim_write_byte), 82 DEVMETHOD(nfc_read_buf, nandsim_read_buf), 83 DEVMETHOD(nfc_write_buf, nandsim_write_buf), 84 85 { 0, 0 }, 86}; 87 88static driver_t nandsim_driver = { 89 "nandsim", 90 nandsim_methods, 91 sizeof(struct nandsim_softc), 92}; 93 94static devclass_t nandsim_devclass; 95DRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); 96DRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); 97 98static int 99nandsim_probe(device_t dev) 100{ 101 102 device_set_desc(dev, "NAND controller simulator"); 103 return (BUS_PROBE_DEFAULT); 104} 105 106static int 107nandsim_attach(device_t dev) 108{ 109 struct nandsim_softc *sc; 110 struct sim_ctrl_conf *params; 111 struct sim_chip *chip; 112 uint16_t *eccpos; 113 int i, err; 114 115 sc = device_get_softc(dev); 116 params = &ctrls[device_get_unit(dev)]; 117 118 if (strlen(params->filename) == 0) 119 snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", 120 params->num); 121 122 nandsim_log_init(sc, params->filename); 123 for (i = 0; i < params->num_cs; i++) { 124 chip = params->chips[i]; 125 if (chip && chip->device_id != 0) { 126 sc->chips[i] = nandsim_chip_init(sc, i, chip); 127 if (chip->features & ONFI_FEAT_16BIT) 128 sc->nand_dev.flags |= NAND_16_BIT; 129 } 130 } 131 132 if (params->ecc_layout[0] != 0xffff) 133 eccpos = params->ecc_layout; 134 else 135 eccpos = NULL; 136 137 nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); 138 139 err = nandbus_create(dev); 140 141 return (err); 142} 143 144static int 145nandsim_detach(device_t dev) 146{ 147 struct nandsim_softc *sc; 148 struct sim_ctrl_conf *params; 149 int i; 150 151 sc = device_get_softc(dev); 152 params = &ctrls[device_get_unit(dev)]; 153 154 for (i = 0; i < params->num_cs; i++) 155 if (sc->chips[i] != NULL) 156 nandsim_chip_destroy(sc->chips[i]); 157 158 nandsim_log_close(sc); 159 160 return (0); 161} 162 163static int 164nandsim_select_cs(device_t dev, uint8_t cs) 165{ 166 struct nandsim_softc *sc; 167 168 sc = device_get_softc(dev); 169 170 if (cs >= MAX_CS_NUM) 171 return (EINVAL); 172 173 sc->active_chip = sc->chips[cs]; 174 175 if (sc->active_chip) 176 nandsim_log(sc->active_chip, NANDSIM_LOG_EV, 177 "Select cs %d\n", cs); 178 179 return (0); 180} 181 182static int 183nandsim_send_command(device_t dev, uint8_t command) 184{ 185 struct nandsim_softc *sc; 186 struct nandsim_chip *chip; 187 struct nandsim_ev *ev; 188 189 sc = device_get_softc(dev); 190 chip = sc->active_chip; 191 192 if (chip == NULL) 193 return (0); 194 195 nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); 196 197 switch (command) { 198 case NAND_CMD_READ_ID: 199 case NAND_CMD_READ_PARAMETER: 200 sc->address_type = ADDR_ID; 201 break; 202 case NAND_CMD_ERASE: 203 sc->address_type = ADDR_ROW; 204 break; 205 case NAND_CMD_READ: 206 case NAND_CMD_PROG: 207 sc->address_type = ADDR_ROWCOL; 208 break; 209 default: 210 sc->address_type = ADDR_NONE; 211 break; 212 } 213 214 if (command == NAND_CMD_STATUS) 215 chip->flags |= NANDSIM_CHIP_GET_STATUS; 216 else { 217 ev = create_event(chip, NANDSIM_EV_CMD, 1); 218 *(uint8_t *)ev->data = command; 219 send_event(ev); 220 } 221 222 return (0); 223} 224 225static int 226nandsim_send_address(device_t dev, uint8_t addr) 227{ 228 struct nandsim_ev *ev; 229 struct nandsim_softc *sc; 230 struct nandsim_chip *chip; 231 232 sc = device_get_softc(dev); 233 chip = sc->active_chip; 234 235 if (chip == NULL) 236 return (0); 237 238 KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); 239 nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); 240 241 ev = create_event(chip, NANDSIM_EV_ADDR, 1); 242 243 *((uint8_t *)(ev->data)) = addr; 244 245 send_event(ev); 246 return (0); 247} 248 249static uint8_t 250nandsim_read_byte(device_t dev) 251{ 252 struct nandsim_softc *sc; 253 struct nandsim_chip *chip; 254 uint8_t ret = 0xff; 255 256 sc = device_get_softc(dev); 257 chip = sc->active_chip; 258 259 if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 260 if (chip->flags & NANDSIM_CHIP_GET_STATUS) { 261 nandsim_chip_timeout(chip); 262 ret = nandchip_get_status(chip); 263 chip->flags &= ~NANDSIM_CHIP_GET_STATUS; 264 } else if (chip->data.index < chip->data.size) { 265 ret = chip->data.data_ptr[chip->data.index++]; 266 byte_corrupt(chip, &ret); 267 } 268 nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); 269 } 270 271 return (ret); 272} 273 274static uint16_t 275nandsim_read_word(device_t dev) 276{ 277 struct nandsim_softc *sc; 278 struct nandsim_chip *chip; 279 uint16_t *data_ptr; 280 uint16_t ret = 0xffff; 281 uint8_t *byte_ret = (uint8_t *)&ret; 282 283 sc = device_get_softc(dev); 284 chip = sc->active_chip; 285 286 if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 287 if (chip->data.index < chip->data.size - 1) { 288 data_ptr = 289 (uint16_t *)&(chip->data.data_ptr[chip->data.index]); 290 ret = *data_ptr; 291 chip->data.index += 2; 292 byte_corrupt(chip, byte_ret); 293 byte_corrupt(chip, byte_ret + 1); 294 } 295 nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); 296 } 297 298 return (ret); 299} 300 301static void 302nandsim_write_byte(device_t dev, uint8_t byte) 303{ 304 struct nandsim_softc *sc; 305 struct nandsim_chip *chip; 306 307 sc = device_get_softc(dev); 308 chip = sc->active_chip; 309 310 if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && 311 (chip->data.index < chip->data.size)) { 312 byte_corrupt(chip, &byte); 313 chip->data.data_ptr[chip->data.index] &= byte; 314 chip->data.index++; 315 nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); 316 } 317} 318 319static void 320nandsim_write_word(device_t dev, uint16_t word) 321{ 322 struct nandsim_softc *sc; 323 struct nandsim_chip *chip; 324 uint16_t *data_ptr; 325 uint8_t *byte_ptr = (uint8_t *)&word; 326 327 sc = device_get_softc(dev); 328 chip = sc->active_chip; 329 330 if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 331 if ((chip->data.index + 1) < chip->data.size) { 332 byte_corrupt(chip, byte_ptr); 333 byte_corrupt(chip, byte_ptr + 1); 334 data_ptr = 335 (uint16_t *)&(chip->data.data_ptr[chip->data.index]); 336 *data_ptr &= word; 337 chip->data.index += 2; 338 } 339 340 nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); 341 } 342} 343 344static void 345nandsim_read_buf(device_t dev, void *buf, uint32_t len) 346{ 347 struct nandsim_softc *sc; 348 uint16_t *buf16 = (uint16_t *)buf; 349 uint8_t *buf8 = (uint8_t *)buf; 350 int i; 351 352 sc = device_get_softc(dev); 353 354 if (sc->nand_dev.flags & NAND_16_BIT) { 355 for (i = 0; i < len / 2; i++) 356 buf16[i] = nandsim_read_word(dev); 357 } else { 358 for (i = 0; i < len; i++) 359 buf8[i] = nandsim_read_byte(dev); 360 } 361} 362 363static void 364nandsim_write_buf(device_t dev, void *buf, uint32_t len) 365{ 366 struct nandsim_softc *sc; 367 uint16_t *buf16 = (uint16_t *)buf; 368 uint8_t *buf8 = (uint8_t *)buf; 369 int i; 370 371 sc = device_get_softc(dev); 372 373 if (sc->nand_dev.flags & NAND_16_BIT) { 374 for (i = 0; i < len / 2; i++) 375 nandsim_write_word(dev, buf16[i]); 376 } else { 377 for (i = 0; i < len; i++) 378 nandsim_write_byte(dev, buf8[i]); 379 } 380} 381 382static void 383byte_corrupt(struct nandsim_chip *chip, uint8_t *byte) 384{ 385 uint32_t rand; 386 uint8_t bit; 387 388 rand = random(); 389 if ((rand % 1000000) < chip->error_ratio) { 390 bit = rand % 8; 391 if (*byte & (1 << bit)) 392 *byte &= ~(1 << bit); 393 else 394 *byte |= (1 << bit); 395 } 396} 397