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