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