cfi.c revision 1.9
1/*	$NetBSD: cfi.c,v 1.9 2019/02/06 04:20:40 mrg Exp $	*/
2/*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Cliff Neighbors.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "opt_flash.h"
32#include "opt_nor.h"
33#include "opt_cfi.h"
34
35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.9 2019/02/06 04:20:40 mrg Exp $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/cdefs.h>
41#include <sys/device.h>
42#include <sys/endian.h>
43
44#include <sys/bus.h>
45
46#include <dev/nor/nor.h>
47#include <dev/nor/cfi.h>
48#include <dev/nor/cfi_0002.h>
49
50
51static int  cfi_scan_media(device_t self, struct nor_chip *chip);
52static void cfi_init(device_t);
53static void cfi_select(device_t, bool);
54static void cfi_read_1(device_t, flash_off_t, uint8_t *);
55static void cfi_read_2(device_t, flash_off_t, uint16_t *);
56static void cfi_read_4(device_t, flash_off_t, uint32_t *);
57static void cfi_read_buf_1(device_t, flash_off_t, uint8_t *, size_t);
58static void cfi_read_buf_2(device_t, flash_off_t, uint16_t *, size_t);
59static void cfi_read_buf_4(device_t, flash_off_t, uint32_t *, size_t);
60static void cfi_write_1(device_t, flash_off_t, uint8_t);
61static void cfi_write_2(device_t, flash_off_t, uint16_t);
62static void cfi_write_4(device_t, flash_off_t, uint32_t);
63static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
64static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
65static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
66static uint8_t cfi_read_qry(struct cfi * const, bus_size_t);
67static bool cfi_jedec_id(struct cfi * const);
68static bool cfi_emulate(struct cfi * const);
69static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *);
70static void cfi_jedec_fill(struct cfi * const,
71	const struct cfi_jedec_tab *);
72#if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
73static void cfi_hexdump(flash_off_t, void * const, u_int, u_int);
74#endif
75
76#define LOG2_64K	16
77#define LOG2_128K	17
78#define LOG2_256K	18
79#define LOG2_512K	19
80#define LOG2_1M		20
81#define LOG2_2M		21
82#define LOG2_4M		22
83#define LOG2_8M		23
84#define LOG2_16M	24
85#define LOG2_32M	25
86#define LOG2_64M	26
87#define LOG2_128M	27
88#define LOG2_256M	28
89#define LOG2_512M	29
90#define LOG2_1G		30
91#define LOG2_2G		31
92const struct cfi_jedec_tab cfi_jedec_tab[] = {
93	{
94		.jt_name = "Pm39LV512",
95		.jt_mid = 0x9d,
96		.jt_did = 0x1b,
97		.jt_id_pri = 0,				/* XXX */
98		.jt_id_alt = 0,				/* XXX */
99		.jt_device_size = LOG2_64K,
100		.jt_interface_code_desc = CFI_IFCODE_X8,
101		.jt_erase_blk_regions = 1,
102		.jt_erase_blk_info = {
103			{ 4096/256, (64/4)-1 },
104		},
105		.jt_write_word_time_typ = 40,
106		.jt_write_nbyte_time_typ = 0,
107		.jt_erase_blk_time_typ = 55,
108		.jt_erase_chip_time_typ = 55,
109		.jt_write_word_time_max = 1,
110		.jt_write_nbyte_time_max = 0,
111		.jt_erase_blk_time_max = 1,
112		.jt_erase_chip_time_max = 1,
113	},
114	{
115		.jt_name = "Pm39LV010",
116		.jt_mid = 0x9d,
117		.jt_did = 0x1c,
118		.jt_id_pri = 0,				/* XXX */
119		.jt_id_alt = 0,				/* XXX */
120		.jt_device_size = LOG2_128K,
121		.jt_interface_code_desc = CFI_IFCODE_X8,
122		.jt_erase_blk_regions = 1,
123		.jt_erase_blk_info = {
124			{ 4096/256, (128/4)-1 },
125		},
126		.jt_write_word_time_typ = 40,
127		.jt_write_nbyte_time_typ = 0,
128		.jt_erase_blk_time_typ = 55,
129		.jt_erase_chip_time_typ = 55,
130		.jt_write_word_time_max = 1,
131		.jt_write_nbyte_time_max = 0,
132		.jt_erase_blk_time_max = 1,
133		.jt_erase_chip_time_max = 1,
134	},
135};
136
137
138const struct nor_interface nor_interface_cfi = {
139	.scan_media = cfi_scan_media,
140	.init = cfi_init,
141	.select = cfi_select,
142	.read_1 = cfi_read_1,
143	.read_2 = cfi_read_2,
144	.read_4 = cfi_read_4,
145	.read_buf_1 = cfi_read_buf_1,
146	.read_buf_2 = cfi_read_buf_2,
147	.read_buf_4 = cfi_read_buf_4,
148	.write_1 = cfi_write_1,
149	.write_2 = cfi_write_2,
150	.write_4 = cfi_write_4,
151	.write_buf_1 = cfi_write_buf_1,
152	.write_buf_2 = cfi_write_buf_2,
153	.write_buf_4 = cfi_write_buf_4,
154	.read_page = NULL,			/* cmdset */
155	.program_page = NULL,			/* cmdset */
156	.busy = NULL,
157	.private = NULL,
158	.access_width = -1,
159	.part_info = NULL,
160	.part_num = -1,
161};
162
163
164/* only data[7..0] are used regardless of chip width */
165#define cfi_unpack_1(n)			((n) & 0xff)
166
167/* construct uint16_t */
168#define cfi_unpack_2(b0, b1)						\
169	((cfi_unpack_1(b1) << 8) | cfi_unpack_1(b0))
170
171/* construct uint32_t */
172#define cfi_unpack_4(b0, b1, b2, b3)					\
173	((cfi_unpack_1(b3) << 24) |					\
174	 (cfi_unpack_1(b2) << 16) |					\
175	 (cfi_unpack_1(b1) <<  8) |					\
176	 (cfi_unpack_1(b0)))
177
178#define cfi_unpack_qry(qryp, data)					\
179    do {								\
180	(qryp)->qry[0] = cfi_unpack_1(data[0x10]);			\
181	(qryp)->qry[1] = cfi_unpack_1(data[0x11]);			\
182	(qryp)->qry[2] = cfi_unpack_1(data[0x12]);			\
183	(qryp)->id_pri = cfi_unpack_2(data[0x13], data[0x14]);		\
184	(qryp)->addr_pri = cfi_unpack_2(data[0x15], data[0x16]);	\
185	(qryp)->id_alt = cfi_unpack_2(data[0x17], data[0x18]);		\
186	(qryp)->addr_alt = cfi_unpack_2(data[0x19], data[0x1a]);	\
187	(qryp)->vcc_min = cfi_unpack_1(data[0x1b]);			\
188	(qryp)->vcc_max = cfi_unpack_1(data[0x1c]);			\
189	(qryp)->vpp_min = cfi_unpack_1(data[0x1d]);			\
190	(qryp)->vpp_max = cfi_unpack_1(data[0x1e]);			\
191	(qryp)->write_word_time_typ = cfi_unpack_1(data[0x1f]);		\
192	(qryp)->write_nbyte_time_typ = cfi_unpack_1(data[0x20]);	\
193	(qryp)->erase_blk_time_typ = cfi_unpack_1(data[0x21]);		\
194	(qryp)->erase_chip_time_typ = cfi_unpack_1(data[0x22]);		\
195	(qryp)->write_word_time_max = cfi_unpack_1(data[0x23]);		\
196	(qryp)->write_nbyte_time_max = cfi_unpack_1(data[0x24]);	\
197	(qryp)->erase_blk_time_max = cfi_unpack_1(data[0x25]);		\
198	(qryp)->erase_chip_time_max = cfi_unpack_1(data[0x26]);		\
199	(qryp)->device_size = cfi_unpack_1(data[0x27]);			\
200	(qryp)->interface_code_desc =					\
201		cfi_unpack_2(data[0x28], data[0x29]);			\
202	(qryp)->write_nbyte_size_max = 					\
203		cfi_unpack_2(data[0x2a], data[0x2b]);			\
204	(qryp)->erase_blk_regions = cfi_unpack_1(data[0x2c]);		\
205	u_int _i = 0x2d;						\
206	const u_int _n = (qryp)->erase_blk_regions;			\
207	KASSERT(_n <= 4);						\
208	for (u_int _r = 0; _r < _n; _r++, _i+=4) {			\
209		(qryp)->erase_blk_info[_r].y =				\
210			cfi_unpack_2(data[_i+0], data[_i+1]);		\
211		(qryp)->erase_blk_info[_r].z =				\
212			cfi_unpack_2(data[_i+2], data[_i+3]);		\
213	}								\
214    } while (0)
215
216#define cfi_unpack_pri_0002(qryp, data)					\
217    do {								\
218	(qryp)->pri.cmd_0002.pri[0] = cfi_unpack_1(data[0x00]);		\
219	(qryp)->pri.cmd_0002.pri[1] = cfi_unpack_1(data[0x01]);		\
220	(qryp)->pri.cmd_0002.pri[2] = cfi_unpack_1(data[0x02]);		\
221	(qryp)->pri.cmd_0002.version_maj = cfi_unpack_1(data[0x03]);	\
222	(qryp)->pri.cmd_0002.version_min = cfi_unpack_1(data[0x04]);	\
223	(qryp)->pri.cmd_0002.asupt = cfi_unpack_1(data[0x05]);		\
224	(qryp)->pri.cmd_0002.erase_susp = cfi_unpack_1(data[0x06]);	\
225	(qryp)->pri.cmd_0002.sector_prot = cfi_unpack_1(data[0x07]);	\
226	(qryp)->pri.cmd_0002.tmp_sector_unprot =			\
227		cfi_unpack_1(data[0x08]);				\
228	(qryp)->pri.cmd_0002.sector_prot_scheme =			\
229		cfi_unpack_1(data[0x09]);				\
230	(qryp)->pri.cmd_0002.simul_op = cfi_unpack_1(data[0x0a]);	\
231	(qryp)->pri.cmd_0002.burst_mode_type = cfi_unpack_1(data[0x0b]);\
232	(qryp)->pri.cmd_0002.page_mode_type = cfi_unpack_1(data[0x0c]);	\
233	(qryp)->pri.cmd_0002.acc_min = cfi_unpack_1(data[0x0d]);	\
234	(qryp)->pri.cmd_0002.acc_max = cfi_unpack_1(data[0x0e]);	\
235	(qryp)->pri.cmd_0002.wp_prot = cfi_unpack_1(data[0x0f]);	\
236	/* XXX 1.3 stops here */					\
237	(qryp)->pri.cmd_0002.prog_susp = cfi_unpack_1(data[0x10]);	\
238	(qryp)->pri.cmd_0002.unlock_bypass = cfi_unpack_1(data[0x11]);	\
239	(qryp)->pri.cmd_0002.sss_size = cfi_unpack_1(data[0x12]);	\
240	(qryp)->pri.cmd_0002.soft_feat = cfi_unpack_1(data[0x13]);	\
241	(qryp)->pri.cmd_0002.page_size = cfi_unpack_1(data[0x14]);	\
242	(qryp)->pri.cmd_0002.erase_susp_time_max =			\
243		cfi_unpack_1(data[0x15]);				\
244	(qryp)->pri.cmd_0002.prog_susp_time_max =			\
245		cfi_unpack_1(data[0x16]);				\
246	(qryp)->pri.cmd_0002.embhwrst_time_max =			\
247		cfi_unpack_1(data[0x38]);				\
248	(qryp)->pri.cmd_0002.hwrst_time_max =				\
249		cfi_unpack_1(data[0x39]);				\
250    } while (0)
251
252#define CFI_QRY_UNPACK_COMMON(cfi, data, type)				\
253    do {								\
254	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;	\
255									\
256	memset(qryp, 0, sizeof(*qryp));					\
257	cfi_unpack_qry(qryp, data);					\
258									\
259	switch (qryp->id_pri) {						\
260	case 0x0002:							\
261		if ((cfi_unpack_1(data[qryp->addr_pri + 0]) == 'P') &&	\
262		    (cfi_unpack_1(data[qryp->addr_pri + 1]) == 'R') &&	\
263		    (cfi_unpack_1(data[qryp->addr_pri + 2]) == 'I')) {	\
264			type *pri_data = &data[qryp->addr_pri];		\
265			cfi_unpack_pri_0002(qryp, pri_data);		\
266			break;						\
267		}							\
268	}								\
269    } while (0)
270
271#ifdef CFI_DEBUG_QRY
272# define CFI_DUMP_QRY(off, p, sz, stride)				\
273    do {								\
274	printf("%s: QRY data\n", __func__);				\
275	cfi_hexdump(off, p, sz, stride);				\
276    } while (0)
277#else
278# define CFI_DUMP_QRY(off, p, sz, stride)
279#endif
280
281#ifdef CFI_DEBUG_JEDEC
282# define CFI_DUMP_JEDEC(off, p, sz, stride)				\
283    do {								\
284	printf("%s: JEDEC data\n", __func__);				\
285	cfi_hexdump(off, p, sz, stride);				\
286    } while (0)
287#else
288# define CFI_DUMP_JEDEC(off, p, sz, stride)
289#endif
290
291
292static void
293cfi_chip_query_1(struct cfi * const cfi)
294{
295	uint8_t data[0x80];
296
297	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
298	    __arraycount(data));
299	CFI_DUMP_QRY(0, data, sizeof(data), 1);
300	CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t);
301}
302
303static void
304cfi_chip_query_2(struct cfi * const cfi)
305{
306	uint16_t data[0x80];
307
308	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
309	    __arraycount(data));
310	CFI_DUMP_QRY(0, data, sizeof(data), 2);
311	CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t);
312}
313
314static void
315cfi_chip_query_4(struct cfi * const cfi)
316{
317	uint32_t data[0x80];
318
319	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
320	    __arraycount(data));
321	CFI_DUMP_QRY(0, data, sizeof(data), 4);
322	CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t);
323}
324
325static void
326cfi_chip_query_8(struct cfi * const cfi)
327{
328#ifdef NOTYET
329	uint64_t data[0x80];
330
331	bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
332	    __arraycount(data));
333	CFI_DUMP_QRY(0, data, sizeof(data), 8);
334	CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t);
335#endif
336}
337
338/*
339 * cfi_chip_query - detect a CFI chip
340 *
341 * fill in the struct cfi as we discover what's there
342 */
343static bool
344cfi_chip_query(struct cfi * const cfi)
345{
346	const bus_size_t cfi_query_offset[] = {
347		CFI_QUERY_MODE_ADDR,
348		CFI_QUERY_MODE_ALT_ADDR
349	};
350
351	KASSERT(cfi != NULL);
352	KASSERT(cfi->cfi_bst != NULL);
353
354	for (int j=0; j < __arraycount(cfi_query_offset); j++) {
355
356		cfi_reset_default(cfi);
357		cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA);
358
359		if (cfi_read_qry(cfi, 0x10) == 'Q' &&
360		    cfi_read_qry(cfi, 0x11) == 'R' &&
361		    cfi_read_qry(cfi, 0x12) == 'Y') {
362			switch(cfi->cfi_portwidth) {
363			case 0:
364				cfi_chip_query_1(cfi);
365				break;
366			case 1:
367				cfi_chip_query_2(cfi);
368				break;
369			case 2:
370				cfi_chip_query_4(cfi);
371				break;
372			case 3:
373				cfi_chip_query_8(cfi);
374				break;
375			default:
376				panic("%s: bad portwidth %d\n",
377				    __func__, cfi->cfi_portwidth);
378			}
379
380			switch (cfi->cfi_qry_data.id_pri) {
381			case 0x0002:
382				cfi->cfi_unlock_addr1 = CFI_AMD_UNLOCK_ADDR1;
383				cfi->cfi_unlock_addr2 = CFI_AMD_UNLOCK_ADDR2;
384				break;
385			default:
386				DPRINTF(("%s: unsupported CFI cmdset %#04x\n",
387				    __func__, cfi->cfi_qry_data.id_pri));
388				return false;
389			}
390
391			cfi->cfi_emulated = false;
392			return true;
393		}
394	}
395
396	return false;
397}
398
399/*
400 * cfi_probe - search for a CFI NOR trying various port & chip widths
401 *
402 * - gather CFI QRY and PRI data
403 * - gather JEDEC ID data
404 * - if cfi_chip_query() fails, emulate CFI using table data if possible,
405 *   otherwise fail.
406 *
407 * NOTE:
408 *   striped NOR chips design not supported yet
409 */
410bool
411cfi_probe(struct cfi * const cfi)
412{
413	bool found;
414
415	KASSERT(cfi != NULL);
416
417	/* XXX set default unlock address for cfi_jedec_id() */
418	cfi->cfi_unlock_addr1 = CFI_AMD_UNLOCK_ADDR1;
419	cfi->cfi_unlock_addr2 = CFI_AMD_UNLOCK_ADDR2;
420
421	for (u_int pw = 0; pw < 3; pw++) {
422		for (u_int cw = 0; cw <= pw; cw++) {
423			cfi->cfi_portwidth = pw;
424			cfi->cfi_chipwidth = cw;
425			found = cfi_chip_query(cfi);
426			cfi_jedec_id(cfi);
427			if (! found)
428				found = cfi_emulate(cfi);
429			if (found)
430				goto exit_qry;
431		}
432	}
433
434    exit_qry:
435	cfi_reset_default(cfi);		/* exit QRY mode */
436	return found;
437}
438
439bool
440cfi_identify(struct cfi * const cfi)
441{
442	const bus_space_tag_t bst = cfi->cfi_bst;
443	const bus_space_handle_t bsh = cfi->cfi_bsh;
444
445	KASSERT(cfi != NULL);
446	KASSERT(bst != NULL);
447
448	memset(cfi, 0, sizeof(struct cfi));	/* XXX clean slate */
449	cfi->cfi_bst = bst;		/* restore bus space */
450	cfi->cfi_bsh = bsh;		/*  "       "   "    */
451
452	return cfi_probe(cfi);
453}
454
455static int
456cfi_scan_media(device_t self, struct nor_chip *chip)
457{
458	struct nor_softc *sc = device_private(self);
459	KASSERT(sc != NULL);
460	KASSERT(sc->sc_nor_if != NULL);
461	struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
462	KASSERT(cfi != NULL);
463
464	sc->sc_nor_if->access_width = cfi->cfi_portwidth;
465
466	chip->nc_manf_id = cfi->cfi_id_data.id_mid;
467	chip->nc_dev_id = cfi->cfi_id_data.id_did[0]; /* XXX 3 words */
468	chip->nc_size = 1 << cfi->cfi_qry_data.device_size;
469
470	/* size of line for Read Buf command */
471	chip->nc_line_size = 1 << cfi->cfi_qry_data.pri.cmd_0002.page_size;
472
473	/*
474	 * size of erase block
475	 * XXX depends on erase region
476	 */
477	chip->nc_num_luns = 1;
478	chip->nc_lun_blocks = cfi->cfi_qry_data.erase_blk_info[0].y + 1;
479	chip->nc_block_size = cfi->cfi_qry_data.erase_blk_info[0].z ?
480	    cfi->cfi_qry_data.erase_blk_info[0].z * 256 : 128;
481
482	switch (cfi->cfi_qry_data.id_pri) {
483	case 0x0002:
484		cfi_0002_init(sc, cfi, chip);
485		break;
486	}
487
488	return 0;
489}
490
491void
492cfi_init(device_t self)
493{
494	/* nothing */
495}
496
497static void
498cfi_select(device_t self, bool select)
499{
500	/* nothing */
501}
502
503static void
504cfi_read_1(device_t self, flash_off_t offset, uint8_t *datap)
505{
506}
507
508static void
509cfi_read_2(device_t self, flash_off_t offset, uint16_t *datap)
510{
511}
512
513static void
514cfi_read_4(device_t self, flash_off_t offset, uint32_t *datap)
515{
516}
517
518static void
519cfi_read_buf_1(device_t self, flash_off_t offset, uint8_t *datap, size_t size)
520{
521}
522
523static void
524cfi_read_buf_2(device_t self, flash_off_t offset, uint16_t *datap, size_t size)
525{
526}
527
528static void
529cfi_read_buf_4(device_t self, flash_off_t offset, uint32_t *datap, size_t size)
530{
531}
532
533static void
534cfi_write_1(device_t self, flash_off_t offset, uint8_t data)
535{
536}
537
538static void
539cfi_write_2(device_t self, flash_off_t offset, uint16_t data)
540{
541}
542
543static void
544cfi_write_4(device_t self, flash_off_t offset, uint32_t data)
545{
546}
547
548static void
549cfi_write_buf_1(device_t self, flash_off_t offset, const uint8_t *datap,
550    size_t size)
551{
552}
553
554static void
555cfi_write_buf_2(device_t self, flash_off_t offset, const uint16_t *datap,
556    size_t size)
557{
558}
559
560static void
561cfi_write_buf_4(device_t self, flash_off_t offset, const uint32_t *datap,
562    size_t size)
563{
564}
565
566/*
567 * cfi_cmd - write a CFI command word.
568 *
569 * The offset 'off' is given for 64-bit port width and will be scaled
570 * down to the actual port width of the chip.
571 * The command word will be constructed out of 'val' regarding port- and
572 * chip width.
573 */
574void
575cfi_cmd(struct cfi * const cfi, bus_size_t off, uint32_t val)
576{
577	const bus_space_tag_t bst = cfi->cfi_bst;
578	bus_space_handle_t bsh = cfi->cfi_bsh;
579	uint64_t cmd;
580	int cw, pw;
581
582	off >>= 3 - cfi->cfi_portwidth;
583
584	pw = 1 << cfi->cfi_portwidth;
585	cw = 1 << cfi->cfi_chipwidth;
586	cmd = 0;
587	while (pw > 0) {
588		cmd <<= cw << 3;
589		cmd += val;
590		pw -= cw;
591	}
592
593	DPRINTF(("%s: %p %x %x %" PRIx64 "\n", __func__, bst, bsh, off, cmd));
594
595	switch (cfi->cfi_portwidth) {
596	case 0:
597		bus_space_write_1(bst, bsh, off, cmd);
598		break;
599	case 1:
600		bus_space_write_2(bst, bsh, off, cmd);
601		break;
602	case 2:
603		bus_space_write_4(bst, bsh, off, cmd);
604		break;
605#ifdef NOTYET
606	case 3:
607		bus_space_write_8(bst, bsh, off, cmd);
608		break;
609#endif
610	default:
611		panic("%s: bad portwidth %d bytes\n",
612			__func__, 1 << cfi->cfi_portwidth);
613	}
614}
615
616static uint8_t
617cfi_read_qry(struct cfi * const cfi, bus_size_t off)
618{
619	const bus_space_tag_t bst = cfi->cfi_bst;
620	bus_space_handle_t bsh = cfi->cfi_bsh;
621	uint8_t data;
622
623	off <<= cfi->cfi_portwidth;
624
625	switch (cfi->cfi_portwidth) {
626	case 0:
627		data = bus_space_read_1(bst, bsh, off);
628		break;
629	case 1:
630		data = bus_space_read_2(bst, bsh, off);
631		break;
632	case 2:
633		data = bus_space_read_4(bst, bsh, off);
634		break;
635	case 3:
636		data = bus_space_read_8(bst, bsh, off);
637		break;
638	default:
639		data = ~0;
640		break;
641	}
642	return data;
643}
644
645/*
646 * cfi_reset_default - when we don't know which command will work, use both
647 */
648void
649cfi_reset_default(struct cfi * const cfi)
650{
651
652	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_RESET_DATA);
653	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_ALT_RESET_DATA);
654}
655
656/*
657 * cfi_reset_std - use standard reset command
658 */
659void
660cfi_reset_std(struct cfi * const cfi)
661{
662
663	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_RESET_DATA);
664}
665
666/*
667 * cfi_reset_alt - use "alternate" reset command
668 */
669void
670cfi_reset_alt(struct cfi * const cfi)
671{
672
673	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_ALT_RESET_DATA);
674}
675
676static void
677cfi_jedec_id_1(struct cfi * const cfi)
678{
679	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
680	uint8_t data[0x10];
681
682	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
683		__arraycount(data));
684
685	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
686
687	idp->id_mid = (uint16_t)data[0];
688	idp->id_did[0] = (uint16_t)data[1];
689	idp->id_did[1] = (uint16_t)data[0xe];
690	idp->id_did[2] = (uint16_t)data[0xf];
691	idp->id_prot_state = (uint16_t)data[2];
692	idp->id_indicators = (uint16_t)data[3];
693
694	/* software bits, upper and lower */
695	idp->id_swb_lo = data[0xc];
696	idp->id_swb_hi = data[0xd];
697
698}
699
700static void
701cfi_jedec_id_2(struct cfi * const cfi)
702{
703	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
704	uint16_t data[0x10];
705
706	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
707		__arraycount(data));
708
709	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
710
711	idp->id_mid = data[0];
712	idp->id_did[0] = data[1];
713	idp->id_did[1] = data[0xe];
714	idp->id_did[2] = data[0xf];
715	idp->id_prot_state = data[2];
716	idp->id_indicators = data[3];
717
718	/* software bits, upper and lower
719	 * - undefined on S29GL-P
720	 * - defined   on S29GL-S
721	 */
722	idp->id_swb_lo = data[0xc];
723	idp->id_swb_hi = data[0xd];
724
725}
726
727static void
728cfi_jedec_id_4(struct cfi * const cfi)
729{
730	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
731	uint32_t data[0x10];
732
733	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
734		__arraycount(data));
735
736	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
737
738	idp->id_mid = data[0] & 0xffff;
739	idp->id_did[0] = data[1] & 0xffff;
740	idp->id_did[1] = data[0xe] & 0xffff;
741	idp->id_did[2] = data[0xf] & 0xffff;
742	idp->id_prot_state = data[2] & 0xffff;
743	idp->id_indicators = data[3] & 0xffff;
744
745	/* software bits, upper and lower
746	 * - undefined on S29GL-P
747	 * - defined   on S29GL-S
748	 */
749	idp->id_swb_lo = data[0xc] & 0xffff;
750	idp->id_swb_hi = data[0xd] & 0xffff;
751
752}
753
754/*
755 * cfi_jedec_id - get JEDEC ID info
756 */
757static bool
758cfi_jedec_id(struct cfi * const cfi)
759{
760
761	DPRINTF(("%s\n", __func__));
762
763	cfi_reset_default(cfi);
764	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
765	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
766	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x90);
767
768	switch(cfi->cfi_portwidth) {
769	case 0:
770		cfi_jedec_id_1(cfi);
771		break;
772	case 1:
773		cfi_jedec_id_2(cfi);
774		break;
775	case 2:
776		cfi_jedec_id_4(cfi);
777		break;
778#ifdef NOTYET
779	case 3:
780		cfi_jedec_id_8(cfi);
781		break;
782#endif
783	default:
784		panic("%s: bad portwidth %d bytes\n",
785			__func__, 1 << cfi->cfi_portwidth);
786	}
787
788	return true;
789}
790
791static bool
792cfi_emulate(struct cfi * const cfi)
793{
794	bool found = false;
795	const struct cfi_jedec_tab *jt = cfi_jedec_search(cfi);
796	if (jt != NULL) {
797		found = true;
798		cfi->cfi_emulated = true;
799		cfi_jedec_fill(cfi, jt);
800	}
801	return found;
802}
803
804/*
805 * cfi_jedec_search - search cfi_jedec_tab[] for entry matching given JEDEC IDs
806 */
807static const struct cfi_jedec_tab *
808cfi_jedec_search(struct cfi *cfi)
809{
810	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
811
812	for (u_int i=0; i < __arraycount(cfi_jedec_tab); i++) {
813		const struct cfi_jedec_tab *jt = &cfi_jedec_tab[i];
814		if ((jt->jt_mid == idp->id_mid) &&
815		    (jt->jt_did == idp->id_did[0])) {
816			return jt;
817		}
818	}
819	return NULL;
820}
821
822/*
823 * cfi_jedec_fill - fill in cfi with info from table entry
824 */
825static void
826cfi_jedec_fill(struct cfi *cfi, const struct cfi_jedec_tab *jt)
827{
828
829	cfi->cfi_name = jt->jt_name;
830
831	struct cfi_query_data *qryp = &cfi->cfi_qry_data;
832	memset(qryp, 0, sizeof(*qryp));
833	qryp->id_pri = jt->jt_id_pri;
834	qryp->id_alt = jt->jt_id_alt;
835	qryp->interface_code_desc = jt->jt_interface_code_desc;
836	qryp->write_word_time_typ = jt->jt_write_word_time_typ;
837	qryp->write_nbyte_time_typ = jt->jt_write_nbyte_time_typ;
838	qryp->erase_blk_time_typ = jt->jt_erase_blk_time_typ;
839	qryp->erase_chip_time_typ = jt->jt_erase_chip_time_typ;
840	qryp->write_word_time_max = jt->jt_write_word_time_max;
841	qryp->write_nbyte_time_max = jt->jt_write_nbyte_time_max;
842	qryp->erase_blk_time_max = jt->jt_erase_blk_time_max;
843	qryp->erase_chip_time_max = jt->jt_erase_chip_time_max;
844	qryp->device_size = jt->jt_device_size;
845	qryp->interface_code_desc = jt->jt_interface_code_desc;
846	qryp->write_nbyte_size_max = jt->jt_write_nbyte_size_max;
847	qryp->erase_blk_regions = jt->jt_erase_blk_regions;
848	for (u_int i=0; i < 4; i++)
849		qryp->erase_blk_info[i] = jt->jt_erase_blk_info[i];
850
851}
852
853void
854cfi_print(device_t self, struct cfi * const cfi)
855{
856	char pbuf[sizeof("XXXX MB")];
857	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;
858
859	format_bytes(pbuf, sizeof(pbuf), 1 << qryp->device_size);
860	if (cfi->cfi_emulated) {
861		aprint_normal_dev(self, "%s NOR flash %s %s\n",
862			cfi->cfi_name, pbuf,
863			cfi_interface_desc_str(qryp->interface_code_desc));
864	} else {
865		aprint_normal_dev(self, "CFI NOR flash %s %s\n", pbuf,
866			cfi_interface_desc_str(qryp->interface_code_desc));
867	}
868#ifdef NOR_VERBOSE
869	aprint_normal_dev(self, "manufacturer id %#x, device id %#x %#x %#x\n",
870		cfi->cfi_id_data.id_mid,
871		cfi->cfi_id_data.id_did[0],
872		cfi->cfi_id_data.id_did[1],
873		cfi->cfi_id_data.id_did[2]);
874	aprint_normal_dev(self, "x%u device operating in %u-bit mode\n",
875		8 << cfi->cfi_portwidth, 8 << cfi->cfi_chipwidth);
876	aprint_normal_dev(self, "sw bits lo=%#x hi=%#x\n",
877		cfi->cfi_id_data.id_swb_lo,
878		cfi->cfi_id_data.id_swb_hi);
879	aprint_normal_dev(self, "max multibyte write size %d\n",
880		1 << qryp->write_nbyte_size_max);
881	aprint_normal_dev(self, "%d Erase Block Region(s)\n",
882		qryp->erase_blk_regions);
883	for (u_int r=0; r < qryp->erase_blk_regions; r++) {
884		size_t sz = qryp->erase_blk_info[r].z ?
885		    qryp->erase_blk_info[r].z * 256 : 128;
886		format_bytes(pbuf, sizeof(pbuf), sz);
887		aprint_normal("    %d: %d blocks, size %s\n", r,
888			qryp->erase_blk_info[r].y + 1, pbuf);
889	}
890#endif
891
892	switch (cfi->cfi_qry_data.id_pri) {
893	case 0x0002:
894		cfi_0002_print(self, cfi);
895		break;
896	}
897}
898
899#if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
900void
901cfi_hexdump(flash_off_t offset, void * const v, u_int count, u_int stride)
902{
903	uint8_t * const data = v;
904	for(int n=0; n < count; n+=16) {
905		int i;
906		printf("%08llx: ", (offset + n) / stride);
907		for(i=n; i < n+16; i++)
908			printf("%02x ", data[i]);
909		printf("\t");
910		for(i=n; i < n+16; i++) {
911			u_int c = (int)data[i];
912			if (c >= 0x20 && c < 0x7f)
913				printf("%c", c);
914			else
915				printf("%c", '.');
916		}
917		printf("\n");
918	}
919}
920#endif
921