Home | History | Annotate | Line # | Download | only in nor
cfi_0002.c revision 1.4
      1  1.4   cliff /*	$NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $	*/
      2  1.3   cliff /*-
      3  1.3   cliff  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      4  1.3   cliff  * All rights reserved.
      5  1.3   cliff  *
      6  1.3   cliff  * This code is derived from software contributed to The NetBSD Foundation
      7  1.3   cliff  * by Cliff Neighbors.
      8  1.3   cliff  *
      9  1.3   cliff  * Redistribution and use in source and binary forms, with or without
     10  1.3   cliff  * modification, are permitted provided that the following conditions
     11  1.3   cliff  * are met:
     12  1.3   cliff  * 1. Redistributions of source code must retain the above copyright
     13  1.3   cliff  *    notice, this list of conditions and the following disclaimer.
     14  1.3   cliff  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.3   cliff  *    notice, this list of conditions and the following disclaimer in the
     16  1.3   cliff  *    documentation and/or other materials provided with the distribution.
     17  1.3   cliff  *
     18  1.3   cliff  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  1.3   cliff  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  1.3   cliff  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  1.3   cliff  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  1.3   cliff  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  1.3   cliff  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  1.3   cliff  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  1.3   cliff  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  1.3   cliff  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  1.3   cliff  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  1.3   cliff  * POSSIBILITY OF SUCH DAMAGE.
     29  1.3   cliff  */
     30  1.1   cliff 
     31  1.1   cliff #include "opt_flash.h"
     32  1.1   cliff 
     33  1.1   cliff #include <sys/cdefs.h>
     34  1.4   cliff __KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $");
     35  1.1   cliff 
     36  1.1   cliff #include <sys/param.h>
     37  1.1   cliff #include <sys/systm.h>
     38  1.1   cliff #include <sys/cdefs.h>
     39  1.1   cliff #include <sys/device.h>
     40  1.1   cliff #include <sys/endian.h>
     41  1.1   cliff #include <sys/time.h>
     42  1.1   cliff 
     43  1.2  dyoung #include <sys/bus.h>
     44  1.1   cliff 
     45  1.1   cliff #include <dev/nor/nor.h>
     46  1.1   cliff #include <dev/nor/cfi.h>
     47  1.1   cliff #include <dev/nor/cfi_0002.h>
     48  1.1   cliff 
     49  1.1   cliff 
     50  1.1   cliff static void cfi_0002_version_init(struct cfi * const);
     51  1.1   cliff static int  cfi_0002_read_page(device_t, flash_off_t, uint8_t *);
     52  1.1   cliff static int  cfi_0002_program_page(device_t, flash_off_t, const uint8_t *);
     53  1.1   cliff static int  cfi_0002_erase_block(device_t, flash_off_t);
     54  1.1   cliff static int  cfi_0002_erase_all(device_t);
     55  1.1   cliff static int  cfi_0002_busy(device_t, flash_off_t, u_long);
     56  1.1   cliff static int  cfi_0002_busy_wait(struct cfi * const, flash_off_t, u_long);
     57  1.1   cliff static int  cfi_0002_busy_poll(struct cfi * const, flash_off_t, u_long);
     58  1.1   cliff static int  cfi_0002_busy_yield(struct cfi * const, flash_off_t, u_long);
     59  1.1   cliff static int  cfi_0002_busy_dq7(struct cfi * const , flash_off_t);
     60  1.1   cliff #ifdef NOTYET
     61  1.1   cliff static int  cfi_0002_busy_reg(struct cfi * const, flash_off_t);
     62  1.1   cliff #endif
     63  1.1   cliff 
     64  1.1   cliff 
     65  1.1   cliff static const char *page_mode_str[] = {
     66  1.1   cliff 	"(not supported)",
     67  1.1   cliff 	"4 word page",
     68  1.1   cliff 	"8 word page",
     69  1.1   cliff 	"16 word page",
     70  1.1   cliff };
     71  1.1   cliff 
     72  1.1   cliff static const char *wp_mode_str[] = {
     73  1.1   cliff 	"Flash device without WP Protect (No Boot)",
     74  1.1   cliff 	"Eight 8 kB Sectors at TOP and Bottom with WP (Dual Boot)",
     75  1.1   cliff 	"Bottom Boot Device with WP Protect (Bottom Boot)",
     76  1.1   cliff 	"Top Boot Device with WP Protect (Top Boot)",
     77  1.1   cliff 	"Uniform, Bottom WP Protect (Uniform Bottom Boot)",
     78  1.1   cliff 	"Uniform, Top WP Protect (Uniform Top Boot)",
     79  1.1   cliff 	"WP Protect for all sectors",
     80  1.1   cliff 	"Uniform, Top or Bottom WP Protect",
     81  1.1   cliff };
     82  1.1   cliff 
     83  1.1   cliff 
     84  1.1   cliff static inline const char *
     85  1.1   cliff cfi_0002_page_mode_str(uint8_t mode)
     86  1.1   cliff {
     87  1.1   cliff 	if (mode >= __arraycount(page_mode_str))
     88  1.1   cliff 		panic("%s: mode %d out of range", __func__, mode);
     89  1.1   cliff 	return page_mode_str[mode];
     90  1.1   cliff }
     91  1.1   cliff 
     92  1.1   cliff static inline const char *
     93  1.1   cliff cfi_0002_wp_mode_str(uint8_t mode)
     94  1.1   cliff {
     95  1.1   cliff 	if (mode >= __arraycount(wp_mode_str))
     96  1.1   cliff 		panic("%s: mode %d out of range", __func__, mode);
     97  1.1   cliff 	return wp_mode_str[mode];
     98  1.1   cliff }
     99  1.1   cliff 
    100  1.1   cliff /*
    101  1.1   cliff  * cfi_0002_time_write_nbyte - maximum usec delay waiting for write buffer
    102  1.1   cliff  */
    103  1.1   cliff static inline u_long
    104  1.1   cliff cfi_0002_time_write_nbyte(struct cfi *cfi)
    105  1.1   cliff {
    106  1.1   cliff 	u_int shft = cfi->cfi_qry_data.write_nbyte_time_typ;
    107  1.1   cliff 	shft += cfi->cfi_qry_data.write_nbyte_time_max;
    108  1.1   cliff 	u_long usec = 1UL << shft;
    109  1.1   cliff 	return usec;
    110  1.1   cliff }
    111  1.1   cliff 
    112  1.1   cliff /*
    113  1.1   cliff  * cfi_0002_time_erase_blk - maximum usec delay waiting for erase block
    114  1.1   cliff  */
    115  1.1   cliff static inline u_long
    116  1.1   cliff cfi_0002_time_erase_blk(struct cfi *cfi)
    117  1.1   cliff {
    118  1.1   cliff 	u_int shft = cfi->cfi_qry_data.erase_blk_time_typ;
    119  1.1   cliff 	shft += cfi->cfi_qry_data.erase_blk_time_max;
    120  1.1   cliff 	u_long usec = 1000UL << shft;
    121  1.1   cliff 	return usec;
    122  1.1   cliff }
    123  1.1   cliff 
    124  1.1   cliff /*
    125  1.1   cliff  * cfi_0002_time_erase_all - maximum usec delay waiting for erase chip
    126  1.1   cliff  */
    127  1.1   cliff static inline u_long
    128  1.1   cliff cfi_0002_time_erase_all(struct cfi *cfi)
    129  1.1   cliff {
    130  1.4   cliff 	u_int shft = cfi->cfi_qry_data.erase_chip_time_typ;
    131  1.4   cliff 	shft += cfi->cfi_qry_data.erase_chip_time_max;
    132  1.1   cliff 	u_long usec = 1000UL << shft;
    133  1.1   cliff 	return usec;
    134  1.1   cliff }
    135  1.1   cliff 
    136  1.1   cliff /*
    137  1.1   cliff  * cfi_0002_time_dflt - maximum usec delay to use waiting for ready
    138  1.1   cliff  *
    139  1.1   cliff  * use the maximum delay for chip erase function
    140  1.1   cliff  * that should be the worst non-sick case
    141  1.1   cliff  */
    142  1.1   cliff static inline u_long
    143  1.1   cliff cfi_0002_time_dflt(struct cfi *cfi)
    144  1.1   cliff {
    145  1.1   cliff 	return cfi_0002_time_erase_all(cfi);
    146  1.1   cliff }
    147  1.1   cliff 
    148  1.1   cliff void
    149  1.1   cliff cfi_0002_init(struct nor_softc * const sc, struct cfi * const cfi,
    150  1.1   cliff     struct nor_chip * const chip)
    151  1.1   cliff {
    152  1.1   cliff 	CFI_0002_STATS_INIT(sc->sc_dev, cfi);
    153  1.1   cliff 
    154  1.1   cliff 	cfi_0002_version_init(cfi);
    155  1.1   cliff 
    156  1.1   cliff 	cfi->cfi_ops.cfi_reset = cfi_reset_std;
    157  1.1   cliff 	cfi->cfi_yield_time = 500;		/* 500 usec */
    158  1.1   cliff 
    159  1.1   cliff 	/* page size for buffered write */
    160  1.1   cliff 	chip->nc_page_size =
    161  1.1   cliff 		1 << cfi->cfi_qry_data.write_nbyte_size_max;
    162  1.1   cliff 
    163  1.1   cliff 	/* these are unused */
    164  1.1   cliff 	chip->nc_spare_size = 0;
    165  1.1   cliff 	chip->nc_badmarker_offs = 0;
    166  1.1   cliff 
    167  1.1   cliff 	/* establish command-set-specific interface ops */
    168  1.1   cliff 	sc->sc_nor_if->read_page = cfi_0002_read_page;
    169  1.1   cliff 	sc->sc_nor_if->program_page = cfi_0002_program_page;
    170  1.1   cliff 	sc->sc_nor_if->erase_block = cfi_0002_erase_block;
    171  1.1   cliff 	sc->sc_nor_if->erase_all = cfi_0002_erase_all;
    172  1.1   cliff 	sc->sc_nor_if->busy = cfi_0002_busy;
    173  1.1   cliff 
    174  1.1   cliff }
    175  1.1   cliff 
    176  1.1   cliff /*
    177  1.1   cliff  * cfi_0002_version_init - command set version-specific initialization
    178  1.1   cliff  *
    179  1.1   cliff  * see "Programmer's Guide for the Spansion 65 nm GL-S MirrorBit EclipseTM
    180  1.1   cliff  * Flash Non-Volatile Memory Family Architecture" section 5.
    181  1.1   cliff  */
    182  1.1   cliff static void
    183  1.1   cliff cfi_0002_version_init(struct cfi * const cfi)
    184  1.1   cliff {
    185  1.1   cliff 	const uint8_t major = cfi->cfi_qry_data.pri.cmd_0002.version_maj;
    186  1.1   cliff 	const uint8_t minor = cfi->cfi_qry_data.pri.cmd_0002.version_min;
    187  1.1   cliff 
    188  1.1   cliff 	if ((minor == '3') && (major == '1')) {
    189  1.1   cliff 		/* cmdset version 1.3 */
    190  1.1   cliff 		cfi->cfi_ops.cfi_busy = cfi_0002_busy_dq7;
    191  1.1   cliff #ifdef NOTYET
    192  1.1   cliff 		cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_q;
    193  1.1   cliff 		cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_ub;
    194  1.1   cliff 	} else if ((minor >= '5') && (major == '1')) {
    195  1.1   cliff 		/* cmdset version 1.5 or later */
    196  1.1   cliff 		cfi->cfi_ops.cfi_busy = cfi_0002_busy_reg;
    197  1.1   cliff 		cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_1;
    198  1.1   cliff 		cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_no_ub;
    199  1.1   cliff #endif
    200  1.1   cliff 	} else {
    201  1.1   cliff 		/* XXX this is excessive */
    202  1.1   cliff 		panic("%s: unknown cmdset version %c.%c\n",
    203  1.1   cliff 			__func__, major, minor);
    204  1.1   cliff 	}
    205  1.1   cliff 
    206  1.1   cliff }
    207  1.1   cliff 
    208  1.1   cliff void
    209  1.1   cliff cfi_0002_print(device_t self, struct cfi * const cfi)
    210  1.1   cliff {
    211  1.1   cliff #ifdef NOR_VERBOSE
    212  1.1   cliff 	struct cmdset_0002_query_data *pri = &cfi->cfi_qry_data.pri.cmd_0002;
    213  1.1   cliff 
    214  1.1   cliff 	aprint_normal_dev(self, "AMD/Fujitsu cmdset (0x0002) version=%c.%c\n",
    215  1.1   cliff 		pri->version_maj, pri->version_min);
    216  1.1   cliff 	aprint_normal_dev(self, "page mode type: %s\n",
    217  1.1   cliff 		cfi_0002_page_mode_str(pri->page_mode_type));
    218  1.1   cliff 	aprint_normal_dev(self, "wp protection: %s\n",
    219  1.1   cliff 		cfi_0002_wp_mode_str(pri->wp_prot));
    220  1.1   cliff 	aprint_normal_dev(self, "program suspend %ssupported\n",
    221  1.1   cliff 		(pri->prog_susp == 0) ? "not " : "");
    222  1.1   cliff 	aprint_normal_dev(self, "unlock bypass %ssupported\n",
    223  1.1   cliff 		(pri->unlock_bypass == 0) ? "not " : "");
    224  1.1   cliff 	aprint_normal_dev(self, "secure silicon sector size %#x\n",
    225  1.1   cliff 		1 << pri->sss_size);
    226  1.1   cliff 	aprint_normal_dev(self, "SW features %#x\n", pri->soft_feat);
    227  1.1   cliff 	aprint_normal_dev(self, "page size %d\n", 1 << pri->page_size);
    228  1.1   cliff #endif
    229  1.1   cliff }
    230  1.1   cliff 
    231  1.1   cliff static int
    232  1.1   cliff cfi_0002_read_page(device_t self, flash_off_t offset, uint8_t *datap)
    233  1.1   cliff {
    234  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    235  1.1   cliff 	KASSERT(sc != NULL);
    236  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    237  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    238  1.1   cliff 	KASSERT(cfi != NULL);
    239  1.1   cliff 	struct nor_chip * const chip = &sc->sc_chip;
    240  1.1   cliff 	KASSERT(chip != NULL);
    241  1.1   cliff 	KASSERT(chip->nc_page_mask != 0);
    242  1.1   cliff 	KASSERT((offset & ~chip->nc_page_mask) == 0);
    243  1.1   cliff 	KASSERT (chip->nc_page_size != 0);
    244  1.1   cliff 	KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
    245  1.1   cliff 
    246  1.1   cliff 	CFI_0002_STATS_INC(cfi, read_page);
    247  1.1   cliff 
    248  1.1   cliff 	bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth;
    249  1.1   cliff 							/* #words/page */
    250  1.1   cliff 
    251  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
    252  1.1   cliff 	if (error != 0)
    253  1.1   cliff 		return error;
    254  1.1   cliff 
    255  1.1   cliff 	switch(cfi->cfi_portwidth) {
    256  1.1   cliff 	case 0:
    257  1.1   cliff 		bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset,
    258  1.1   cliff 			(uint8_t *)datap, count);
    259  1.1   cliff 		break;
    260  1.1   cliff 	case 1:
    261  1.1   cliff 		bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset,
    262  1.1   cliff 			(uint16_t *)datap, count);
    263  1.1   cliff 		break;
    264  1.1   cliff 	case 2:
    265  1.1   cliff 		bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset,
    266  1.1   cliff 			(uint32_t *)datap, count);
    267  1.1   cliff 		break;
    268  1.1   cliff 	default:
    269  1.1   cliff 		panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
    270  1.1   cliff 	};
    271  1.1   cliff 
    272  1.1   cliff 	return 0;
    273  1.1   cliff }
    274  1.1   cliff 
    275  1.1   cliff static int
    276  1.1   cliff cfi_0002_program_page(device_t self, flash_off_t offset, const uint8_t *datap)
    277  1.1   cliff {
    278  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    279  1.1   cliff 	KASSERT(sc != NULL);
    280  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    281  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    282  1.1   cliff 	KASSERT(cfi != NULL);
    283  1.1   cliff 	struct nor_chip * const chip = &sc->sc_chip;
    284  1.1   cliff 	KASSERT(chip != NULL);
    285  1.1   cliff 	KASSERT(chip->nc_page_mask != 0);
    286  1.1   cliff 	KASSERT((offset & ~chip->nc_page_mask) == 0);
    287  1.1   cliff 	KASSERT (chip->nc_page_size != 0);
    288  1.1   cliff 	KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
    289  1.1   cliff 
    290  1.1   cliff 	CFI_0002_STATS_INC(cfi, program_page);
    291  1.1   cliff 
    292  1.1   cliff 	bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth;
    293  1.1   cliff 							/* #words/page */
    294  1.1   cliff 	bus_size_t sa = offset >> cfi->cfi_portwidth;	/* sector addr */
    295  1.1   cliff 	uint32_t wc = count - 1;			/* #words - 1 */
    296  1.1   cliff 
    297  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
    298  1.1   cliff 	if (error != 0)
    299  1.1   cliff 		return ETIMEDOUT;
    300  1.1   cliff 
    301  1.1   cliff 	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
    302  1.1   cliff 	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
    303  1.1   cliff 	cfi_cmd(cfi, sa,    0x25); /* Write To Buffer */
    304  1.1   cliff 	cfi_cmd(cfi, sa,    wc);
    305  1.1   cliff 
    306  1.1   cliff 	switch(cfi->cfi_portwidth) {
    307  1.1   cliff 	case 0:
    308  1.1   cliff 		bus_space_write_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset,
    309  1.1   cliff 			(const uint8_t *)datap, count);
    310  1.1   cliff 		break;
    311  1.1   cliff 	case 1:
    312  1.1   cliff 		bus_space_write_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset,
    313  1.1   cliff 			(const uint16_t *)datap, count);
    314  1.1   cliff 		break;
    315  1.1   cliff 	case 2:
    316  1.1   cliff 		bus_space_write_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset,
    317  1.1   cliff 			(const uint32_t *)datap, count);
    318  1.1   cliff 		break;
    319  1.1   cliff 	default:
    320  1.1   cliff 		panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
    321  1.1   cliff 	};
    322  1.1   cliff 
    323  1.1   cliff 	cfi_cmd(cfi, sa,    0x29);	/*  Write Buffer Program Confirm */
    324  1.1   cliff 
    325  1.1   cliff 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi));
    326  1.1   cliff 
    327  1.1   cliff 	return error;
    328  1.1   cliff }
    329  1.1   cliff 
    330  1.1   cliff static int
    331  1.1   cliff cfi_0002_erase_all(device_t self)
    332  1.1   cliff {
    333  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    334  1.1   cliff 	KASSERT(sc != NULL);
    335  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    336  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    337  1.1   cliff 	KASSERT(cfi != NULL);
    338  1.1   cliff 	struct nor_chip * const chip = &sc->sc_chip;
    339  1.1   cliff 	KASSERT(chip != NULL);
    340  1.1   cliff 
    341  1.1   cliff 	CFI_0002_STATS_INC(cfi, erase_all);
    342  1.1   cliff 
    343  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_dflt(cfi));
    344  1.1   cliff 	if (error != 0)
    345  1.1   cliff 		return ETIMEDOUT;
    346  1.1   cliff 
    347  1.1   cliff 	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
    348  1.1   cliff 	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
    349  1.1   cliff 	cfi_cmd(cfi, 0x555, 0x80); /* erase start */
    350  1.1   cliff 	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
    351  1.1   cliff 	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
    352  1.1   cliff 	cfi_cmd(cfi, 0x555, 0x10); /* erase chip */
    353  1.1   cliff 
    354  1.1   cliff 	error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi));
    355  1.1   cliff 
    356  1.1   cliff 	return error;
    357  1.1   cliff }
    358  1.1   cliff 
    359  1.1   cliff static int
    360  1.1   cliff cfi_0002_erase_block(device_t self, flash_off_t offset)
    361  1.1   cliff {
    362  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    363  1.1   cliff 	KASSERT(sc != NULL);
    364  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    365  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    366  1.1   cliff 	KASSERT(cfi != NULL);
    367  1.1   cliff 	struct nor_chip * const chip = &sc->sc_chip;
    368  1.1   cliff 	KASSERT(chip != NULL);
    369  1.1   cliff 	KASSERT(chip->nc_block_mask != 0);
    370  1.1   cliff 	KASSERT((offset & ~chip->nc_block_mask) == 0);
    371  1.1   cliff 	KASSERT(chip->nc_block_size != 0);
    372  1.1   cliff 	KASSERT((chip->nc_block_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
    373  1.1   cliff 
    374  1.1   cliff 	CFI_0002_STATS_INC(cfi, erase_block);
    375  1.1   cliff 
    376  1.1   cliff 	/* scale sector addr by portwidth or chipwidth ?  */
    377  1.1   cliff 	bus_size_t sa = offset >> cfi->cfi_portwidth;
    378  1.1   cliff 
    379  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
    380  1.1   cliff 	if (error != 0)
    381  1.1   cliff 		return ETIMEDOUT;
    382  1.1   cliff 
    383  1.1   cliff 	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
    384  1.1   cliff 	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
    385  1.1   cliff 	cfi_cmd(cfi, 0x555, 0x80); /* erase start */
    386  1.1   cliff 	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
    387  1.1   cliff 	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
    388  1.1   cliff 	cfi_cmd(cfi, sa,    0x30); /* erase sector */
    389  1.1   cliff 
    390  1.1   cliff 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi));
    391  1.1   cliff 
    392  1.1   cliff 	return error;
    393  1.1   cliff }
    394  1.1   cliff 
    395  1.1   cliff /*
    396  1.1   cliff  * cfi_0002_busy - nor_interface busy op
    397  1.1   cliff  */
    398  1.1   cliff static int
    399  1.1   cliff cfi_0002_busy(device_t self, flash_off_t offset, u_long usec)
    400  1.1   cliff {
    401  1.1   cliff 	struct nor_softc *sc = device_private(self);
    402  1.1   cliff 	KASSERT(sc != NULL);
    403  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    404  1.1   cliff 	struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
    405  1.1   cliff 
    406  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy);
    407  1.1   cliff 
    408  1.1   cliff 	return cfi_0002_busy_wait(cfi, offset, usec);
    409  1.1   cliff }
    410  1.1   cliff 
    411  1.1   cliff /*
    412  1.1   cliff  * cfi_0002_busy_wait - wait until device is not busy
    413  1.1   cliff  */
    414  1.1   cliff static int
    415  1.1   cliff cfi_0002_busy_wait(struct cfi * const cfi, flash_off_t offset, u_long usec)
    416  1.1   cliff {
    417  1.1   cliff 	int error;
    418  1.1   cliff 
    419  1.1   cliff #ifdef CFI_0002_STATS
    420  1.1   cliff 	struct timeval start;
    421  1.1   cliff 	struct timeval now;
    422  1.1   cliff 	struct timeval delta;
    423  1.1   cliff 
    424  1.1   cliff 	if (usec > cfi->cfi_0002_stats.busy_usec_max)
    425  1.1   cliff 		cfi->cfi_0002_stats.busy_usec_max = usec;
    426  1.1   cliff 	if (usec < cfi->cfi_0002_stats.busy_usec_min)
    427  1.1   cliff 		cfi->cfi_0002_stats.busy_usec_min = usec;
    428  1.1   cliff 	microtime(&start);
    429  1.1   cliff #endif
    430  1.1   cliff 	if (usec > cfi->cfi_yield_time) {
    431  1.1   cliff 		error = cfi_0002_busy_yield(cfi, offset, usec);
    432  1.1   cliff #ifdef CFI_0002_STATS
    433  1.1   cliff 		microtime(&now);
    434  1.1   cliff 		cfi->cfi_0002_stats.busy_yield++;
    435  1.1   cliff 		timersub(&now, &start, &delta);
    436  1.1   cliff 		timeradd(&delta,
    437  1.1   cliff 			&cfi->cfi_0002_stats.busy_yield_tv,
    438  1.1   cliff 			&cfi->cfi_0002_stats.busy_yield_tv);
    439  1.1   cliff #endif
    440  1.1   cliff 	} else {
    441  1.1   cliff 		error = cfi_0002_busy_poll(cfi, offset, usec);
    442  1.1   cliff #ifdef CFI_0002_STATS
    443  1.1   cliff 		microtime(&now);
    444  1.1   cliff 		cfi->cfi_0002_stats.busy_poll++;
    445  1.1   cliff 		timersub(&now, &start, &delta);
    446  1.1   cliff 		timeradd(&delta,
    447  1.1   cliff 			&cfi->cfi_0002_stats.busy_poll_tv,
    448  1.1   cliff 			&cfi->cfi_0002_stats.busy_poll_tv);
    449  1.1   cliff #endif
    450  1.1   cliff 	}
    451  1.1   cliff 	return error;
    452  1.1   cliff }
    453  1.1   cliff 
    454  1.1   cliff /*
    455  1.1   cliff  * cfi_0002_busy_poll - poll until device is not busy
    456  1.1   cliff  */
    457  1.1   cliff static int
    458  1.1   cliff cfi_0002_busy_poll(struct cfi * const cfi, flash_off_t offset, u_long usec)
    459  1.1   cliff {
    460  1.1   cliff 	u_long count = usec >> 3;
    461  1.1   cliff 	if (count == 0)
    462  1.1   cliff 		count = 1;	/* enforce minimum */
    463  1.1   cliff 	do {
    464  1.1   cliff 		if (! cfi->cfi_ops.cfi_busy(cfi, offset))
    465  1.1   cliff 			return 0;	/* not busy */
    466  1.1   cliff 		DELAY(8);
    467  1.1   cliff 	} while (count-- != 0);
    468  1.1   cliff 
    469  1.1   cliff 	return ETIMEDOUT;		/* busy */
    470  1.1   cliff }
    471  1.1   cliff 
    472  1.1   cliff /*
    473  1.1   cliff  * cfi_0002_busy_yield - yield until device is not busy
    474  1.1   cliff  */
    475  1.1   cliff static int
    476  1.1   cliff cfi_0002_busy_yield(struct cfi * const cfi, flash_off_t offset, u_long usec)
    477  1.1   cliff {
    478  1.1   cliff 	struct timeval start;
    479  1.1   cliff 	struct timeval delta;
    480  1.1   cliff 	struct timeval limit;
    481  1.1   cliff 	struct timeval now;
    482  1.1   cliff 
    483  1.1   cliff 	microtime(&start);
    484  1.1   cliff 
    485  1.1   cliff 	/* try optimism */
    486  1.1   cliff 	if (! cfi->cfi_ops.cfi_busy(cfi, offset)) {
    487  1.1   cliff 		CFI_0002_STATS_INC(cfi, busy_yield_hit);
    488  1.1   cliff 		return 0;		/* not busy */
    489  1.1   cliff 	}
    490  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy_yield_miss);
    491  1.1   cliff 
    492  1.1   cliff 	delta.tv_sec = usec / 1000000;
    493  1.1   cliff 	delta.tv_usec = usec % 1000000;
    494  1.1   cliff 	timeradd(&start, &delta, &limit);
    495  1.1   cliff 	do {
    496  1.1   cliff 		yield();
    497  1.1   cliff 		microtime(&now);
    498  1.1   cliff 		if (! cfi->cfi_ops.cfi_busy(cfi, offset))
    499  1.1   cliff 			return 0;	/* not busy */
    500  1.1   cliff 	} while (timercmp(&now, &limit, <));
    501  1.1   cliff 
    502  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy_yield_timo);
    503  1.1   cliff 
    504  1.1   cliff 	return ETIMEDOUT;		/* busy */
    505  1.1   cliff }
    506  1.1   cliff 
    507  1.1   cliff /*
    508  1.1   cliff  * cfi_0002_busy_dq7 - DQ7 "toggle" method to check busy
    509  1.1   cliff  *
    510  1.1   cliff  * Check busy during/after erase, program, protect operation.
    511  1.1   cliff  *
    512  1.1   cliff  * NOTE:
    513  1.1   cliff  *	Chip manufacturers (Spansion) plan to deprecate this method.
    514  1.1   cliff  */
    515  1.1   cliff static int
    516  1.1   cliff cfi_0002_busy_dq7(struct cfi * const cfi, flash_off_t offset)
    517  1.1   cliff {
    518  1.1   cliff 	bus_space_tag_t bst = cfi->cfi_bst;
    519  1.1   cliff 	bus_space_handle_t bsh = cfi->cfi_bsh;
    520  1.1   cliff 	bool busy;
    521  1.1   cliff 
    522  1.1   cliff 	switch(cfi->cfi_portwidth) {
    523  1.1   cliff 	case 0: {
    524  1.1   cliff 		uint8_t r0 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
    525  1.1   cliff 		uint8_t r1 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
    526  1.1   cliff 		busy = (r0 != r1);
    527  1.1   cliff 		break;
    528  1.1   cliff 	}
    529  1.1   cliff 	case 1: {
    530  1.1   cliff 		uint16_t r0 = bus_space_read_2(bst, bsh, 0);
    531  1.1   cliff 		uint16_t r1 = bus_space_read_2(bst, bsh, 0);
    532  1.1   cliff 		busy = (r0 != r1);
    533  1.1   cliff 		break;
    534  1.1   cliff 	}
    535  1.1   cliff 	case 2: {
    536  1.1   cliff 		uint32_t r0 = bus_space_read_4(bst, bsh, 0);
    537  1.1   cliff 		uint32_t r1 = bus_space_read_4(bst, bsh, 0);
    538  1.1   cliff 		busy = (r0 != r1);
    539  1.1   cliff 		break;
    540  1.1   cliff 	}
    541  1.1   cliff 	default:
    542  1.1   cliff 		busy = true;	/* appeas gcc */
    543  1.1   cliff 		panic("%s: bad port width %d\n",
    544  1.1   cliff 			__func__, cfi->cfi_portwidth);
    545  1.1   cliff 	}
    546  1.1   cliff 	return busy;
    547  1.1   cliff }
    548  1.1   cliff 
    549  1.1   cliff #ifdef NOTYET
    550  1.1   cliff /*
    551  1.1   cliff  * cfi_0002_busy_reg - read and evaluate Read Status Register
    552  1.1   cliff  *
    553  1.1   cliff  * NOTE:
    554  1.1   cliff  *	Read Status Register not present on all chips
    555  1.1   cliff  *	use "toggle" method when Read Status Register not available.
    556  1.1   cliff  */
    557  1.1   cliff static bool
    558  1.1   cliff cfi_0002_busy_reg(struct cfi * const cfi, flash_off_t offset)
    559  1.1   cliff {
    560  1.1   cliff 	bus_space_tag_t bst = cfi->cfi_bst;
    561  1.1   cliff 	bus_space_handle_t bsh = cfi->cfi_bsh;
    562  1.1   cliff 	uint32_t r;
    563  1.1   cliff 
    564  1.1   cliff 	cfi_cmd(cfi, 0x555, 0x70);	/* Status Register Read  */
    565  1.1   cliff 
    566  1.1   cliff 	switch(cfi->cfi_portwidth) {
    567  1.1   cliff 	case 0:
    568  1.1   cliff 		r = bus_space_read_1(bst, bsh, 0);
    569  1.1   cliff 		break;
    570  1.1   cliff 	case 1:
    571  1.1   cliff 		r = bus_space_read_2(bst, bsh, 0);
    572  1.1   cliff 		break;
    573  1.1   cliff 	case 2:
    574  1.1   cliff 		r = bus_space_read_4(bst, bsh, 0);
    575  1.1   cliff 		break;
    576  1.1   cliff 	default:
    577  1.1   cliff 		panic("%s: bad port width %d\n",
    578  1.1   cliff 			__func__, cfi->cfi_portwidth);
    579  1.1   cliff 	}
    580  1.1   cliff 
    581  1.1   cliff 	return ((r & __BIT(7)) == 0):
    582  1.1   cliff }
    583  1.1   cliff #endif	/* NOTYET */
    584  1.1   cliff 
    585  1.1   cliff #ifdef CFI_0002_STATS
    586  1.1   cliff void
    587  1.1   cliff cfi_0002_stats_reset(struct cfi *cfi)
    588  1.1   cliff {
    589  1.1   cliff 	memset(&cfi->cfi_0002_stats, 0, sizeof(struct cfi_0002_stats));
    590  1.1   cliff         cfi->cfi_0002_stats.busy_usec_min = ~0;
    591  1.1   cliff }
    592  1.1   cliff 
    593  1.1   cliff void
    594  1.1   cliff cfi_0002_stats_print(struct cfi *cfi)
    595  1.1   cliff {
    596  1.1   cliff 	printf("read_page %lu\n", cfi->cfi_0002_stats.read_page);
    597  1.1   cliff 	printf("program_page %lu\n", cfi->cfi_0002_stats.program_page);
    598  1.1   cliff 	printf("erase_all %lu\n", cfi->cfi_0002_stats.erase_all);
    599  1.1   cliff 	printf("erase_block %lu\n", cfi->cfi_0002_stats.erase_block);
    600  1.1   cliff 	printf("busy %lu\n", cfi->cfi_0002_stats.busy);
    601  1.1   cliff 
    602  1.1   cliff 	printf("write_nbyte_time_typ %d\n",
    603  1.1   cliff 		 cfi->cfi_qry_data.write_nbyte_time_typ);
    604  1.1   cliff 	printf("write_nbyte_time_max %d\n",
    605  1.1   cliff 		 cfi->cfi_qry_data.write_nbyte_time_max);
    606  1.1   cliff 
    607  1.1   cliff 	printf("erase_blk_time_typ %d\n",
    608  1.1   cliff 		 cfi->cfi_qry_data.erase_blk_time_typ);
    609  1.1   cliff 	printf("erase_blk_time_max %d\n",
    610  1.1   cliff 		 cfi->cfi_qry_data.erase_blk_time_max);
    611  1.1   cliff 
    612  1.4   cliff 	printf("erase_chip_time_typ %d\n",
    613  1.4   cliff 		 cfi->cfi_qry_data.erase_chip_time_typ);
    614  1.4   cliff 	printf("erase_chip_time_max %d\n",
    615  1.4   cliff 		 cfi->cfi_qry_data.erase_chip_time_max);
    616  1.1   cliff 
    617  1.1   cliff 	printf("time_write_nbyte %lu\n", cfi_0002_time_write_nbyte(cfi));
    618  1.1   cliff 	printf("time_erase_blk %lu\n", cfi_0002_time_erase_blk(cfi));
    619  1.1   cliff 	printf("time_erase_all %lu\n", cfi_0002_time_erase_all(cfi));
    620  1.1   cliff 
    621  1.1   cliff 	printf("busy_usec_min %lu\n", cfi->cfi_0002_stats.busy_usec_min);
    622  1.1   cliff 	printf("busy_usec_max %lu\n", cfi->cfi_0002_stats.busy_usec_max);
    623  1.1   cliff 
    624  1.1   cliff 	printf("busy_poll_tv %lld.%d\n",
    625  1.1   cliff 		cfi->cfi_0002_stats.busy_poll_tv.tv_sec,
    626  1.1   cliff 		cfi->cfi_0002_stats.busy_poll_tv.tv_usec);
    627  1.1   cliff 	printf("busy_yield_tv %lld.%d\n",
    628  1.1   cliff 		cfi->cfi_0002_stats.busy_yield_tv.tv_sec,
    629  1.1   cliff 		cfi->cfi_0002_stats.busy_yield_tv.tv_usec);
    630  1.1   cliff 	printf("busy_poll %lu\n", cfi->cfi_0002_stats.busy_poll);
    631  1.1   cliff 	printf("busy_yield %lu\n", cfi->cfi_0002_stats.busy_yield);
    632  1.1   cliff 	printf("busy_yield_hit %lu\n", cfi->cfi_0002_stats.busy_yield_hit);
    633  1.1   cliff 	printf("busy_yield_miss %lu\n", cfi->cfi_0002_stats.busy_yield_miss);
    634  1.1   cliff 	printf("busy_yield_timo %lu\n", cfi->cfi_0002_stats.busy_yield_timo);
    635  1.1   cliff }
    636  1.1   cliff #endif	/* CFI_0002_STATS */
    637