rmixl_nand.c revision 1.3 1 /* $NetBSD: rmixl_nand.c,v 1.3 2011/03/18 19:58:21 cliff Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2010 Adam Hoka <ahoka (at) 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.3 2011/03/18 19:58:21 cliff 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 <machine/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_byte(device_t, uint8_t *);
67 static void rmixl_nand_write_byte(device_t, uint8_t);
68 static void rmixl_nand_read_word(device_t, uint16_t *);
69 static void rmixl_nand_write_word(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
101 rmixl_nand_match(device_tparent, cfdata_tmatch, 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
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 sc->sc_nand_if.select = nand_default_select;
206 sc->sc_nand_if.command = rmixl_nand_command;
207 sc->sc_nand_if.address = rmixl_nand_address;
208 sc->sc_nand_if.read_buf_byte = rmixl_nand_read_buf;
209 sc->sc_nand_if.read_buf_word = rmixl_nand_read_buf;
210 sc->sc_nand_if.read_byte = rmixl_nand_read_byte;
211 sc->sc_nand_if.read_word = rmixl_nand_read_word;
212 sc->sc_nand_if.write_buf_byte = rmixl_nand_write_buf;
213 sc->sc_nand_if.write_buf_word = rmixl_nand_write_buf;
214 sc->sc_nand_if.write_byte = rmixl_nand_write_byte;
215 sc->sc_nand_if.write_word = rmixl_nand_write_word;
216 sc->sc_nand_if.busy = rmixl_nand_busy;
217
218 sc->sc_nand_if.ecc_compute = nand_default_ecc_compute;
219 sc->sc_nand_if.ecc_correct = nand_default_ecc_correct;
220 sc->sc_nand_if.ecc_prepare = NULL;
221 sc->sc_nand_if.ecc.necc_code_size = 3;
222 sc->sc_nand_if.ecc.necc_block_size = 256;
223 sc->sc_nand_if.ecc.necc_type = NAND_ECC_TYPE_SW;
224
225 /*
226 * reset to get NAND into known state
227 */
228 rmixl_nand_command(self, ONFI_RESET);
229 rmixl_nand_busy(self);
230
231 if (! pmf_device_register1(self, NULL, NULL, NULL))
232 aprint_error_dev(self, "couldn't establish power handler\n");
233
234 sc->sc_nanddev = nand_attach_mi(&sc->sc_nand_if, self);
235 }
236
237 static int
238 rmixl_nand_detach(device_t self, int flags)
239 {
240 struct rmixl_nand_softc *sc = device_private(self);
241 int rv = 0;
242
243 pmf_device_deregister(self);
244
245 if (sc->sc_nanddev != NULL)
246 rv = config_detach(sc->sc_nanddev, flags);
247
248 bus_space_unmap(sc->sc_iobus_bst, sc->sc_iobus_bsh, sc->sc_iobus_size);
249
250 return rv;
251 }
252
253 static void
254 rmixl_nand_command(device_t self, uint8_t command)
255 {
256 struct rmixl_nand_softc *sc = device_private(self);
257
258 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
259 sc->sc_cmd_reg, command);
260 }
261
262 static void
263 rmixl_nand_address(device_t self, uint8_t address)
264 {
265 struct rmixl_nand_softc *sc = device_private(self);
266
267 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
268 sc->sc_addr_reg, address);
269 }
270
271 static void
272 rmixl_nand_busy(device_t self)
273 {
274 struct rmixl_nand_softc *sc = device_private(self);
275 uint32_t istatus;
276
277 for(u_int count=100000; count--;) {
278 istatus = bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh,
279 RMIXL_FLASH_INT_STATUS);
280 if ((istatus & __BIT(8)) != 0)
281 return;
282 DELAY(1);
283 }
284 #ifdef DEBUG
285 printf("%s: timed out, istatus=%#x\n", __func__, istatus);
286 #ifdef DDB
287 Debugger();
288 #endif
289 #endif
290 }
291
292 static void
293 rmixl_nand_read_byte(device_t self, uint8_t *data)
294 {
295 struct rmixl_nand_softc *sc = device_private(self);
296
297 *data = bus_space_read_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
298 }
299
300 static void
301 rmixl_nand_write_byte(device_t self, uint8_t data)
302 {
303 struct rmixl_nand_softc *sc = device_private(self);
304
305 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
306 }
307
308 static void
309 rmixl_nand_read_word(device_t self, uint16_t *data)
310 {
311 struct rmixl_nand_softc *sc = device_private(self);
312
313 *data = bus_space_read_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
314 }
315
316 static void
317 rmixl_nand_write_word(device_t self, uint16_t data)
318 {
319 struct rmixl_nand_softc *sc = device_private(self);
320
321 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
322 }
323
324 static void
325 rmixl_nand_read_buf(device_t self, void *buf, size_t len)
326 {
327 struct rmixl_nand_softc *sc = device_private(self);
328 uintptr_t addr = (uintptr_t)buf;
329 size_t sz;
330
331 /* leading byte alignment */
332 if ((len >= 1) && ((addr & 1) != 0)) {
333 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
334 sc->sc_iobus_bsh, 0);
335 addr += 1;
336 len -= 1;
337 }
338
339 /* leading short alignment */
340 if ((len >= 2) && ((addr & 2) != 0)) {
341 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
342 sc->sc_iobus_bsh, 0);
343 addr += 2;
344 len -= 2;
345 }
346
347 /* word alignment */
348 sz = len >> 2;
349 if (sz != 0) {
350 bus_space_read_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
351 0, (uint32_t *)addr, sz);
352 sz <<= 2;
353 addr += sz;
354 len -= sz;
355 }
356
357 /* trailing short alignment */
358 if (len >= 2) {
359 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
360 sc->sc_iobus_bsh, 0);
361 addr += 2;
362 len -= 2;
363 }
364
365 /* trailing byte alignment */
366 if (len != 0)
367 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
368 sc->sc_iobus_bsh, 0);
369 }
370
371 static void
372 rmixl_nand_write_buf(device_t self, const void *buf, size_t len)
373 {
374 struct rmixl_nand_softc *sc = device_private(self);
375 uintptr_t addr = (uintptr_t)buf;
376 size_t sz;
377
378 /* leading byte alignment */
379 if ((len >= 1) && ((addr & 1) != 0)) {
380 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
381 *((uint8_t *)addr));
382 addr += 1;
383 len -= 1;
384 }
385
386 /* leading short alignment */
387 if ((len >= 2) && ((addr & 2) != 0)) {
388 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
389 *((uint16_t *)addr));
390 addr += 2;
391 len -= 2;
392 }
393
394 /* word alignment */
395 sz = len >> 2;
396 if (sz != 0) {
397 bus_space_write_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
398 0, (uint32_t *)addr, sz);
399 sz <<= 2;
400 addr += sz;
401 len -= sz;
402 }
403
404 /* trailing short alignment */
405 if (len >= 2) {
406 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
407 *((uint16_t *)addr));
408 addr += 2;
409 len -= 2;
410 }
411
412 /* trailing byte alignment */
413 if (len != 0)
414 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
415 *((uint8_t *)addr));
416 }
417