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 
51 static int  cfi_scan_media(device_t self, struct nor_chip *chip);
52 static void cfi_init(device_t);
53 static void cfi_select(device_t, bool);
54 static void cfi_read_1(device_t, flash_off_t, uint8_t *);
55 static void cfi_read_2(device_t, flash_off_t, uint16_t *);
56 static void cfi_read_4(device_t, flash_off_t, uint32_t *);
57 static void cfi_read_buf_1(device_t, flash_off_t, uint8_t *, size_t);
58 static void cfi_read_buf_2(device_t, flash_off_t, uint16_t *, size_t);
59 static void cfi_read_buf_4(device_t, flash_off_t, uint32_t *, size_t);
60 static void cfi_write_1(device_t, flash_off_t, uint8_t);
61 static void cfi_write_2(device_t, flash_off_t, uint16_t);
62 static void cfi_write_4(device_t, flash_off_t, uint32_t);
63 static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
64 static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
65 static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
66 static uint8_t cfi_read_qry(struct cfi * const, bus_size_t);
67 static bool cfi_jedec_id(struct cfi * const);
68 static bool cfi_emulate(struct cfi * const);
69 static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *);
70 static void cfi_jedec_fill(struct cfi * const,
71           const struct cfi_jedec_tab *);
72 #if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
73 static 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
92 const 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 
138 const 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 
292 static void
cfi_chip_query_1(struct cfi * const cfi)293 cfi_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 
303 static void
cfi_chip_query_2(struct cfi * const cfi)304 cfi_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 
314 static void
cfi_chip_query_4(struct cfi * const cfi)315 cfi_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 
325 static void
cfi_chip_query_8(struct cfi * const cfi)326 cfi_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  */
343 static bool
cfi_chip_query(struct cfi * const cfi)344 cfi_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  */
410 bool
cfi_probe(struct cfi * const cfi)411 cfi_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 
439 bool
cfi_identify(struct cfi * const cfi)440 cfi_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 
455 static int
cfi_scan_media(device_t self,struct nor_chip * chip)456 cfi_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 
491 void
cfi_init(device_t self)492 cfi_init(device_t self)
493 {
494           /* nothing */
495 }
496 
497 static void
cfi_select(device_t self,bool select)498 cfi_select(device_t self, bool select)
499 {
500           /* nothing */
501 }
502 
503 static void
cfi_read_1(device_t self,flash_off_t offset,uint8_t * datap)504 cfi_read_1(device_t self, flash_off_t offset, uint8_t *datap)
505 {
506 }
507 
508 static void
cfi_read_2(device_t self,flash_off_t offset,uint16_t * datap)509 cfi_read_2(device_t self, flash_off_t offset, uint16_t *datap)
510 {
511 }
512 
513 static void
cfi_read_4(device_t self,flash_off_t offset,uint32_t * datap)514 cfi_read_4(device_t self, flash_off_t offset, uint32_t *datap)
515 {
516 }
517 
518 static void
cfi_read_buf_1(device_t self,flash_off_t offset,uint8_t * datap,size_t size)519 cfi_read_buf_1(device_t self, flash_off_t offset, uint8_t *datap, size_t size)
520 {
521 }
522 
523 static void
cfi_read_buf_2(device_t self,flash_off_t offset,uint16_t * datap,size_t size)524 cfi_read_buf_2(device_t self, flash_off_t offset, uint16_t *datap, size_t size)
525 {
526 }
527 
528 static void
cfi_read_buf_4(device_t self,flash_off_t offset,uint32_t * datap,size_t size)529 cfi_read_buf_4(device_t self, flash_off_t offset, uint32_t *datap, size_t size)
530 {
531 }
532 
533 static void
cfi_write_1(device_t self,flash_off_t offset,uint8_t data)534 cfi_write_1(device_t self, flash_off_t offset, uint8_t data)
535 {
536 }
537 
538 static void
cfi_write_2(device_t self,flash_off_t offset,uint16_t data)539 cfi_write_2(device_t self, flash_off_t offset, uint16_t data)
540 {
541 }
542 
543 static void
cfi_write_4(device_t self,flash_off_t offset,uint32_t data)544 cfi_write_4(device_t self, flash_off_t offset, uint32_t data)
545 {
546 }
547 
548 static void
cfi_write_buf_1(device_t self,flash_off_t offset,const uint8_t * datap,size_t size)549 cfi_write_buf_1(device_t self, flash_off_t offset, const uint8_t *datap,
550     size_t size)
551 {
552 }
553 
554 static void
cfi_write_buf_2(device_t self,flash_off_t offset,const uint16_t * datap,size_t size)555 cfi_write_buf_2(device_t self, flash_off_t offset, const uint16_t *datap,
556     size_t size)
557 {
558 }
559 
560 static void
cfi_write_buf_4(device_t self,flash_off_t offset,const uint32_t * datap,size_t size)561 cfi_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  */
574 void
cfi_cmd(struct cfi * const cfi,bus_size_t off,uint32_t val)575 cfi_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 
616 static uint8_t
cfi_read_qry(struct cfi * const cfi,bus_size_t off)617 cfi_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  */
648 void
cfi_reset_default(struct cfi * const cfi)649 cfi_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  */
659 void
cfi_reset_std(struct cfi * const cfi)660 cfi_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  */
669 void
cfi_reset_alt(struct cfi * const cfi)670 cfi_reset_alt(struct cfi * const cfi)
671 {
672 
673           cfi_cmd(cfi, CFI_ADDR_ANY, CFI_ALT_RESET_DATA);
674 }
675 
676 static void
cfi_jedec_id_1(struct cfi * const cfi)677 cfi_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 
700 static void
cfi_jedec_id_2(struct cfi * const cfi)701 cfi_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 
727 static void
cfi_jedec_id_4(struct cfi * const cfi)728 cfi_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  */
757 static bool
cfi_jedec_id(struct cfi * const cfi)758 cfi_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 
791 static bool
cfi_emulate(struct cfi * const cfi)792 cfi_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  */
807 static const struct cfi_jedec_tab *
cfi_jedec_search(struct cfi * cfi)808 cfi_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  */
825 static void
cfi_jedec_fill(struct cfi * cfi,const struct cfi_jedec_tab * jt)826 cfi_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 
853 void
cfi_print(device_t self,struct cfi * const cfi)854 cfi_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)
900 void
cfi_hexdump(flash_off_t offset,void * const v,u_int count,u_int stride)901 cfi_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