cfi.h revision 1.3
1/*	$NetBSD: cfi.h,v 1.3 2011/07/17 00:52:42 dyoung Exp $	*/
2
3#ifndef _CFI_H_
4#define _CFI_H_
5
6#include <dev/nor/cfi_0002.h>
7#include <sys/bus.h>
8
9/*
10 * minimum size to bus_space_map for probe/identify QRY:
11 * larget offset needed is CFI_QUERY_MODE_ALT_ADDRESS
12 * scaled by maximum attempted port width, so
13 *	min >= (0x555 * sizeof(uint32_t))
14 */
15#define CFI_QRY_MIN_MAP_SIZE	0x2000
16
17
18typedef enum {
19	CFI_STATE_DATA_ARRAY = 0,
20	CFI_STATE_QUERY,
21	/* TBD */
22} cfi_state_t;
23
24
25/*
26 * CFI Query structure
27 */
28struct cfi_query_data {
29    /* Query info */
30    uint8_t	qry[3];			/* { 'Q', 'R', 'Y' } */
31    uint16_t	id_pri;			/* primary comand set ID */
32    uint16_t	addr_pri;		/* primary table addr */
33    uint16_t	id_alt;			/* alternate command set ID */
34    uint16_t	addr_alt;		/* alternate table addr */
35    /* System Interface info */
36    uint8_t	vcc_min;		/* min Vcc */
37    uint8_t	vcc_max;		/* max Vcc */
38    uint8_t	vpp_min;		/* min Vpp */
39    uint8_t	vpp_max;		/* max Vpp */
40    uint8_t	write_word_time_typ;	/* typ 1-word timeout, 1<<N usec */
41    uint8_t	write_nbyte_time_typ;	/* typ multi-byte timeout, 1<<N usec */
42    uint8_t	erase_blk_time_typ;	/* typ 1-blk erase timeout, 1<<N msec */
43    uint8_t	erase_chiptime_typ;	/* typ chip erase timeout, 1<<N msec */
44    uint8_t	write_word_time_max;	/* max 1-word timeout, typ<<N */
45    uint8_t	write_nbyte_time_max;	/* max multi-byte timeout, typ<<N */
46    uint8_t	erase_blk_time_max;	/* max 1-blk erase timeout, typ<<N */
47    uint8_t	erase_chiptime_max;	/* max chip erase timeout, typ<<N */
48    /* Device Geometry Definition */
49    uint8_t	device_size;		/* 1<<N bytes */
50    uint16_t	interface_code_desc;	/* JEP137 interface code description */
51    uint16_t	write_nbyte_size_max;	/* max size of multi-byte write, 1<<N */
52    uint8_t	erase_blk_regions;	/* number of erase block regions */
53    struct {
54	uint16_t z;			/* Erase Blocks are z * 256 bytes */
55	uint16_t y;			/* y+1 = #Erase Blocks in region */
56    } erase_blk_info[4];
57    /* Vendor-specific Primary command set info */
58    union {
59	struct cmdset_0002_query_data cmd_0002;
60    } pri;
61#ifdef NOTYET
62    /* Vendor-specific Alternate command set info */
63    union {
64	/* some command set structure here */
65    } pri;
66#endif
67};
68
69/*
70 * decode interface_code_desc
71 */
72static inline const char *
73cfi_interface_desc_str(uint16_t icd)
74{
75	switch(icd) {
76	case 0:
77		return "x8";
78	case 1:
79		return "x16";
80	case 2:
81		return "x8/x16";
82	default:
83		return "";
84	}
85}
86
87/*
88 * id_pri: CFI Command set and control assignments
89 */
90#define CFI_ID_PRI_NONE		0x0000
91#define CFI_ID_PRI_INTEL_EXT	0x0001
92#define CFI_ID_PRI_AMD_STD	0x0002
93#define CFI_ID_PRI_INTEL_STD	0x0003
94#define CFI_ID_PRI_AMD_EXT	0x0004
95#define CFI_ID_PRI_WINBOND	0x0005
96#define CFI_ID_PRI_ST_ADV	0x0020
97#define CFI_ID_PRI_MITSU_ADV	0x0100
98#define CFI_ID_PRI_MITSU_EXT	0x0101
99#define CFI_ID_PRI_SST_PAGE	0x0102
100#define CFI_ID_PRI_SST_OLD	0x0701
101#define CFI_ID_PRI_INTEL_PERF	0x0200
102#define CFI_ID_PRI_INTEL_DATA	0x0210
103#define CFI_ID_PRI_RESV		0xffff	/* not allowed, reserved */
104
105/*
106 * JEDEC ID (autoselect) data
107 */
108struct cfi_jedec_id_data {
109	uint16_t	id_mid;		/* manufacturer ID */
110	uint16_t	id_did[3];	/* device ID */
111	uint16_t	id_prot_state;
112	uint16_t	id_indicators;
113	uint8_t		id_swb_lo;	/* lower software bits */
114	uint8_t		id_swb_hi;	/* upper software bits */
115};
116
117/*
118 * table entry used to determine operating mode by QRY signature
119 */
120struct cfi_opmodes {
121	uint8_t		portwidth;	/* (1<<N) bytes */
122	uint8_t		chipwidth;	/* (1<<N) bytes */
123	uint8_t		interleave;	/* (1<<N) bytes */
124	uint8_t		qsa;		/* Query Start Address (in bytes) */
125	uint8_t		len;		/* signature length */
126	const uint8_t  *sig;		/* signature */
127	const char     *str;		/* descriptive string */
128};
129
130struct cfi;	/* fwd ref */
131
132struct cfi_ops {
133	void	(*cfi_reset)(struct cfi *);
134	int 	(*cfi_busy)(struct cfi *, flash_off_t);
135	int	(*cfi_program_word)(struct cfi *, flash_off_t);
136	int	(*cfi_erase_sector)(struct cfi *, flash_off_t);
137};
138
139/* NOTE:
140 * CFI_0002_STATS are just meant temporarily for debugging
141 * not for long-term use. Some event counters at the flash and nor
142 * layers might be helpful eventually
143 */
144#define CFI_0002_STATS	/* XXX TMP */
145#ifdef CFI_0002_STATS
146struct cfi_0002_stats {
147	u_long read_page;
148	u_long program_page;
149	u_long erase_all;
150	u_long erase_block;
151	u_long busy;
152	u_long busy_usec_min;
153	u_long busy_usec_max;
154	struct timeval busy_poll_tv;
155	struct timeval busy_yield_tv;
156	u_long busy_poll;
157	u_long busy_yield;
158	u_long busy_yield_hit;
159	u_long busy_yield_miss;
160	u_long busy_yield_timo;
161};
162
163extern void cfi_0002_stats_reset(struct cfi *);
164extern void cfi_0002_stats_print(struct cfi *);
165#define CFI_0002_STATS_INIT(dev, cfi)			\
166    do {						\
167	aprint_normal_dev(dev, "cfi=%p\n", cfi);	\
168	cfi_0002_stats_reset(cfi);			\
169    } while (0)
170#define CFI_0002_STATS_INC(cfi, field)	(cfi)->cfi_0002_stats.field++
171
172#else
173
174#define CFI_0002_STATS_INIT(cfi)
175#define CFI_0002_STATS_INC(cfi, field)
176
177#endif	/* CFI_0002_STATS */
178
179struct cfi {
180	bus_space_tag_t		cfi_bst;
181	bus_space_handle_t	cfi_bsh;
182	cfi_state_t		cfi_state;
183	uint8_t			cfi_portwidth;	/* port width, 1<<N bytes */
184	uint8_t			cfi_chipwidth;	/* chip width, 1<<N bytes */
185	struct cfi_query_data	cfi_qry_data;	/* CFI Query data */
186	struct cfi_jedec_id_data
187				cfi_id_data;	/* JEDEC ID data */
188	const struct cfi_opmodes
189			       *cfi_opmode;
190	struct cfi_ops		cfi_ops;	/* chip dependent functions */
191	u_long			cfi_yield_time;	/* thresh. for yield in wait */
192#ifdef CFI_0002_STATS
193	struct cfi_0002_stats	cfi_0002_stats;
194#endif
195};
196
197
198enum {
199	CFI_ADDRESS_ANY = 0x00,		    /* XXX "don't care" */
200
201	CFI_RESET_DATA = 0xf0,
202	CFI_ALT_RESET_DATA = 0xff,
203
204	CFI_QUERY_MODE_ADDRESS = 0x55,	    /* some devices accept anything */
205	CFI_QUERY_MODE_ALT_ADDRESS = 0x555,
206	CFI_QUERY_DATA = 0x98,
207};
208
209static inline void
210cfi_reset(struct cfi * const cfi)
211{
212	KASSERT(cfi->cfi_ops.cfi_reset != NULL);
213	cfi->cfi_ops.cfi_reset(cfi);
214}
215
216static inline int
217cfi_erase_sector(struct cfi * const cfi, flash_off_t offset)
218{
219	KASSERT(cfi->cfi_ops.cfi_erase_sector != NULL);
220	return cfi->cfi_ops.cfi_erase_sector(cfi, offset);
221}
222
223static inline int
224cfi_program_word(struct cfi * const cfi, flash_off_t offset)
225{
226	KASSERT(cfi->cfi_ops.cfi_program_word != NULL);
227	return cfi->cfi_ops.cfi_program_word(cfi, offset);
228}
229
230extern const struct nor_interface nor_interface_cfi;
231
232extern bool cfi_probe(struct cfi * const);
233extern bool cfi_identify(struct cfi * const);
234extern void cfi_print(device_t, struct cfi * const);
235extern void cfi_reset_default(struct cfi * const);
236extern void cfi_reset_std(struct cfi * const);
237extern void cfi_reset_alt(struct cfi * const);
238extern void cfi_cmd(struct cfi * const, bus_size_t, uint32_t);
239
240#endif	/* _CFI_H_ */
241