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