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