1 /* $NetBSD: rmixl_nand.c,v 1.8 2023/05/10 00:07:58 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by the Department of Software Engineering, University of Szeged, Hungary
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * Device driver for the RMI XLS NAND controller
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: rmixl_nand.c,v 1.8 2023/05/10 00:07:58 riastradh Exp $");
40
41 #include "opt_flash.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/cdefs.h>
46 #include <sys/device.h>
47 #include <sys/endian.h>
48
49 #include <sys/bus.h>
50
51 #include <mips/rmi/rmixlreg.h>
52 #include <mips/rmi/rmixlvar.h>
53 #include <mips/rmi/rmixl_iobusvar.h>
54 #include <mips/rmi/rmixl_intr.h>
55
56 #include <dev/nand/nand.h>
57 #include <dev/nand/onfi.h>
58
59
60 static int rmixl_nand_match(device_t, cfdata_t, void *);
61 static void rmixl_nand_attach(device_t, device_t, void *);
62 static int rmixl_nand_detach(device_t, int);
63 static void rmixl_nand_command(device_t, uint8_t);
64 static void rmixl_nand_address(device_t, uint8_t);
65 static void rmixl_nand_busy(device_t);
66 static void rmixl_nand_read_1(device_t, uint8_t *);
67 static void rmixl_nand_write_1(device_t, uint8_t);
68 static void rmixl_nand_read_2(device_t, uint16_t *);
69 static void rmixl_nand_write_2(device_t, uint16_t);
70 static void rmixl_nand_read_buf(device_t, void *, size_t);
71 static void rmixl_nand_write_buf(device_t, const void *, size_t);
72
73
74 struct rmixl_nand_softc {
75 device_t sc_dev;
76 device_t sc_nanddev;
77 struct iobus_softc *sc_iobus_sc;
78
79 int sc_cs; /* chip select index */
80 int sc_buswidth; /* in bytes */
81
82 struct nand_interface sc_nand_if;
83
84 bus_space_tag_t sc_obio_bst;
85 bus_space_handle_t sc_obio_bsh;
86 u_long sc_cmd_reg;
87 u_long sc_addr_reg;
88
89 bus_addr_t sc_iobus_addr;
90 bus_size_t sc_iobus_size;
91 bus_space_tag_t sc_iobus_bst;
92 bus_space_handle_t sc_iobus_bsh;
93 u_long sc_data_reg;
94
95 };
96
97 CFATTACH_DECL_NEW(rmixl_nand, sizeof(struct rmixl_nand_softc), rmixl_nand_match,
98 rmixl_nand_attach, rmixl_nand_detach, NULL);
99
100 static int
rmixl_nand_match(device_t parent,cfdata_t match,void * aux)101 rmixl_nand_match(device_t parent, cfdata_t match, void *aux)
102 {
103 struct rmixl_iobus_attach_args *ia = aux;
104 bus_space_handle_t bsh;
105 volatile uint32_t *vaddr;
106 int err;
107 int rv;
108
109 if ((ia->ia_dev_parm & RMIXL_FLASH_CSDEV_NANDEN) == 0)
110 return 0; /* not NAND */
111
112 if (cpu_rmixlp(mips_options.mips_cpu)) {
113 aprint_error("%s: NAND not yet supported on XLP", __func__);
114 return 0;
115 }
116
117 if (! cpu_rmixls(mips_options.mips_cpu)) {
118 aprint_error("%s: NAND not supported on this processor",
119 __func__);
120 return 0;
121 }
122
123 /*
124 * probe for NAND -- this may be redundant
125 * if the device isn't there, the NANDEN test (above)
126 * should have failed
127 */
128 err = bus_space_map(ia->ia_iobus_bst, ia->ia_iobus_addr,
129 sizeof(uint32_t), 0, &bsh);
130 if (err != 0) {
131 aprint_debug("%s: bus_space_map err %d, "
132 "iobus space addr %#" PRIxBUSADDR "\n",
133 __func__, err, ia->ia_iobus_addr);
134 return 0;
135 }
136
137 vaddr = bus_space_vaddr(ia->ia_iobus_bst, bsh);
138 rv = rmixl_probe_4(vaddr);
139 if (rv == 0)
140 aprint_debug("%s: rmixl_probe_4 failed, vaddr %p\n",
141 __func__, vaddr);
142
143 bus_space_unmap(ia->ia_iobus_bst, bsh, sizeof(uint32_t));
144
145 return rv;
146 }
147
148 static void
rmixl_nand_attach(device_t parent,device_t self,void * aux)149 rmixl_nand_attach(device_t parent, device_t self, void *aux)
150 {
151 struct rmixl_nand_softc *sc = device_private(self);
152 sc->sc_iobus_sc = device_private(parent);
153 struct rmixl_iobus_attach_args *ia = aux;
154 uint32_t val;
155 int err;
156
157 aprint_normal("\n");
158
159 sc->sc_dev = self;
160 sc->sc_obio_bst = ia->ia_obio_bst;
161 sc->sc_obio_bsh = ia->ia_obio_bsh;
162 sc->sc_iobus_bst = ia->ia_iobus_bst;
163 sc->sc_iobus_addr = ia->ia_iobus_addr;
164 sc->sc_iobus_size = sizeof(uint32_t);
165 sc->sc_cs = ia->ia_cs;
166
167 sc->sc_cmd_reg = RMIXL_NAND_CLEn(ia->ia_cs);
168 sc->sc_addr_reg = RMIXL_NAND_ALEn(ia->ia_cs);
169
170 aprint_debug_dev(self, "CS#%d cstime_parma %#x, cstime_parmb %#x\n",
171 ia->ia_cs,
172 bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh,
173 RMIXL_FLASH_CSTIME_PARMAn(ia->ia_cs)),
174 bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh,
175 RMIXL_FLASH_CSTIME_PARMBn(ia->ia_cs)));
176
177 err = bus_space_map(sc->sc_iobus_bst, sc->sc_iobus_addr,
178 sc->sc_iobus_size, 0, &sc->sc_iobus_bsh);
179 if (err != 0) {
180 aprint_error_dev(self,
181 "bus space map err %d, iobus space\n", err);
182 return;
183 }
184
185 /*
186 * determine buswidth
187 */
188 val = ia->ia_dev_parm;
189 val &= RMIXL_FLASH_CSDEV_DWIDTH;
190 val >>= RMIXL_FLASH_CSDEV_DWIDTH_SHFT;
191 switch(val) {
192 case 0: /* FALLTHROUGH */
193 case 3:
194 sc->sc_buswidth = 1; /* 8 bit */
195 break;
196 case 1:
197 sc->sc_buswidth = 2; /* 16 bit */
198 break;
199 case 2:
200 sc->sc_buswidth = 4; /* 32 bit */
201 break;
202 }
203 aprint_debug_dev(self, "bus width %d bits\n", 8 * sc->sc_buswidth);
204
205 nand_init_interface(&sc->sc_nand_if);
206
207 sc->sc_nand_if.command = rmixl_nand_command;
208 sc->sc_nand_if.address = rmixl_nand_address;
209 sc->sc_nand_if.read_buf_1 = rmixl_nand_read_buf;
210 sc->sc_nand_if.read_buf_2 = rmixl_nand_read_buf;
211 sc->sc_nand_if.read_1 = rmixl_nand_read_1;
212 sc->sc_nand_if.read_2 = rmixl_nand_read_2;
213 sc->sc_nand_if.write_buf_1 = rmixl_nand_write_buf;
214 sc->sc_nand_if.write_buf_2 = rmixl_nand_write_buf;
215 sc->sc_nand_if.write_1 = rmixl_nand_write_1;
216 sc->sc_nand_if.write_2 = rmixl_nand_write_2;
217 sc->sc_nand_if.busy = rmixl_nand_busy;
218
219 sc->sc_nand_if.ecc.necc_code_size = 3;
220 sc->sc_nand_if.ecc.necc_block_size = 256;
221
222 /*
223 * reset to get NAND into known state
224 */
225 rmixl_nand_command(self, ONFI_RESET);
226 rmixl_nand_busy(self);
227
228 if (! pmf_device_register1(self, NULL, NULL, NULL))
229 aprint_error_dev(self, "couldn't establish power handler\n");
230
231 sc->sc_nanddev = nand_attach_mi(&sc->sc_nand_if, self);
232 }
233
234 static int
rmixl_nand_detach(device_t self,int flags)235 rmixl_nand_detach(device_t self, int flags)
236 {
237 struct rmixl_nand_softc *sc = device_private(self);
238 int error;
239
240 error = config_detach_children(self, flags);
241 if (error)
242 return error;
243
244 pmf_device_deregister(self);
245
246 bus_space_unmap(sc->sc_iobus_bst, sc->sc_iobus_bsh, sc->sc_iobus_size);
247
248 return 0;
249 }
250
251 static void
rmixl_nand_command(device_t self,uint8_t command)252 rmixl_nand_command(device_t self, uint8_t command)
253 {
254 struct rmixl_nand_softc *sc = device_private(self);
255
256 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
257 sc->sc_cmd_reg, command);
258 }
259
260 static void
rmixl_nand_address(device_t self,uint8_t address)261 rmixl_nand_address(device_t self, uint8_t address)
262 {
263 struct rmixl_nand_softc *sc = device_private(self);
264
265 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
266 sc->sc_addr_reg, address);
267 }
268
269 static void
rmixl_nand_busy(device_t self)270 rmixl_nand_busy(device_t self)
271 {
272 struct rmixl_nand_softc *sc = device_private(self);
273 uint32_t istatus;
274
275 for(u_int count=100000; count--;) {
276 istatus = bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh,
277 RMIXL_FLASH_INT_STATUS);
278 if ((istatus & __BIT(8)) != 0)
279 return;
280 DELAY(1);
281 }
282 #ifdef DEBUG
283 printf("%s: timed out, istatus=%#x\n", __func__, istatus);
284 #ifdef DDB
285 Debugger();
286 #endif
287 #endif
288 }
289
290 static void
rmixl_nand_read_1(device_t self,uint8_t * data)291 rmixl_nand_read_1(device_t self, uint8_t *data)
292 {
293 struct rmixl_nand_softc *sc = device_private(self);
294
295 *data = bus_space_read_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
296 }
297
298 static void
rmixl_nand_write_1(device_t self,uint8_t data)299 rmixl_nand_write_1(device_t self, uint8_t data)
300 {
301 struct rmixl_nand_softc *sc = device_private(self);
302
303 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
304 }
305
306 static void
rmixl_nand_read_2(device_t self,uint16_t * data)307 rmixl_nand_read_2(device_t self, uint16_t *data)
308 {
309 struct rmixl_nand_softc *sc = device_private(self);
310
311 *data = bus_space_read_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
312 }
313
314 static void
rmixl_nand_write_2(device_t self,uint16_t data)315 rmixl_nand_write_2(device_t self, uint16_t data)
316 {
317 struct rmixl_nand_softc *sc = device_private(self);
318
319 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
320 }
321
322 static void
rmixl_nand_read_buf(device_t self,void * buf,size_t len)323 rmixl_nand_read_buf(device_t self, void *buf, size_t len)
324 {
325 struct rmixl_nand_softc *sc = device_private(self);
326 uintptr_t addr = (uintptr_t)buf;
327 size_t sz;
328
329 /* leading byte alignment */
330 if ((len >= 1) && ((addr & 1) != 0)) {
331 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
332 sc->sc_iobus_bsh, 0);
333 addr += 1;
334 len -= 1;
335 }
336
337 /* leading short alignment */
338 if ((len >= 2) && ((addr & 2) != 0)) {
339 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
340 sc->sc_iobus_bsh, 0);
341 addr += 2;
342 len -= 2;
343 }
344
345 /* word alignment */
346 sz = len >> 2;
347 if (sz != 0) {
348 bus_space_read_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
349 0, (uint32_t *)addr, sz);
350 sz <<= 2;
351 addr += sz;
352 len -= sz;
353 }
354
355 /* trailing short alignment */
356 if (len >= 2) {
357 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
358 sc->sc_iobus_bsh, 0);
359 addr += 2;
360 len -= 2;
361 }
362
363 /* trailing byte alignment */
364 if (len != 0)
365 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
366 sc->sc_iobus_bsh, 0);
367 }
368
369 static void
rmixl_nand_write_buf(device_t self,const void * buf,size_t len)370 rmixl_nand_write_buf(device_t self, const void *buf, size_t len)
371 {
372 struct rmixl_nand_softc *sc = device_private(self);
373 uintptr_t addr = (uintptr_t)buf;
374 size_t sz;
375
376 /* leading byte alignment */
377 if ((len >= 1) && ((addr & 1) != 0)) {
378 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
379 *((uint8_t *)addr));
380 addr += 1;
381 len -= 1;
382 }
383
384 /* leading short alignment */
385 if ((len >= 2) && ((addr & 2) != 0)) {
386 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
387 *((uint16_t *)addr));
388 addr += 2;
389 len -= 2;
390 }
391
392 /* word alignment */
393 sz = len >> 2;
394 if (sz != 0) {
395 bus_space_write_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
396 0, (uint32_t *)addr, sz);
397 sz <<= 2;
398 addr += sz;
399 len -= sz;
400 }
401
402 /* trailing short alignment */
403 if (len >= 2) {
404 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
405 *((uint16_t *)addr));
406 addr += 2;
407 len -= 2;
408 }
409
410 /* trailing byte alignment */
411 if (len != 0)
412 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
413 *((uint8_t *)addr));
414 }
415