nor.c revision 1.4.14.1 1 /* $NetBSD: nor.c,v 1.4.14.1 2014/08/20 00:03:41 tls Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2011 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 /* Common driver for NOR chips implementing the ONFI CFI specification */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: nor.c,v 1.4.14.1 2014/08/20 00:03:41 tls Exp $");
38
39 #include "locators.h"
40 #include "opt_nor.h"
41
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/device.h>
45 #include <sys/kmem.h>
46 #include <sys/sysctl.h>
47 #include <sys/atomic.h>
48
49 #include <dev/flash/flash.h>
50 #include <dev/flash/flash_io.h>
51 #include <dev/nor/nor.h>
52
53
54 static int nor_match(device_t, cfdata_t, void *);
55 static void nor_attach(device_t, device_t, void *);
56 static int nor_detach(device_t, int);
57 static bool nor_shutdown(device_t, int);
58 static int nor_print(void *, const char *);
59 static int nor_search(device_t, cfdata_t, const int *, void *);
60
61 /* flash interface implementation */
62 static int nor_flash_isbad(device_t, flash_off_t, bool *);
63 static int nor_flash_markbad(device_t, flash_off_t);
64 static int nor_flash_write(device_t, flash_off_t, size_t, size_t *,
65 const u_char *);
66 static int nor_flash_read(device_t, flash_off_t, size_t, size_t *, uint8_t *);
67 static int nor_flash_erase_all(device_t);
68 static int nor_flash_erase(device_t, struct flash_erase_instruction *);
69 static int nor_flash_submit(device_t, buf_t *);
70
71 /* default functions for driver development */
72 static void nor_default_select(device_t, bool);
73 static int nor_default_read_page(device_t, flash_off_t, uint8_t *);
74 static int nor_default_program_page(device_t, flash_off_t, const uint8_t *);
75
76 static int nor_scan_media(device_t, struct nor_chip *);
77
78 CFATTACH_DECL_NEW(nor, sizeof(struct nor_softc),
79 nor_match, nor_attach, nor_detach, NULL);
80
81 #ifdef NOR_DEBUG
82 int nordebug = NOR_DEBUG;
83 #endif
84
85 int nor_cachesync_timeout = 1;
86 int nor_cachesync_nodenum;
87
88 struct flash_interface nor_flash_if = {
89 .type = FLASH_TYPE_NOR,
90
91 .read = nor_flash_read,
92 .write = nor_flash_write,
93 .erase = nor_flash_erase,
94 .block_isbad = nor_flash_isbad,
95 .block_markbad = nor_flash_markbad,
96
97 .submit = nor_flash_submit
98 };
99
100 #ifdef NOR_VERBOSE
101 const struct nor_manufacturer nor_mfrs[] = {
102 { NOR_MFR_AMD, "AMD" },
103 { NOR_MFR_FUJITSU, "Fujitsu" },
104 { NOR_MFR_RENESAS, "Renesas" },
105 { NOR_MFR_STMICRO, "ST Micro" },
106 { NOR_MFR_MICRON, "Micron" },
107 { NOR_MFR_NATIONAL, "National" },
108 { NOR_MFR_TOSHIBA, "Toshiba" },
109 { NOR_MFR_HYNIX, "Hynix" },
110 { NOR_MFGR_MACRONIX, "Macronix" },
111 { NOR_MFR_SAMSUNG, "Samsung" },
112 { NOR_MFR_UNKNOWN, "Unknown" }
113 };
114
115 static const char *
116 nor_midtoname(int id)
117 {
118 int i;
119
120 for (i = 0; nor_mfrs[i].id != 0; i++) {
121 if (nor_mfrs[i].id == id)
122 return nor_mfrs[i].name;
123 }
124
125 KASSERT(nor_mfrs[i].id == 0);
126
127 return nor_mfrs[i].name;
128 }
129 #endif
130
131 /* ARGSUSED */
132 static int
133 nor_match(device_t parent, cfdata_t match, void *aux)
134 {
135 /* pseudo device, always attaches */
136 return 1;
137 }
138
139 static void
140 nor_attach(device_t parent, device_t self, void *aux)
141 {
142 struct nor_softc * const sc = device_private(self);
143 struct nor_attach_args * const naa = aux;
144 struct nor_chip * const chip = &sc->sc_chip;
145
146 sc->sc_dev = self;
147 sc->sc_controller_dev = parent;
148 sc->sc_nor_if = naa->naa_nor_if;
149
150 aprint_naive("\n");
151 aprint_normal("\n");
152
153 if (nor_scan_media(self, chip))
154 return;
155
156 sc->sc_flash_if = nor_flash_if;
157 sc->sc_flash_if.erasesize = chip->nc_block_size;
158 sc->sc_flash_if.page_size = chip->nc_page_size;
159 sc->sc_flash_if.writesize = chip->nc_page_size;
160
161 /* allocate cache */
162 #ifdef NOTYET
163 chip->nc_oob_cache = kmem_alloc(chip->nc_spare_size, KM_SLEEP);
164 #endif
165 chip->nc_page_cache = kmem_alloc(chip->nc_page_size, KM_SLEEP);
166
167 mutex_init(&sc->sc_device_lock, MUTEX_DEFAULT, IPL_NONE);
168
169 if (flash_sync_thread_init(&sc->sc_flash_io, self, &sc->sc_flash_if)) {
170 goto error;
171 }
172
173 if (!pmf_device_register1(sc->sc_dev, NULL, NULL, nor_shutdown))
174 aprint_error_dev(sc->sc_dev,
175 "couldn't establish power handler\n");
176
177 #ifdef NOR_BBT
178 nor_bbt_init(self);
179 nor_bbt_scan(self);
180 #endif
181
182 /*
183 * Attach all our devices
184 */
185 config_search_ia(nor_search, self, NULL, NULL);
186
187 return;
188
189 error:
190 #ifdef NOTET
191 kmem_free(chip->nc_oob_cache, chip->nc_spare_size);
192 #endif
193 kmem_free(chip->nc_page_cache, chip->nc_page_size);
194 mutex_destroy(&sc->sc_device_lock);
195 }
196
197 static int
198 nor_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
199 {
200 struct nor_softc * const sc = device_private(parent);
201 struct nor_chip * const chip = &sc->sc_chip;
202 struct flash_attach_args faa;
203
204 faa.partinfo.part_offset = cf->cf_loc[FLASHBUSCF_OFFSET];
205
206 if (cf->cf_loc[FLASHBUSCF_SIZE] == 0) {
207 faa.partinfo.part_size =
208 chip->nc_size - faa.partinfo.part_offset;
209 } else {
210 faa.partinfo.part_size = cf->cf_loc[FLASHBUSCF_SIZE];
211 }
212
213 if (cf->cf_loc[FLASHBUSCF_READONLY])
214 faa.partinfo.part_flags = FLASH_PART_READONLY;
215 else
216 faa.partinfo.part_flags = 0;
217
218 faa.flash_if = &sc->sc_flash_if;
219
220 if (config_match(parent, cf, &faa)) {
221 if (config_attach(parent, cf, &faa, nor_print) != NULL) {
222 return 0;
223 } else {
224 return 1;
225 }
226 }
227
228 return 1;
229 }
230
231 static int
232 nor_detach(device_t self, int flags)
233 {
234 struct nor_softc * const sc = device_private(self);
235 struct nor_chip * const chip = &sc->sc_chip;
236 int error = 0;
237
238 error = config_detach_children(self, flags);
239 if (error) {
240 return error;
241 }
242
243 flash_sync_thread_destroy(&sc->sc_flash_io);
244 #ifdef NOR_BBT
245 nor_bbt_detach(self);
246 #endif
247 #ifdef NOTET
248 /* free oob cache */
249 kmem_free(chip->nc_oob_cache, chip->nc_spare_size);
250 #endif
251 kmem_free(chip->nc_page_cache, chip->nc_page_size);
252
253 mutex_destroy(&sc->sc_device_lock);
254
255 pmf_device_deregister(sc->sc_dev);
256
257 return error;
258 }
259
260 static int
261 nor_print(void *aux, const char *pnp)
262 {
263 if (pnp != NULL)
264 aprint_normal("nor at %s\n", pnp);
265
266 return UNCONF;
267 }
268
269 /* ask for a nor driver to attach to the controller */
270 device_t
271 nor_attach_mi(struct nor_interface * const nor_if, device_t parent)
272 {
273 struct nor_attach_args arg;
274
275 KASSERT(nor_if != NULL);
276
277 if (nor_if->select == NULL)
278 nor_if->select = &nor_default_select;
279 if (nor_if->read_page == NULL)
280 nor_if->read_page = &nor_default_read_page;
281 if (nor_if->program_page == NULL)
282 nor_if->program_page = &nor_default_program_page;
283
284 arg.naa_nor_if = nor_if;
285
286 device_t dev = config_found_ia(parent, "norbus", &arg, nor_print);
287
288 return dev;
289 }
290
291 static void
292 nor_default_select(device_t self, bool n)
293 {
294 /* do nothing */
295 return;
296 }
297
298 static int
299 nor_flash_submit(device_t self, buf_t * const bp)
300 {
301 struct nor_softc * const sc = device_private(self);
302
303 return flash_io_submit(&sc->sc_flash_io, bp);
304 }
305
306
307 /* default everything to reasonable values, to ease future api changes */
308 void
309 nor_init_interface(struct nor_interface * const nor_if)
310 {
311 nor_if->select = &nor_default_select;
312 nor_if->read_1 = NULL;
313 nor_if->read_2 = NULL;
314 nor_if->read_4 = NULL;
315 nor_if->read_buf_1 = NULL;
316 nor_if->read_buf_2 = NULL;
317 nor_if->read_buf_4 = NULL;
318 nor_if->write_1 = NULL;
319 nor_if->write_2 = NULL;
320 nor_if->write_4 = NULL;
321 nor_if->write_buf_1 = NULL;
322 nor_if->write_buf_2 = NULL;
323 nor_if->write_buf_4 = NULL;
324 nor_if->busy = NULL;
325 }
326
327 #ifdef NOTYET
328 /* handle quirks here */
329 static void
330 nor_quirks(device_t self, struct nor_chip * const chip)
331 {
332 /* this is an example only! */
333 switch (chip->nc_manf_id) {
334 case NOR_MFR_SAMSUNG:
335 if (chip->nc_dev_id == 0x00) {
336 /* do something only samsung chips need */
337 /* or */
338 /* chip->nc_quirks |= NC_QUIRK_NO_READ_START */
339 }
340 }
341
342 return;
343 }
344 #endif
345
346 /**
347 * scan media to determine the chip's properties
348 * this function resets the device
349 */
350 static int
351 nor_scan_media(device_t self, struct nor_chip * const chip)
352 {
353 struct nor_softc * const sc = device_private(self);
354 char pbuf[3][sizeof("XXXX MB")];
355
356 KASSERT(sc->sc_nor_if != NULL);
357 KASSERT(sc->sc_nor_if->scan_media != NULL);
358 int error = sc->sc_nor_if->scan_media(self, chip);
359 if (error != 0)
360 return error;
361
362 #ifdef NOR_VERBOSE
363 aprint_normal_dev(self,
364 "manufacturer id: 0x%.4x (%s), device id: 0x%.4x\n",
365 chip->nc_manf_id,
366 nor_midtoname(chip->nc_manf_id),
367 chip->nc_dev_id);
368 #endif
369
370 format_bytes(pbuf[0], sizeof(pbuf[0]), chip->nc_page_size);
371 format_bytes(pbuf[1], sizeof(pbuf[1]), chip->nc_spare_size);
372 format_bytes(pbuf[2], sizeof(pbuf[2]), chip->nc_block_size);
373 aprint_normal_dev(self,
374 "page size: %s, spare size: %s, block size: %s\n",
375 pbuf[0], pbuf[1], pbuf[2]);
376
377 format_bytes(pbuf[0], sizeof(pbuf[0]), chip->nc_size);
378 aprint_normal_dev(self,
379 "LUN size: %" PRIu32 " blocks, LUNs: %" PRIu8
380 ", total storage size: %s\n",
381 chip->nc_lun_blocks, chip->nc_num_luns, pbuf[0]);
382
383 #ifdef NOTYET
384 /* XXX does this apply to nor? */
385 /*
386 * calculate badblock marker offset in oob
387 * we try to be compatible with linux here
388 */
389 if (chip->nc_page_size > 512)
390 chip->nc_badmarker_offs = 0;
391 else
392 chip->nc_badmarker_offs = 5;
393 #endif
394
395 /* Calculate page shift and mask */
396 chip->nc_page_shift = ffs(chip->nc_page_size) - 1;
397 chip->nc_page_mask = ~(chip->nc_page_size - 1);
398 /* same for block */
399 chip->nc_block_shift = ffs(chip->nc_block_size) - 1;
400 chip->nc_block_mask = ~(chip->nc_block_size - 1);
401
402 #ifdef NOTYET
403 /* look for quirks here if needed in future */
404 nor_quirks(self, chip);
405 #endif
406
407 return 0;
408 }
409
410 /* ARGSUSED */
411 static bool
412 nor_shutdown(device_t self, int howto)
413 {
414 return true;
415 }
416
417 /* implementation of the block device API */
418
419 /* read a page, default implementation */
420 static int
421 nor_default_read_page(device_t self, flash_off_t offset, uint8_t * const data)
422 {
423 struct nor_softc * const sc = device_private(self);
424 struct nor_chip * const chip = &sc->sc_chip;
425
426 /*
427 * access by specified access_width
428 * note: #bits == 1 << width
429 */
430 switch(sc->sc_nor_if->access_width) {
431 case 0:
432 nor_read_buf_1(self, offset, data, chip->nc_page_size);
433 break;
434 case 1:
435 nor_read_buf_2(self, offset, data, chip->nc_page_size);
436 break;
437 case 2:
438 nor_read_buf_4(self, offset, data, chip->nc_page_size);
439 break;
440 #ifdef NOTYET
441 case 3:
442 nor_read_buf_8(self, offset, data, chip->nc_page_size);
443 break;
444 #endif
445 default:
446 panic("%s: bad width %d\n", __func__, sc->sc_nor_if->access_width);
447 }
448
449 #if 0
450 /* for debugging new drivers */
451 nor_dump_data("page", data, chip->nc_page_size);
452 #endif
453
454 return 0;
455 }
456
457 /* write a page, default implementation */
458 static int
459 nor_default_program_page(device_t self, flash_off_t offset,
460 const uint8_t * const data)
461 {
462 struct nor_softc * const sc = device_private(self);
463 struct nor_chip * const chip = &sc->sc_chip;
464
465 /*
466 * access by specified width
467 * #bits == 1 << access_width
468 */
469 switch(sc->sc_nor_if->access_width) {
470 case 0:
471 nor_write_buf_1(self, offset, data, chip->nc_page_size);
472 break;
473 case 1:
474 nor_write_buf_2(self, offset, data, chip->nc_page_size);
475 break;
476 case 2:
477 nor_write_buf_4(self, offset, data, chip->nc_page_size);
478 break;
479 #ifdef NOTYET
480 case 3:
481 nor_write_buf_8(self, offset, data, chip->nc_page_size);
482 break;
483 #endif
484 default:
485 panic("%s: bad width %d\n", __func__,
486 sc->sc_nor_if->access_width);
487 }
488
489 #if 0
490 /* for debugging new drivers */
491 nor_dump_data("page", data, chip->nc_page_size);
492 #endif
493
494 return 0;
495 }
496
497 /*
498 * nor_flash_erase_all - erase the entire chip
499 *
500 * XXX a good way to brick your system
501 */
502 static int
503 nor_flash_erase_all(device_t self)
504 {
505 struct nor_softc * const sc = device_private(self);
506 int error;
507
508 mutex_enter(&sc->sc_device_lock);
509 error = nor_erase_all(self);
510 mutex_exit(&sc->sc_device_lock);
511
512 return error;
513 }
514
515 static int
516 nor_flash_erase(device_t self, struct flash_erase_instruction * const ei)
517 {
518 struct nor_softc * const sc = device_private(self);
519 struct nor_chip * const chip = &sc->sc_chip;
520 flash_off_t addr;
521 int error = 0;
522
523 if (ei->ei_addr < 0 || ei->ei_len < chip->nc_block_size)
524 return EINVAL;
525
526 if (ei->ei_addr + ei->ei_len > chip->nc_size) {
527 DPRINTF(("%s: erase address is past the end"
528 " of the device\n", __func__));
529 return EINVAL;
530 }
531
532 if ((ei->ei_addr == 0) && (ei->ei_len == chip->nc_size)
533 && (sc->sc_nor_if->erase_all != NULL)) {
534 return nor_flash_erase_all(self);
535 }
536
537 if (ei->ei_addr % chip->nc_block_size != 0) {
538 aprint_error_dev(self,
539 "nor_flash_erase: ei_addr (%ju) is not"
540 " a multiple of block size (%ju)\n",
541 (uintmax_t)ei->ei_addr,
542 (uintmax_t)chip->nc_block_size);
543 return EINVAL;
544 }
545
546 if (ei->ei_len % chip->nc_block_size != 0) {
547 aprint_error_dev(self,
548 "nor_flash_erase: ei_len (%ju) is not"
549 " a multiple of block size (%ju)",
550 (uintmax_t)ei->ei_len,
551 (uintmax_t)chip->nc_block_size);
552 return EINVAL;
553 }
554
555 mutex_enter(&sc->sc_device_lock);
556 addr = ei->ei_addr;
557 while (addr < ei->ei_addr + ei->ei_len) {
558 #ifdef NOTYET
559 if (nor_isbad(self, addr)) {
560 aprint_error_dev(self, "bad block encountered\n");
561 ei->ei_state = FLASH_ERASE_FAILED;
562 error = EIO;
563 goto out;
564 }
565 #endif
566
567 error = nor_erase_block(self, addr);
568 if (error) {
569 ei->ei_state = FLASH_ERASE_FAILED;
570 goto out;
571 }
572
573 addr += chip->nc_block_size;
574 }
575 mutex_exit(&sc->sc_device_lock);
576
577 ei->ei_state = FLASH_ERASE_DONE;
578 if (ei->ei_callback != NULL) {
579 ei->ei_callback(ei);
580 }
581
582 return 0;
583 out:
584 mutex_exit(&sc->sc_device_lock);
585
586 return error;
587 }
588
589 /*
590 * handle (page) unaligned write to nor
591 */
592 static int
593 nor_flash_write_unaligned(device_t self, flash_off_t offset, size_t len,
594 size_t * const retlen, const uint8_t * const buf)
595 {
596 struct nor_softc * const sc = device_private(self);
597 struct nor_chip * const chip = &sc->sc_chip;
598 flash_off_t first, last, firstoff;
599 const uint8_t *bufp;
600 flash_off_t addr;
601 size_t left, count;
602 int error = 0, i;
603
604 first = offset & chip->nc_page_mask;
605 firstoff = offset & ~chip->nc_page_mask;
606 /* XXX check if this should be len - 1 */
607 last = (offset + len) & chip->nc_page_mask;
608 count = last - first + 1;
609
610 addr = first;
611 *retlen = 0;
612
613 mutex_enter(&sc->sc_device_lock);
614 if (count == 1) {
615 #ifdef NOTYET
616 if (nor_isbad(self, addr)) {
617 aprint_error_dev(self,
618 "nor_flash_write_unaligned: "
619 "bad block encountered\n");
620 error = EIO;
621 goto out;
622 }
623 #endif
624
625 error = nor_read_page(self, addr, chip->nc_page_cache);
626 if (error) {
627 goto out;
628 }
629
630 memcpy(chip->nc_page_cache + firstoff, buf, len);
631
632 error = nor_program_page(self, addr, chip->nc_page_cache);
633 if (error) {
634 goto out;
635 }
636
637 *retlen = len;
638 goto out;
639 }
640
641 bufp = buf;
642 left = len;
643
644 for (i = 0; i < count && left != 0; i++) {
645 #ifdef NOTYET
646 if (nor_isbad(self, addr)) {
647 aprint_error_dev(self,
648 "nor_flash_write_unaligned: "
649 "bad block encountered\n");
650 error = EIO;
651 goto out;
652 }
653 #endif
654
655 if (i == 0) {
656 error = nor_read_page(self, addr, chip->nc_page_cache);
657 if (error) {
658 goto out;
659 }
660
661 memcpy(chip->nc_page_cache + firstoff,
662 bufp, chip->nc_page_size - firstoff);
663
664 printf("write page: %s: %d\n", __FILE__, __LINE__);
665 error = nor_program_page(self, addr,
666 chip->nc_page_cache);
667 if (error) {
668 goto out;
669 }
670
671 bufp += chip->nc_page_size - firstoff;
672 left -= chip->nc_page_size - firstoff;
673 *retlen += chip->nc_page_size - firstoff;
674
675 } else if (i == count - 1) {
676 error = nor_read_page(self, addr, chip->nc_page_cache);
677 if (error) {
678 goto out;
679 }
680
681 memcpy(chip->nc_page_cache, bufp, left);
682
683 error = nor_program_page(self, addr,
684 chip->nc_page_cache);
685 if (error) {
686 goto out;
687 }
688
689 *retlen += left;
690 KASSERT(left < chip->nc_page_size);
691
692 } else {
693 /* XXX debug */
694 if (left > chip->nc_page_size) {
695 printf("left: %zu, i: %d, count: %zu\n",
696 (size_t )left, i, count);
697 }
698 KASSERT(left > chip->nc_page_size);
699
700 error = nor_program_page(self, addr, bufp);
701 if (error) {
702 goto out;
703 }
704
705 bufp += chip->nc_page_size;
706 left -= chip->nc_page_size;
707 *retlen += chip->nc_page_size;
708 }
709
710 addr += chip->nc_page_size;
711 }
712
713 KASSERT(*retlen == len);
714 out:
715 mutex_exit(&sc->sc_device_lock);
716
717 return error;
718 }
719
720 static int
721 nor_flash_write(device_t self, flash_off_t offset, size_t len,
722 size_t * const retlen, const uint8_t * const buf)
723 {
724 struct nor_softc * const sc = device_private(self);
725 struct nor_chip * const chip = &sc->sc_chip;
726 const uint8_t *bufp;
727 size_t pages, page;
728 daddr_t addr;
729 int error = 0;
730
731 if ((offset + len) > chip->nc_size) {
732 DPRINTF(("%s: write (off: 0x%jx, len: %ju),"
733 " exceeds device size (0x%jx)\n", __func__,
734 (uintmax_t)offset, (uintmax_t)len,
735 (uintmax_t)chip->nc_size));
736 return EINVAL;
737 }
738
739 if (len % chip->nc_page_size != 0 ||
740 offset % chip->nc_page_size != 0) {
741 return nor_flash_write_unaligned(self,
742 offset, len, retlen, buf);
743 }
744
745 pages = len / chip->nc_page_size;
746 KASSERT(pages != 0);
747 *retlen = 0;
748
749 addr = offset;
750 bufp = buf;
751
752 mutex_enter(&sc->sc_device_lock);
753 for (page = 0; page < pages; page++) {
754 #ifdef NOTYET
755 /* do we need this check here? */
756 if (nor_isbad(self, addr)) {
757 aprint_error_dev(self,
758 "nor_flash_write: bad block encountered\n");
759
760 error = EIO;
761 goto out;
762 }
763 #endif
764
765 error = nor_program_page(self, addr, bufp);
766 if (error) {
767 goto out;
768 }
769
770 addr += chip->nc_page_size;
771 bufp += chip->nc_page_size;
772 *retlen += chip->nc_page_size;
773 }
774 out:
775 mutex_exit(&sc->sc_device_lock);
776 DPRINTF(("%s: retlen: %zu, len: %zu\n", __func__, *retlen, len));
777
778 return error;
779 }
780
781 /*
782 * handle (page) unaligned read from nor
783 */
784 static int
785 nor_flash_read_unaligned(device_t self, flash_off_t offset, size_t len,
786 size_t * const retlen, uint8_t * const buf)
787 {
788 struct nor_softc * const sc = device_private(self);
789 struct nor_chip * const chip = &sc->sc_chip;
790 daddr_t first, last, count, firstoff;
791 uint8_t *bufp;
792 daddr_t addr;
793 size_t left;
794 int error = 0, i;
795
796 first = offset & chip->nc_page_mask;
797 firstoff = offset & ~chip->nc_page_mask;
798 last = (offset + len) & chip->nc_page_mask;
799 count = (last - first) / chip->nc_page_size + 1;
800
801 addr = first;
802 bufp = buf;
803 left = len;
804 *retlen = 0;
805
806 mutex_enter(&sc->sc_device_lock);
807 if (count == 1) {
808 error = nor_read_page(self, addr, chip->nc_page_cache);
809 if (error) {
810 goto out;
811 }
812
813 memcpy(bufp, chip->nc_page_cache + firstoff, len);
814
815 *retlen = len;
816 goto out;
817 }
818
819 for (i = 0; i < count && left != 0; i++) {
820 /* XXX Why use the page cache here ? */
821 error = nor_read_page(self, addr, chip->nc_page_cache);
822 if (error) {
823 goto out;
824 }
825
826 if (i == 0) {
827 memcpy(bufp, chip->nc_page_cache + firstoff,
828 chip->nc_page_size - firstoff);
829
830 bufp += chip->nc_page_size - firstoff;
831 left -= chip->nc_page_size - firstoff;
832 *retlen += chip->nc_page_size - firstoff;
833
834 } else if (i == count - 1) {
835 memcpy(bufp, chip->nc_page_cache, left);
836 *retlen += left;
837 KASSERT(left < chip->nc_page_size);
838
839 } else {
840 memcpy(bufp, chip->nc_page_cache, chip->nc_page_size);
841
842 bufp += chip->nc_page_size;
843 left -= chip->nc_page_size;
844 *retlen += chip->nc_page_size;
845 }
846
847 addr += chip->nc_page_size;
848 }
849 KASSERT(*retlen == len);
850 out:
851 mutex_exit(&sc->sc_device_lock);
852
853 return error;
854 }
855
856 static int
857 nor_flash_read(device_t self, flash_off_t offset, size_t len,
858 size_t * const retlen, uint8_t * const buf)
859 {
860 struct nor_softc * const sc = device_private(self);
861 struct nor_chip * const chip = &sc->sc_chip;
862 uint8_t *bufp;
863 size_t addr;
864 size_t i, pages;
865 int error = 0;
866
867 *retlen = 0;
868
869 DPRINTF(("%s: off: 0x%jx, len: %zu\n",
870 __func__, (uintmax_t)offset, len));
871
872 if (__predict_false((offset + len) > chip->nc_size)) {
873 DPRINTF(("%s: read (off: 0x%jx, len: %zu),"
874 " exceeds device size (%ju)\n", __func__,
875 (uintmax_t)offset, len, (uintmax_t)chip->nc_size));
876 return EINVAL;
877 }
878
879 /* Handle unaligned access, shouldnt be needed when using the
880 * block device, as strategy handles it, so only low level
881 * accesses will use this path
882 */
883 /* XXX^2 */
884 #if 0
885 if (len < chip->nc_page_size)
886 panic("TODO page size is larger than read size");
887 #endif
888
889 if (len % chip->nc_page_size != 0 ||
890 offset % chip->nc_page_size != 0) {
891 return nor_flash_read_unaligned(self,
892 offset, len, retlen, buf);
893 }
894
895 bufp = buf;
896 addr = offset;
897 pages = len / chip->nc_page_size;
898
899 mutex_enter(&sc->sc_device_lock);
900 for (i = 0; i < pages; i++) {
901 #ifdef NOTYET
902 /* XXX do we need this check here? */
903 if (nor_isbad(self, addr)) {
904 aprint_error_dev(self, "bad block encountered\n");
905 error = EIO;
906 goto out;
907 }
908 #endif
909 error = nor_read_page(self, addr, bufp);
910 if (error)
911 goto out;
912
913 bufp += chip->nc_page_size;
914 addr += chip->nc_page_size;
915 *retlen += chip->nc_page_size;
916 }
917 out:
918 mutex_exit(&sc->sc_device_lock);
919
920 return error;
921 }
922
923 static int
924 nor_flash_isbad(device_t self, flash_off_t ofs, bool * const isbad)
925 {
926 struct nor_softc * const sc = device_private(self);
927 struct nor_chip * const chip = &sc->sc_chip;
928 #ifdef NOTYET
929 bool result;
930 #endif
931
932 if (ofs > chip->nc_size) {
933 DPRINTF(("%s: offset 0x%jx is larger than"
934 " device size (0x%jx)\n", __func__,
935 (uintmax_t)ofs, (uintmax_t)chip->nc_size));
936 return EINVAL;
937 }
938
939 if (ofs % chip->nc_block_size != 0) {
940 DPRINTF(("offset (0x%jx) is not the multiple of block size "
941 "(%ju)",
942 (uintmax_t)ofs, (uintmax_t)chip->nc_block_size));
943 return EINVAL;
944 }
945
946 #ifdef NOTYET
947 mutex_enter(&sc->sc_device_lock);
948 result = nor_isbad(self, ofs);
949 mutex_exit(&sc->sc_device_lock);
950
951 *isbad = result;
952 #else
953 *isbad = false;
954 #endif
955
956 return 0;
957 }
958
959 static int
960 nor_flash_markbad(device_t self, flash_off_t ofs)
961 {
962 struct nor_softc * const sc = device_private(self);
963 struct nor_chip * const chip = &sc->sc_chip;
964
965 if (ofs > chip->nc_size) {
966 DPRINTF(("%s: offset 0x%jx is larger than"
967 " device size (0x%jx)\n", __func__,
968 ofs, (uintmax_t)chip->nc_size));
969 return EINVAL;
970 }
971
972 if (ofs % chip->nc_block_size != 0) {
973 panic("offset (%ju) is not the multiple of block size (%ju)",
974 (uintmax_t)ofs, (uintmax_t)chip->nc_block_size);
975 }
976
977 /* TODO: implement this */
978
979 return 0;
980 }
981
982 static int
983 sysctl_nor_verify(SYSCTLFN_ARGS)
984 {
985 int error, t;
986 struct sysctlnode node;
987
988 node = *rnode;
989 t = *(int *)rnode->sysctl_data;
990 node.sysctl_data = &t;
991 error = sysctl_lookup(SYSCTLFN_CALL(&node));
992 if (error || newp == NULL)
993 return error;
994
995 if (node.sysctl_num == nor_cachesync_nodenum) {
996 if (t <= 0 || t > 60)
997 return EINVAL;
998 } else {
999 return EINVAL;
1000 }
1001
1002 *(int *)rnode->sysctl_data = t;
1003
1004 return 0;
1005 }
1006
1007 SYSCTL_SETUP(sysctl_nor, "sysctl nor subtree setup")
1008 {
1009 int rc, nor_root_num;
1010 const struct sysctlnode *node;
1011
1012 if ((rc = sysctl_createv(clog, 0, NULL, &node,
1013 CTLFLAG_PERMANENT, CTLTYPE_NODE, "nor",
1014 SYSCTL_DESCR("NOR driver controls"),
1015 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
1016 goto error;
1017 }
1018
1019 nor_root_num = node->sysctl_num;
1020
1021 if ((rc = sysctl_createv(clog, 0, NULL, &node,
1022 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1023 CTLTYPE_INT, "cache_sync_timeout",
1024 SYSCTL_DESCR("NOR write cache sync timeout in seconds"),
1025 sysctl_nor_verify, 0, &nor_cachesync_timeout,
1026 0, CTL_HW, nor_root_num, CTL_CREATE,
1027 CTL_EOL)) != 0) {
1028 goto error;
1029 }
1030
1031 nor_cachesync_nodenum = node->sysctl_num;
1032
1033 return;
1034
1035 error:
1036 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
1037 }
1038
1039 MODULE(MODULE_CLASS_DRIVER, nor, "flash");
1040
1041 #ifdef _MODULE
1042 #include "ioconf.c"
1043 #endif
1044
1045 static int
1046 nor_modcmd(modcmd_t cmd, void *opaque)
1047 {
1048 switch (cmd) {
1049 case MODULE_CMD_INIT:
1050 #ifdef _MODULE
1051 return config_init_component(cfdriver_ioconf_nor,
1052 cfattach_ioconf_nor, cfdata_ioconf_nor);
1053 #else
1054 return 0;
1055 #endif
1056 case MODULE_CMD_FINI:
1057 #ifdef _MODULE
1058 return config_fini_component(cfdriver_ioconf_nor,
1059 cfattach_ioconf_nor, cfdata_ioconf_nor);
1060 #else
1061 return 0;
1062 #endif
1063 default:
1064 return ENOTTY;
1065 }
1066 }
1067