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