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