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/* Simulated 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/rman.h> 40235537Sgber#include <sys/lock.h> 41235537Sgber#include <sys/mutex.h> 42235537Sgber#include <sys/time.h> 43235537Sgber 44235537Sgber#include <dev/nand/nand.h> 45235537Sgber#include <dev/nand/nandbus.h> 46235537Sgber#include <dev/nand/nandsim.h> 47235537Sgber#include <dev/nand/nandsim_log.h> 48235537Sgber#include <dev/nand/nandsim_chip.h> 49235537Sgber#include "nfc_if.h" 50235537Sgber 51235537Sgber#define ADDRESS_SIZE 5 52235537Sgber 53235537Sgberextern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; 54235537Sgber 55235537Sgberstatic void byte_corrupt(struct nandsim_chip *, uint8_t *); 56235537Sgber 57235537Sgberstatic int nandsim_attach(device_t); 58235537Sgberstatic int nandsim_detach(device_t); 59235537Sgberstatic int nandsim_probe(device_t); 60235537Sgber 61235537Sgberstatic uint8_t nandsim_read_byte(device_t); 62235537Sgberstatic uint16_t nandsim_read_word(device_t); 63235537Sgberstatic int nandsim_select_cs(device_t, uint8_t); 64235537Sgberstatic void nandsim_write_byte(device_t, uint8_t); 65235537Sgberstatic void nandsim_write_word(device_t, uint16_t); 66235537Sgberstatic void nandsim_read_buf(device_t, void *, uint32_t); 67235537Sgberstatic void nandsim_write_buf(device_t, void *, uint32_t); 68235537Sgberstatic int nandsim_send_command(device_t, uint8_t); 69235537Sgberstatic int nandsim_send_address(device_t, uint8_t); 70235537Sgber 71235537Sgberstatic device_method_t nandsim_methods[] = { 72235537Sgber DEVMETHOD(device_probe, nandsim_probe), 73235537Sgber DEVMETHOD(device_attach, nandsim_attach), 74235537Sgber DEVMETHOD(device_detach, nandsim_detach), 75235537Sgber 76235537Sgber DEVMETHOD(nfc_select_cs, nandsim_select_cs), 77235537Sgber DEVMETHOD(nfc_send_command, nandsim_send_command), 78235537Sgber DEVMETHOD(nfc_send_address, nandsim_send_address), 79235537Sgber DEVMETHOD(nfc_read_byte, nandsim_read_byte), 80235537Sgber DEVMETHOD(nfc_read_word, nandsim_read_word), 81235537Sgber DEVMETHOD(nfc_write_byte, nandsim_write_byte), 82235537Sgber DEVMETHOD(nfc_read_buf, nandsim_read_buf), 83235537Sgber DEVMETHOD(nfc_write_buf, nandsim_write_buf), 84235537Sgber 85235537Sgber { 0, 0 }, 86235537Sgber}; 87235537Sgber 88235537Sgberstatic driver_t nandsim_driver = { 89235537Sgber "nandsim", 90235537Sgber nandsim_methods, 91235537Sgber sizeof(struct nandsim_softc), 92235537Sgber}; 93235537Sgber 94235537Sgberstatic devclass_t nandsim_devclass; 95235537SgberDRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); 96235537SgberDRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); 97235537Sgber 98235537Sgberstatic int 99235537Sgbernandsim_probe(device_t dev) 100235537Sgber{ 101235537Sgber 102235537Sgber device_set_desc(dev, "NAND controller simulator"); 103235537Sgber return (BUS_PROBE_DEFAULT); 104235537Sgber} 105235537Sgber 106235537Sgberstatic int 107235537Sgbernandsim_attach(device_t dev) 108235537Sgber{ 109235537Sgber struct nandsim_softc *sc; 110235537Sgber struct sim_ctrl_conf *params; 111235537Sgber struct sim_chip *chip; 112235537Sgber uint16_t *eccpos; 113235537Sgber int i, err; 114235537Sgber 115235537Sgber sc = device_get_softc(dev); 116235537Sgber params = &ctrls[device_get_unit(dev)]; 117235537Sgber 118235537Sgber if (strlen(params->filename) == 0) 119235537Sgber snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", 120235537Sgber params->num); 121235537Sgber 122235537Sgber nandsim_log_init(sc, params->filename); 123235537Sgber for (i = 0; i < params->num_cs; i++) { 124235537Sgber chip = params->chips[i]; 125235537Sgber if (chip && chip->device_id != 0) { 126235537Sgber sc->chips[i] = nandsim_chip_init(sc, i, chip); 127235537Sgber if (chip->features & ONFI_FEAT_16BIT) 128235537Sgber sc->nand_dev.flags |= NAND_16_BIT; 129235537Sgber } 130235537Sgber } 131235537Sgber 132235537Sgber if (params->ecc_layout[0] != 0xffff) 133235537Sgber eccpos = params->ecc_layout; 134235537Sgber else 135235537Sgber eccpos = NULL; 136235537Sgber 137235537Sgber nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); 138235537Sgber 139235537Sgber err = nandbus_create(dev); 140235537Sgber 141235537Sgber return (err); 142235537Sgber} 143235537Sgber 144235537Sgberstatic int 145235537Sgbernandsim_detach(device_t dev) 146235537Sgber{ 147235537Sgber struct nandsim_softc *sc; 148235537Sgber struct sim_ctrl_conf *params; 149235537Sgber int i; 150235537Sgber 151235537Sgber sc = device_get_softc(dev); 152235537Sgber params = &ctrls[device_get_unit(dev)]; 153235537Sgber 154235537Sgber for (i = 0; i < params->num_cs; i++) 155235537Sgber if (sc->chips[i] != NULL) 156235537Sgber nandsim_chip_destroy(sc->chips[i]); 157235537Sgber 158235537Sgber nandsim_log_close(sc); 159235537Sgber 160235537Sgber return (0); 161235537Sgber} 162235537Sgber 163235537Sgberstatic int 164235537Sgbernandsim_select_cs(device_t dev, uint8_t cs) 165235537Sgber{ 166235537Sgber struct nandsim_softc *sc; 167235537Sgber 168235537Sgber sc = device_get_softc(dev); 169235537Sgber 170235537Sgber if (cs >= MAX_CS_NUM) 171235537Sgber return (EINVAL); 172235537Sgber 173235537Sgber sc->active_chip = sc->chips[cs]; 174235537Sgber 175235537Sgber if (sc->active_chip) 176235537Sgber nandsim_log(sc->active_chip, NANDSIM_LOG_EV, 177235537Sgber "Select cs %d\n", cs); 178235537Sgber 179235537Sgber return (0); 180235537Sgber} 181235537Sgber 182235537Sgberstatic int 183235537Sgbernandsim_send_command(device_t dev, uint8_t command) 184235537Sgber{ 185235537Sgber struct nandsim_softc *sc; 186235537Sgber struct nandsim_chip *chip; 187235537Sgber struct nandsim_ev *ev; 188235537Sgber 189235537Sgber sc = device_get_softc(dev); 190235537Sgber chip = sc->active_chip; 191235537Sgber 192235537Sgber if (chip == NULL) 193235537Sgber return (0); 194235537Sgber 195235537Sgber nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); 196235537Sgber 197235537Sgber switch (command) { 198235537Sgber case NAND_CMD_READ_ID: 199235537Sgber case NAND_CMD_READ_PARAMETER: 200235537Sgber sc->address_type = ADDR_ID; 201235537Sgber break; 202235537Sgber case NAND_CMD_ERASE: 203235537Sgber sc->address_type = ADDR_ROW; 204235537Sgber break; 205235537Sgber case NAND_CMD_READ: 206235537Sgber case NAND_CMD_PROG: 207235537Sgber sc->address_type = ADDR_ROWCOL; 208235537Sgber break; 209235537Sgber default: 210235537Sgber sc->address_type = ADDR_NONE; 211235537Sgber break; 212235537Sgber } 213235537Sgber 214235537Sgber if (command == NAND_CMD_STATUS) 215235537Sgber chip->flags |= NANDSIM_CHIP_GET_STATUS; 216235537Sgber else { 217235537Sgber ev = create_event(chip, NANDSIM_EV_CMD, 1); 218235537Sgber *(uint8_t *)ev->data = command; 219235537Sgber send_event(ev); 220235537Sgber } 221235537Sgber 222235537Sgber return (0); 223235537Sgber} 224235537Sgber 225235537Sgberstatic int 226235537Sgbernandsim_send_address(device_t dev, uint8_t addr) 227235537Sgber{ 228235537Sgber struct nandsim_ev *ev; 229235537Sgber struct nandsim_softc *sc; 230235537Sgber struct nandsim_chip *chip; 231235537Sgber 232235537Sgber sc = device_get_softc(dev); 233235537Sgber chip = sc->active_chip; 234235537Sgber 235235537Sgber if (chip == NULL) 236235537Sgber return (0); 237235537Sgber 238235537Sgber KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); 239235537Sgber nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); 240235537Sgber 241235537Sgber ev = create_event(chip, NANDSIM_EV_ADDR, 1); 242235537Sgber 243235537Sgber *((uint8_t *)(ev->data)) = addr; 244235537Sgber 245235537Sgber send_event(ev); 246235537Sgber return (0); 247235537Sgber} 248235537Sgber 249235537Sgberstatic uint8_t 250235537Sgbernandsim_read_byte(device_t dev) 251235537Sgber{ 252235537Sgber struct nandsim_softc *sc; 253235537Sgber struct nandsim_chip *chip; 254235537Sgber uint8_t ret = 0xff; 255235537Sgber 256235537Sgber sc = device_get_softc(dev); 257235537Sgber chip = sc->active_chip; 258235537Sgber 259235537Sgber if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 260235537Sgber if (chip->flags & NANDSIM_CHIP_GET_STATUS) { 261235537Sgber nandsim_chip_timeout(chip); 262235537Sgber ret = nandchip_get_status(chip); 263235537Sgber chip->flags &= ~NANDSIM_CHIP_GET_STATUS; 264235537Sgber } else if (chip->data.index < chip->data.size) { 265235537Sgber ret = chip->data.data_ptr[chip->data.index++]; 266235537Sgber byte_corrupt(chip, &ret); 267235537Sgber } 268235537Sgber nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); 269235537Sgber } 270235537Sgber 271235537Sgber return (ret); 272235537Sgber} 273235537Sgber 274235537Sgberstatic uint16_t 275235537Sgbernandsim_read_word(device_t dev) 276235537Sgber{ 277235537Sgber struct nandsim_softc *sc; 278235537Sgber struct nandsim_chip *chip; 279235537Sgber uint16_t *data_ptr; 280235537Sgber uint16_t ret = 0xffff; 281235537Sgber uint8_t *byte_ret = (uint8_t *)&ret; 282235537Sgber 283235537Sgber sc = device_get_softc(dev); 284235537Sgber chip = sc->active_chip; 285235537Sgber 286235537Sgber if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 287235537Sgber if (chip->data.index < chip->data.size - 1) { 288235537Sgber data_ptr = 289235537Sgber (uint16_t *)&(chip->data.data_ptr[chip->data.index]); 290235537Sgber ret = *data_ptr; 291235537Sgber chip->data.index += 2; 292235537Sgber byte_corrupt(chip, byte_ret); 293235537Sgber byte_corrupt(chip, byte_ret + 1); 294235537Sgber } 295235537Sgber nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); 296235537Sgber } 297235537Sgber 298235537Sgber return (ret); 299235537Sgber} 300235537Sgber 301235537Sgberstatic void 302235537Sgbernandsim_write_byte(device_t dev, uint8_t byte) 303235537Sgber{ 304235537Sgber struct nandsim_softc *sc; 305235537Sgber struct nandsim_chip *chip; 306235537Sgber 307235537Sgber sc = device_get_softc(dev); 308235537Sgber chip = sc->active_chip; 309235537Sgber 310235537Sgber if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && 311235537Sgber (chip->data.index < chip->data.size)) { 312235537Sgber byte_corrupt(chip, &byte); 313235537Sgber chip->data.data_ptr[chip->data.index] &= byte; 314235537Sgber chip->data.index++; 315235537Sgber nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); 316235537Sgber } 317235537Sgber} 318235537Sgber 319235537Sgberstatic void 320235537Sgbernandsim_write_word(device_t dev, uint16_t word) 321235537Sgber{ 322235537Sgber struct nandsim_softc *sc; 323235537Sgber struct nandsim_chip *chip; 324235537Sgber uint16_t *data_ptr; 325235537Sgber uint8_t *byte_ptr = (uint8_t *)&word; 326235537Sgber 327235537Sgber sc = device_get_softc(dev); 328235537Sgber chip = sc->active_chip; 329235537Sgber 330235537Sgber if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { 331235537Sgber if ((chip->data.index + 1) < chip->data.size) { 332235537Sgber byte_corrupt(chip, byte_ptr); 333235537Sgber byte_corrupt(chip, byte_ptr + 1); 334235537Sgber data_ptr = 335235537Sgber (uint16_t *)&(chip->data.data_ptr[chip->data.index]); 336235537Sgber *data_ptr &= word; 337235537Sgber chip->data.index += 2; 338235537Sgber } 339235537Sgber 340235537Sgber nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); 341235537Sgber } 342235537Sgber} 343235537Sgber 344235537Sgberstatic void 345235537Sgbernandsim_read_buf(device_t dev, void *buf, uint32_t len) 346235537Sgber{ 347235537Sgber struct nandsim_softc *sc; 348235537Sgber uint16_t *buf16 = (uint16_t *)buf; 349235537Sgber uint8_t *buf8 = (uint8_t *)buf; 350235537Sgber int i; 351235537Sgber 352235537Sgber sc = device_get_softc(dev); 353235537Sgber 354235537Sgber if (sc->nand_dev.flags & NAND_16_BIT) { 355235537Sgber for (i = 0; i < len / 2; i++) 356235537Sgber buf16[i] = nandsim_read_word(dev); 357235537Sgber } else { 358235537Sgber for (i = 0; i < len; i++) 359235537Sgber buf8[i] = nandsim_read_byte(dev); 360235537Sgber } 361235537Sgber} 362235537Sgber 363235537Sgberstatic void 364235537Sgbernandsim_write_buf(device_t dev, void *buf, uint32_t len) 365235537Sgber{ 366235537Sgber struct nandsim_softc *sc; 367235537Sgber uint16_t *buf16 = (uint16_t *)buf; 368235537Sgber uint8_t *buf8 = (uint8_t *)buf; 369235537Sgber int i; 370235537Sgber 371235537Sgber sc = device_get_softc(dev); 372235537Sgber 373235537Sgber if (sc->nand_dev.flags & NAND_16_BIT) { 374235537Sgber for (i = 0; i < len / 2; i++) 375235537Sgber nandsim_write_word(dev, buf16[i]); 376235537Sgber } else { 377235537Sgber for (i = 0; i < len; i++) 378235537Sgber nandsim_write_byte(dev, buf8[i]); 379235537Sgber } 380235537Sgber} 381235537Sgber 382235537Sgberstatic void 383235537Sgberbyte_corrupt(struct nandsim_chip *chip, uint8_t *byte) 384235537Sgber{ 385235537Sgber uint32_t rand; 386235537Sgber uint8_t bit; 387235537Sgber 388235537Sgber rand = random(); 389235537Sgber if ((rand % 1000000) < chip->error_ratio) { 390235537Sgber bit = rand % 8; 391235537Sgber if (*byte & (1 << bit)) 392235537Sgber *byte &= ~(1 << bit); 393235537Sgber else 394235537Sgber *byte |= (1 << bit); 395235537Sgber } 396235537Sgber} 397