Home | History | Annotate | Line # | Download | only in nor
cfi_0002.c revision 1.7
      1  1.7   joerg /*	$NetBSD: cfi_0002.c,v 1.7 2014/07/24 23:25:53 joerg 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.7   joerg __KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.7 2014/07/24 23:25:53 joerg 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.7   joerg #ifdef NOR_VERBOSE
     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 static inline const char *
     84  1.1   cliff cfi_0002_page_mode_str(uint8_t mode)
     85  1.1   cliff {
     86  1.1   cliff 	if (mode >= __arraycount(page_mode_str))
     87  1.1   cliff 		panic("%s: mode %d out of range", __func__, mode);
     88  1.1   cliff 	return page_mode_str[mode];
     89  1.1   cliff }
     90  1.1   cliff 
     91  1.1   cliff static inline const char *
     92  1.1   cliff cfi_0002_wp_mode_str(uint8_t mode)
     93  1.1   cliff {
     94  1.1   cliff 	if (mode >= __arraycount(wp_mode_str))
     95  1.1   cliff 		panic("%s: mode %d out of range", __func__, mode);
     96  1.1   cliff 	return wp_mode_str[mode];
     97  1.1   cliff }
     98  1.7   joerg #endif
     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.6     phx 	bus_size_t sa = offset << (3 - cfi->cfi_portwidth);
    295  1.6     phx 							/* sector addr */
    296  1.1   cliff 	uint32_t wc = count - 1;			/* #words - 1 */
    297  1.1   cliff 
    298  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
    299  1.1   cliff 	if (error != 0)
    300  1.1   cliff 		return ETIMEDOUT;
    301  1.1   cliff 
    302  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
    303  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
    304  1.6     phx 	cfi_cmd(cfi, sa,                    0x25); /* Write To Buffer */
    305  1.6     phx 	cfi_cmd(cfi, sa,                    wc);
    306  1.1   cliff 
    307  1.1   cliff 	switch(cfi->cfi_portwidth) {
    308  1.1   cliff 	case 0:
    309  1.1   cliff 		bus_space_write_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset,
    310  1.1   cliff 			(const uint8_t *)datap, count);
    311  1.1   cliff 		break;
    312  1.1   cliff 	case 1:
    313  1.1   cliff 		bus_space_write_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset,
    314  1.1   cliff 			(const uint16_t *)datap, count);
    315  1.1   cliff 		break;
    316  1.1   cliff 	case 2:
    317  1.1   cliff 		bus_space_write_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset,
    318  1.1   cliff 			(const uint32_t *)datap, count);
    319  1.1   cliff 		break;
    320  1.1   cliff 	default:
    321  1.1   cliff 		panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
    322  1.1   cliff 	};
    323  1.1   cliff 
    324  1.6     phx 	cfi_cmd(cfi, sa, 0x29);	/*  Write Buffer Program Confirm */
    325  1.1   cliff 
    326  1.1   cliff 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi));
    327  1.1   cliff 
    328  1.1   cliff 	return error;
    329  1.1   cliff }
    330  1.1   cliff 
    331  1.1   cliff static int
    332  1.1   cliff cfi_0002_erase_all(device_t self)
    333  1.1   cliff {
    334  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    335  1.1   cliff 	KASSERT(sc != NULL);
    336  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    337  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    338  1.1   cliff 	KASSERT(cfi != NULL);
    339  1.1   cliff 
    340  1.1   cliff 	CFI_0002_STATS_INC(cfi, erase_all);
    341  1.1   cliff 
    342  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_dflt(cfi));
    343  1.1   cliff 	if (error != 0)
    344  1.1   cliff 		return ETIMEDOUT;
    345  1.1   cliff 
    346  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
    347  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
    348  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */
    349  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
    350  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
    351  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x10); /* erase chip */
    352  1.1   cliff 
    353  1.1   cliff 	error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi));
    354  1.1   cliff 
    355  1.1   cliff 	return error;
    356  1.1   cliff }
    357  1.1   cliff 
    358  1.1   cliff static int
    359  1.1   cliff cfi_0002_erase_block(device_t self, flash_off_t offset)
    360  1.1   cliff {
    361  1.1   cliff 	struct nor_softc * const sc = device_private(self);
    362  1.1   cliff 	KASSERT(sc != NULL);
    363  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    364  1.1   cliff 	struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
    365  1.1   cliff 	KASSERT(cfi != NULL);
    366  1.1   cliff 
    367  1.1   cliff 	CFI_0002_STATS_INC(cfi, erase_block);
    368  1.1   cliff 
    369  1.6     phx 	bus_size_t sa = offset << (3 - cfi->cfi_portwidth);
    370  1.1   cliff 
    371  1.1   cliff 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
    372  1.1   cliff 	if (error != 0)
    373  1.1   cliff 		return ETIMEDOUT;
    374  1.1   cliff 
    375  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
    376  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
    377  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */
    378  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
    379  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
    380  1.6     phx 	cfi_cmd(cfi, sa,                    0x30); /* erase sector */
    381  1.1   cliff 
    382  1.1   cliff 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi));
    383  1.1   cliff 
    384  1.1   cliff 	return error;
    385  1.1   cliff }
    386  1.1   cliff 
    387  1.1   cliff /*
    388  1.1   cliff  * cfi_0002_busy - nor_interface busy op
    389  1.1   cliff  */
    390  1.1   cliff static int
    391  1.1   cliff cfi_0002_busy(device_t self, flash_off_t offset, u_long usec)
    392  1.1   cliff {
    393  1.1   cliff 	struct nor_softc *sc = device_private(self);
    394  1.1   cliff 	KASSERT(sc != NULL);
    395  1.1   cliff 	KASSERT(sc->sc_nor_if != NULL);
    396  1.1   cliff 	struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
    397  1.1   cliff 
    398  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy);
    399  1.1   cliff 
    400  1.1   cliff 	return cfi_0002_busy_wait(cfi, offset, usec);
    401  1.1   cliff }
    402  1.1   cliff 
    403  1.1   cliff /*
    404  1.1   cliff  * cfi_0002_busy_wait - wait until device is not busy
    405  1.1   cliff  */
    406  1.1   cliff static int
    407  1.1   cliff cfi_0002_busy_wait(struct cfi * const cfi, flash_off_t offset, u_long usec)
    408  1.1   cliff {
    409  1.1   cliff 	int error;
    410  1.1   cliff 
    411  1.1   cliff #ifdef CFI_0002_STATS
    412  1.1   cliff 	struct timeval start;
    413  1.1   cliff 	struct timeval now;
    414  1.1   cliff 	struct timeval delta;
    415  1.1   cliff 
    416  1.1   cliff 	if (usec > cfi->cfi_0002_stats.busy_usec_max)
    417  1.1   cliff 		cfi->cfi_0002_stats.busy_usec_max = usec;
    418  1.1   cliff 	if (usec < cfi->cfi_0002_stats.busy_usec_min)
    419  1.1   cliff 		cfi->cfi_0002_stats.busy_usec_min = usec;
    420  1.1   cliff 	microtime(&start);
    421  1.1   cliff #endif
    422  1.1   cliff 	if (usec > cfi->cfi_yield_time) {
    423  1.1   cliff 		error = cfi_0002_busy_yield(cfi, offset, usec);
    424  1.1   cliff #ifdef CFI_0002_STATS
    425  1.1   cliff 		microtime(&now);
    426  1.1   cliff 		cfi->cfi_0002_stats.busy_yield++;
    427  1.1   cliff 		timersub(&now, &start, &delta);
    428  1.1   cliff 		timeradd(&delta,
    429  1.1   cliff 			&cfi->cfi_0002_stats.busy_yield_tv,
    430  1.1   cliff 			&cfi->cfi_0002_stats.busy_yield_tv);
    431  1.1   cliff #endif
    432  1.1   cliff 	} else {
    433  1.1   cliff 		error = cfi_0002_busy_poll(cfi, offset, usec);
    434  1.1   cliff #ifdef CFI_0002_STATS
    435  1.1   cliff 		microtime(&now);
    436  1.1   cliff 		cfi->cfi_0002_stats.busy_poll++;
    437  1.1   cliff 		timersub(&now, &start, &delta);
    438  1.1   cliff 		timeradd(&delta,
    439  1.1   cliff 			&cfi->cfi_0002_stats.busy_poll_tv,
    440  1.1   cliff 			&cfi->cfi_0002_stats.busy_poll_tv);
    441  1.1   cliff #endif
    442  1.1   cliff 	}
    443  1.1   cliff 	return error;
    444  1.1   cliff }
    445  1.1   cliff 
    446  1.1   cliff /*
    447  1.1   cliff  * cfi_0002_busy_poll - poll until device is not busy
    448  1.1   cliff  */
    449  1.1   cliff static int
    450  1.1   cliff cfi_0002_busy_poll(struct cfi * const cfi, flash_off_t offset, u_long usec)
    451  1.1   cliff {
    452  1.1   cliff 	u_long count = usec >> 3;
    453  1.1   cliff 	if (count == 0)
    454  1.1   cliff 		count = 1;	/* enforce minimum */
    455  1.1   cliff 	do {
    456  1.1   cliff 		if (! cfi->cfi_ops.cfi_busy(cfi, offset))
    457  1.1   cliff 			return 0;	/* not busy */
    458  1.1   cliff 		DELAY(8);
    459  1.1   cliff 	} while (count-- != 0);
    460  1.1   cliff 
    461  1.1   cliff 	return ETIMEDOUT;		/* busy */
    462  1.1   cliff }
    463  1.1   cliff 
    464  1.1   cliff /*
    465  1.1   cliff  * cfi_0002_busy_yield - yield until device is not busy
    466  1.1   cliff  */
    467  1.1   cliff static int
    468  1.1   cliff cfi_0002_busy_yield(struct cfi * const cfi, flash_off_t offset, u_long usec)
    469  1.1   cliff {
    470  1.1   cliff 	struct timeval start;
    471  1.1   cliff 	struct timeval delta;
    472  1.1   cliff 	struct timeval limit;
    473  1.1   cliff 	struct timeval now;
    474  1.1   cliff 
    475  1.1   cliff 	microtime(&start);
    476  1.1   cliff 
    477  1.1   cliff 	/* try optimism */
    478  1.1   cliff 	if (! cfi->cfi_ops.cfi_busy(cfi, offset)) {
    479  1.1   cliff 		CFI_0002_STATS_INC(cfi, busy_yield_hit);
    480  1.1   cliff 		return 0;		/* not busy */
    481  1.1   cliff 	}
    482  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy_yield_miss);
    483  1.1   cliff 
    484  1.1   cliff 	delta.tv_sec = usec / 1000000;
    485  1.1   cliff 	delta.tv_usec = usec % 1000000;
    486  1.1   cliff 	timeradd(&start, &delta, &limit);
    487  1.1   cliff 	do {
    488  1.1   cliff 		yield();
    489  1.1   cliff 		microtime(&now);
    490  1.1   cliff 		if (! cfi->cfi_ops.cfi_busy(cfi, offset))
    491  1.1   cliff 			return 0;	/* not busy */
    492  1.1   cliff 	} while (timercmp(&now, &limit, <));
    493  1.1   cliff 
    494  1.1   cliff 	CFI_0002_STATS_INC(cfi, busy_yield_timo);
    495  1.1   cliff 
    496  1.1   cliff 	return ETIMEDOUT;		/* busy */
    497  1.1   cliff }
    498  1.1   cliff 
    499  1.1   cliff /*
    500  1.1   cliff  * cfi_0002_busy_dq7 - DQ7 "toggle" method to check busy
    501  1.1   cliff  *
    502  1.1   cliff  * Check busy during/after erase, program, protect operation.
    503  1.1   cliff  *
    504  1.1   cliff  * NOTE:
    505  1.1   cliff  *	Chip manufacturers (Spansion) plan to deprecate this method.
    506  1.1   cliff  */
    507  1.1   cliff static int
    508  1.1   cliff cfi_0002_busy_dq7(struct cfi * const cfi, flash_off_t offset)
    509  1.1   cliff {
    510  1.1   cliff 	bus_space_tag_t bst = cfi->cfi_bst;
    511  1.1   cliff 	bus_space_handle_t bsh = cfi->cfi_bsh;
    512  1.1   cliff 	bool busy;
    513  1.1   cliff 
    514  1.1   cliff 	switch(cfi->cfi_portwidth) {
    515  1.1   cliff 	case 0: {
    516  1.1   cliff 		uint8_t r0 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
    517  1.1   cliff 		uint8_t r1 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
    518  1.1   cliff 		busy = (r0 != r1);
    519  1.1   cliff 		break;
    520  1.1   cliff 	}
    521  1.1   cliff 	case 1: {
    522  1.1   cliff 		uint16_t r0 = bus_space_read_2(bst, bsh, 0);
    523  1.1   cliff 		uint16_t r1 = bus_space_read_2(bst, bsh, 0);
    524  1.1   cliff 		busy = (r0 != r1);
    525  1.1   cliff 		break;
    526  1.1   cliff 	}
    527  1.1   cliff 	case 2: {
    528  1.1   cliff 		uint32_t r0 = bus_space_read_4(bst, bsh, 0);
    529  1.1   cliff 		uint32_t r1 = bus_space_read_4(bst, bsh, 0);
    530  1.1   cliff 		busy = (r0 != r1);
    531  1.1   cliff 		break;
    532  1.1   cliff 	}
    533  1.1   cliff 	default:
    534  1.1   cliff 		busy = true;	/* appeas gcc */
    535  1.1   cliff 		panic("%s: bad port width %d\n",
    536  1.1   cliff 			__func__, cfi->cfi_portwidth);
    537  1.1   cliff 	}
    538  1.1   cliff 	return busy;
    539  1.1   cliff }
    540  1.1   cliff 
    541  1.1   cliff #ifdef NOTYET
    542  1.1   cliff /*
    543  1.1   cliff  * cfi_0002_busy_reg - read and evaluate Read Status Register
    544  1.1   cliff  *
    545  1.1   cliff  * NOTE:
    546  1.1   cliff  *	Read Status Register not present on all chips
    547  1.1   cliff  *	use "toggle" method when Read Status Register not available.
    548  1.1   cliff  */
    549  1.1   cliff static bool
    550  1.1   cliff cfi_0002_busy_reg(struct cfi * const cfi, flash_off_t offset)
    551  1.1   cliff {
    552  1.1   cliff 	bus_space_tag_t bst = cfi->cfi_bst;
    553  1.1   cliff 	bus_space_handle_t bsh = cfi->cfi_bsh;
    554  1.1   cliff 	uint32_t r;
    555  1.1   cliff 
    556  1.6     phx 	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x70); /* Status Register Read  */
    557  1.1   cliff 
    558  1.1   cliff 	switch(cfi->cfi_portwidth) {
    559  1.1   cliff 	case 0:
    560  1.1   cliff 		r = bus_space_read_1(bst, bsh, 0);
    561  1.1   cliff 		break;
    562  1.1   cliff 	case 1:
    563  1.1   cliff 		r = bus_space_read_2(bst, bsh, 0);
    564  1.1   cliff 		break;
    565  1.1   cliff 	case 2:
    566  1.1   cliff 		r = bus_space_read_4(bst, bsh, 0);
    567  1.1   cliff 		break;
    568  1.1   cliff 	default:
    569  1.1   cliff 		panic("%s: bad port width %d\n",
    570  1.1   cliff 			__func__, cfi->cfi_portwidth);
    571  1.1   cliff 	}
    572  1.1   cliff 
    573  1.1   cliff 	return ((r & __BIT(7)) == 0):
    574  1.1   cliff }
    575  1.1   cliff #endif	/* NOTYET */
    576  1.1   cliff 
    577  1.1   cliff #ifdef CFI_0002_STATS
    578  1.1   cliff void
    579  1.1   cliff cfi_0002_stats_reset(struct cfi *cfi)
    580  1.1   cliff {
    581  1.1   cliff 	memset(&cfi->cfi_0002_stats, 0, sizeof(struct cfi_0002_stats));
    582  1.1   cliff         cfi->cfi_0002_stats.busy_usec_min = ~0;
    583  1.1   cliff }
    584  1.1   cliff 
    585  1.1   cliff void
    586  1.1   cliff cfi_0002_stats_print(struct cfi *cfi)
    587  1.1   cliff {
    588  1.1   cliff 	printf("read_page %lu\n", cfi->cfi_0002_stats.read_page);
    589  1.1   cliff 	printf("program_page %lu\n", cfi->cfi_0002_stats.program_page);
    590  1.1   cliff 	printf("erase_all %lu\n", cfi->cfi_0002_stats.erase_all);
    591  1.1   cliff 	printf("erase_block %lu\n", cfi->cfi_0002_stats.erase_block);
    592  1.1   cliff 	printf("busy %lu\n", cfi->cfi_0002_stats.busy);
    593  1.1   cliff 
    594  1.1   cliff 	printf("write_nbyte_time_typ %d\n",
    595  1.1   cliff 		 cfi->cfi_qry_data.write_nbyte_time_typ);
    596  1.1   cliff 	printf("write_nbyte_time_max %d\n",
    597  1.1   cliff 		 cfi->cfi_qry_data.write_nbyte_time_max);
    598  1.1   cliff 
    599  1.1   cliff 	printf("erase_blk_time_typ %d\n",
    600  1.1   cliff 		 cfi->cfi_qry_data.erase_blk_time_typ);
    601  1.1   cliff 	printf("erase_blk_time_max %d\n",
    602  1.1   cliff 		 cfi->cfi_qry_data.erase_blk_time_max);
    603  1.1   cliff 
    604  1.4   cliff 	printf("erase_chip_time_typ %d\n",
    605  1.4   cliff 		 cfi->cfi_qry_data.erase_chip_time_typ);
    606  1.4   cliff 	printf("erase_chip_time_max %d\n",
    607  1.4   cliff 		 cfi->cfi_qry_data.erase_chip_time_max);
    608  1.1   cliff 
    609  1.1   cliff 	printf("time_write_nbyte %lu\n", cfi_0002_time_write_nbyte(cfi));
    610  1.1   cliff 	printf("time_erase_blk %lu\n", cfi_0002_time_erase_blk(cfi));
    611  1.1   cliff 	printf("time_erase_all %lu\n", cfi_0002_time_erase_all(cfi));
    612  1.1   cliff 
    613  1.1   cliff 	printf("busy_usec_min %lu\n", cfi->cfi_0002_stats.busy_usec_min);
    614  1.1   cliff 	printf("busy_usec_max %lu\n", cfi->cfi_0002_stats.busy_usec_max);
    615  1.1   cliff 
    616  1.1   cliff 	printf("busy_poll_tv %lld.%d\n",
    617  1.1   cliff 		cfi->cfi_0002_stats.busy_poll_tv.tv_sec,
    618  1.1   cliff 		cfi->cfi_0002_stats.busy_poll_tv.tv_usec);
    619  1.1   cliff 	printf("busy_yield_tv %lld.%d\n",
    620  1.1   cliff 		cfi->cfi_0002_stats.busy_yield_tv.tv_sec,
    621  1.1   cliff 		cfi->cfi_0002_stats.busy_yield_tv.tv_usec);
    622  1.1   cliff 	printf("busy_poll %lu\n", cfi->cfi_0002_stats.busy_poll);
    623  1.1   cliff 	printf("busy_yield %lu\n", cfi->cfi_0002_stats.busy_yield);
    624  1.1   cliff 	printf("busy_yield_hit %lu\n", cfi->cfi_0002_stats.busy_yield_hit);
    625  1.1   cliff 	printf("busy_yield_miss %lu\n", cfi->cfi_0002_stats.busy_yield_miss);
    626  1.1   cliff 	printf("busy_yield_timo %lu\n", cfi->cfi_0002_stats.busy_yield_timo);
    627  1.1   cliff }
    628  1.1   cliff #endif	/* CFI_0002_STATS */
    629