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