rmixl_nand.c revision 1.5.2.2 1 /* $NetBSD: rmixl_nand.c,v 1.5.2.2 2011/04/21 01:41:13 rmind 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.5.2.2 2011/04/21 01:41:13 rmind 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_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
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_byte = rmixl_nand_read_buf;
210 sc->sc_nand_if.read_buf_word = rmixl_nand_read_buf;
211 sc->sc_nand_if.read_byte = rmixl_nand_read_byte;
212 sc->sc_nand_if.read_word = rmixl_nand_read_word;
213 sc->sc_nand_if.write_buf_byte = rmixl_nand_write_buf;
214 sc->sc_nand_if.write_buf_word = rmixl_nand_write_buf;
215 sc->sc_nand_if.write_byte = rmixl_nand_write_byte;
216 sc->sc_nand_if.write_word = rmixl_nand_write_word;
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
235 rmixl_nand_detach(device_t self, int flags)
236 {
237 struct rmixl_nand_softc *sc = device_private(self);
238 int rv = 0;
239
240 pmf_device_deregister(self);
241
242 if (sc->sc_nanddev != NULL)
243 rv = config_detach(sc->sc_nanddev, flags);
244
245 bus_space_unmap(sc->sc_iobus_bst, sc->sc_iobus_bsh, sc->sc_iobus_size);
246
247 return rv;
248 }
249
250 static void
251 rmixl_nand_command(device_t self, uint8_t command)
252 {
253 struct rmixl_nand_softc *sc = device_private(self);
254
255 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
256 sc->sc_cmd_reg, command);
257 }
258
259 static void
260 rmixl_nand_address(device_t self, uint8_t address)
261 {
262 struct rmixl_nand_softc *sc = device_private(self);
263
264 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh,
265 sc->sc_addr_reg, address);
266 }
267
268 static void
269 rmixl_nand_busy(device_t self)
270 {
271 struct rmixl_nand_softc *sc = device_private(self);
272 uint32_t istatus;
273
274 for(u_int count=100000; count--;) {
275 istatus = bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh,
276 RMIXL_FLASH_INT_STATUS);
277 if ((istatus & __BIT(8)) != 0)
278 return;
279 DELAY(1);
280 }
281 #ifdef DEBUG
282 printf("%s: timed out, istatus=%#x\n", __func__, istatus);
283 #ifdef DDB
284 Debugger();
285 #endif
286 #endif
287 }
288
289 static void
290 rmixl_nand_read_byte(device_t self, uint8_t *data)
291 {
292 struct rmixl_nand_softc *sc = device_private(self);
293
294 *data = bus_space_read_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
295 }
296
297 static void
298 rmixl_nand_write_byte(device_t self, uint8_t data)
299 {
300 struct rmixl_nand_softc *sc = device_private(self);
301
302 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
303 }
304
305 static void
306 rmixl_nand_read_word(device_t self, uint16_t *data)
307 {
308 struct rmixl_nand_softc *sc = device_private(self);
309
310 *data = bus_space_read_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0);
311 }
312
313 static void
314 rmixl_nand_write_word(device_t self, uint16_t data)
315 {
316 struct rmixl_nand_softc *sc = device_private(self);
317
318 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data);
319 }
320
321 static void
322 rmixl_nand_read_buf(device_t self, void *buf, size_t len)
323 {
324 struct rmixl_nand_softc *sc = device_private(self);
325 uintptr_t addr = (uintptr_t)buf;
326 size_t sz;
327
328 /* leading byte alignment */
329 if ((len >= 1) && ((addr & 1) != 0)) {
330 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
331 sc->sc_iobus_bsh, 0);
332 addr += 1;
333 len -= 1;
334 }
335
336 /* leading short alignment */
337 if ((len >= 2) && ((addr & 2) != 0)) {
338 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
339 sc->sc_iobus_bsh, 0);
340 addr += 2;
341 len -= 2;
342 }
343
344 /* word alignment */
345 sz = len >> 2;
346 if (sz != 0) {
347 bus_space_read_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
348 0, (uint32_t *)addr, sz);
349 sz <<= 2;
350 addr += sz;
351 len -= sz;
352 }
353
354 /* trailing short alignment */
355 if (len >= 2) {
356 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst,
357 sc->sc_iobus_bsh, 0);
358 addr += 2;
359 len -= 2;
360 }
361
362 /* trailing byte alignment */
363 if (len != 0)
364 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst,
365 sc->sc_iobus_bsh, 0);
366 }
367
368 static void
369 rmixl_nand_write_buf(device_t self, const void *buf, size_t len)
370 {
371 struct rmixl_nand_softc *sc = device_private(self);
372 uintptr_t addr = (uintptr_t)buf;
373 size_t sz;
374
375 /* leading byte alignment */
376 if ((len >= 1) && ((addr & 1) != 0)) {
377 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
378 *((uint8_t *)addr));
379 addr += 1;
380 len -= 1;
381 }
382
383 /* leading short alignment */
384 if ((len >= 2) && ((addr & 2) != 0)) {
385 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
386 *((uint16_t *)addr));
387 addr += 2;
388 len -= 2;
389 }
390
391 /* word alignment */
392 sz = len >> 2;
393 if (sz != 0) {
394 bus_space_write_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh,
395 0, (uint32_t *)addr, sz);
396 sz <<= 2;
397 addr += sz;
398 len -= sz;
399 }
400
401 /* trailing short alignment */
402 if (len >= 2) {
403 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
404 *((uint16_t *)addr));
405 addr += 2;
406 len -= 2;
407 }
408
409 /* trailing byte alignment */
410 if (len != 0)
411 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0,
412 *((uint8_t *)addr));
413 }
414