Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/nor - dump raw QRY and/or JEDEC data depending on CF...



details:   https://anonhg.NetBSD.org/src/rev/1bdc36109f0c
branches:  trunk
changeset: 767577:1bdc36109f0c
user:      cliff <cliff%NetBSD.org@localhost>
date:      Sat Jul 23 06:27:40 2011 +0000

description:
- dump raw QRY and/or JEDEC data depending on CFI_DEBUG_QRY, CFI_DEBUG_JEDEC
- add ability to emulate CFI based on table lookup keyed by JEDEC IDs.
- warn if CFI command set is unknown

diffstat:

 sys/dev/nor/cfi.c |  311 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 276 insertions(+), 35 deletions(-)

diffs (truncated from 492 to 300 lines):

diff -r 0e0830816d1e -r 1bdc36109f0c sys/dev/nor/cfi.c
--- a/sys/dev/nor/cfi.c Sat Jul 23 06:27:09 2011 +0000
+++ b/sys/dev/nor/cfi.c Sat Jul 23 06:27:40 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cfi.c,v 1.3 2011/07/19 20:52:10 cliff Exp $    */
+/*     $NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $    */
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -28,11 +28,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_flash.h"
 #include "opt_nor.h"
-#include "opt_flash.h"
+#include "opt_cfi.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.3 2011/07/19 20:52:10 cliff Exp $"); 
+__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $"); 
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -63,7 +64,18 @@
 static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
 static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
 static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
+static void cfi_jedec_id_1(struct cfi * const );
+static void cfi_jedec_id_2(struct cfi * const );
+static void cfi_jedec_id_4(struct cfi * const );
 static bool cfi_jedec_id(struct cfi * const);
+static bool cfi_emulate(struct cfi * const);
+static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *);
+static void cfi_jedec_fill(struct cfi * const,
+       const struct cfi_jedec_tab *);
+#if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
+static void cfi_hexdump(flash_off_t, void * const, u_int, u_int);
+#endif
+
 
 
 /*
@@ -99,6 +111,70 @@
 };
 
 
+#define LOG2_64K       16
+#define LOG2_128K      17
+#define LOG2_256K      18
+#define LOG2_512K      19
+#define LOG2_1M                20
+#define LOG2_2M                21
+#define LOG2_4M                22
+#define LOG2_8M                23
+#define LOG2_16M       24
+#define LOG2_32M       25
+#define LOG2_64M       26
+#define LOG2_128M      27
+#define LOG2_256M      28
+#define LOG2_512M      29
+#define LOG2_1G                30
+#define LOG2_2G                31
+const struct cfi_jedec_tab cfi_jedec_tab[] = {
+       {
+               .jt_name = "Pm39LV512",
+               .jt_mid = 0x9d,
+               .jt_did = 0x1b,
+               .jt_id_pri = 0,                         /* XXX */
+               .jt_id_alt = 0,                         /* XXX */
+               .jt_device_size = LOG2_64K,
+               .jt_interface_code_desc = CFI_IFCODE_X8,
+               .jt_erase_blk_regions = 1,
+               .jt_erase_blk_info = {
+                       { 4096/256, (64/4)-1 },
+               },
+               .jt_write_word_time_typ = 40,
+               .jt_write_nbyte_time_typ = 0,
+               .jt_erase_blk_time_typ = 55,
+               .jt_erase_chip_time_typ = 55,
+               .jt_write_word_time_max = 1,
+               .jt_write_nbyte_time_max = 0,
+               .jt_erase_blk_time_max = 1,
+               .jt_erase_chip_time_max = 1,
+               .jt_opmode = &cfi_opmodes_1[0],
+       },
+       {
+               .jt_name = "Pm39LV010",
+               .jt_mid = 0x9d,
+               .jt_did = 0x1c,
+               .jt_id_pri = 0,                         /* XXX */
+               .jt_id_alt = 0,                         /* XXX */
+               .jt_device_size = LOG2_128K,
+               .jt_interface_code_desc = CFI_IFCODE_X8,
+               .jt_erase_blk_regions = 1,
+               .jt_erase_blk_info = {
+                       { 4096/256, (128/4)-1 },
+               },
+               .jt_write_word_time_typ = 40,
+               .jt_write_nbyte_time_typ = 0,
+               .jt_erase_blk_time_typ = 55,
+               .jt_erase_chip_time_typ = 55,
+               .jt_write_word_time_max = 1,
+               .jt_write_nbyte_time_max = 0,
+               .jt_erase_blk_time_max = 1,
+               .jt_erase_chip_time_max = 1,
+               .jt_opmode = &cfi_opmodes_1[0],
+       },
+};
+
+
 const struct nor_interface nor_interface_cfi = {
        .scan_media = cfi_scan_media,
        .init = cfi_init,
@@ -157,11 +233,11 @@
        (qryp)->write_word_time_typ = cfi_unpack_1(data[0x1f]);         \
        (qryp)->write_nbyte_time_typ = cfi_unpack_1(data[0x20]);        \
        (qryp)->erase_blk_time_typ = cfi_unpack_1(data[0x21]);          \
-       (qryp)->erase_chiptime_typ = cfi_unpack_1(data[0x22]);          \
+       (qryp)->erase_chip_time_typ = cfi_unpack_1(data[0x22]);         \
        (qryp)->write_word_time_max = cfi_unpack_1(data[0x23]);         \
        (qryp)->write_nbyte_time_max = cfi_unpack_1(data[0x24]);        \
        (qryp)->erase_blk_time_max = cfi_unpack_1(data[0x25]);          \
-       (qryp)->erase_chiptime_max = cfi_unpack_1(data[0x26]);          \
+       (qryp)->erase_chip_time_max = cfi_unpack_1(data[0x26]);         \
        (qryp)->device_size = cfi_unpack_1(data[0x27]);                 \
        (qryp)->interface_code_desc =                                   \
                be16toh(cfi_unpack_2(data[0x28], data[0x29]));          \
@@ -239,6 +315,27 @@
        }                                                               \
     } while (0)
 
+#ifdef CFI_DEBUG_QRY
+# define CFI_DUMP_QRY(off, p, sz, stride)                              \
+    do {                                                               \
+       printf("%s: QRY data\n", __func__);                             \
+       cfi_hexdump(off, p, sz, stride);                                \
+    } while (0)
+#else
+# define CFI_DUMP_QRY(off, p, sz, stride)
+#endif
+
+#ifdef CFI_DEBUG_JEDEC
+# define CFI_DUMP_JEDEC(off, p, sz, stride)                            \
+    do {                                                               \
+       printf("%s: JEDEC data\n", __func__);                           \
+       cfi_hexdump(off, p, sz, stride);                                \
+    } while (0)
+#else
+# define CFI_DUMP_JEDEC(off, p, sz, stride)
+#endif
+
+
 /*
  * cfi_chip_query_opmode - determine operational mode based on QRY signature
  */
@@ -263,6 +360,8 @@
        bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
                __arraycount(data));
 
+       CFI_DUMP_QRY(0, data, sizeof(data), 1);
+
        bool found = cfi_chip_query_opmode(cfi, data, cfi_opmodes_1,
                __arraycount(cfi_opmodes_1));
 
@@ -281,6 +380,8 @@
        bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
                __arraycount(data));
 
+       CFI_DUMP_QRY(0, data, sizeof(data), 2);
+
        bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
                cfi_opmodes_2, __arraycount(cfi_opmodes_2));
 
@@ -299,6 +400,8 @@
        bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
                __arraycount(data));
 
+       CFI_DUMP_QRY(0, data, sizeof(data), 4);
+
        bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
                cfi_opmodes_4, __arraycount(cfi_opmodes_4));
 
@@ -318,6 +421,8 @@
        bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
                __arraycount(data));
 
+       CFI_DUMP_QRY(0, data, sizeof(data), 8);
+
        bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
                cfi_opmodes_8, __arraycount(cfi_opmodes_8));
 
@@ -372,12 +477,20 @@
                }
        }
 
+       if (found)
+               cfi->cfi_emulated = false;
+
        return found;
 }
 
 /*
  * cfi_probe - search for a CFI NOR trying various port & chip widths
  *
+ * - gather CFI QRY and PRI data
+ * - gather JEDEC ID data
+ * - if cfi_chip_query() fails, emulate CFI using table data if possible,
+ *   otherwise fail.
+ *
  * NOTE:
  *   striped NOR chips design not supported yet,
  *   so force portwidth=chipwidth for now
@@ -394,10 +507,13 @@
                cfi->cfi_portwidth =            /* XXX */
                cfi->cfi_chipwidth = cw;
                found = cfi_chip_query(cfi);
+               cfi_jedec_id(cfi);
+               if (! found)
+                       found = cfi_emulate(cfi);
                if (found)
-                       goto out;
+                       break;
        }
- out:
+
        cfi_reset_default(cfi);         /* exit QRY mode */
        return found;
 }
@@ -407,7 +523,7 @@
 {
        const bus_space_tag_t bst = cfi->cfi_bst;
        const bus_space_handle_t bsh = cfi->cfi_bsh;
-       bool found = true;
+       bool found;
 
        KASSERT(cfi != NULL);
        KASSERT(bst != NULL);
@@ -416,20 +532,8 @@
        cfi->cfi_bst = bst;             /* restore bus space */
        cfi->cfi_bsh = bsh;             /*  "       "   "    */
 
-       /* gather CFI PRQ and PRI data */
-       if (! cfi_probe(cfi)) {
-               aprint_debug("%s: cfi_probe failed\n", __func__);
-               found = false;
-               goto out;
-       }
+       found = cfi_probe(cfi);
 
-       /* gather ID data if possible */
-       if (! cfi_jedec_id(cfi)) {
-               aprint_debug("%s: cfi_jedec_id failed\n", __func__);
-               goto out;
-       }
-
- out:
        cfi_reset_default(cfi); /* exit QRY mode */
 
        return found;
@@ -466,6 +570,8 @@
                cfi_0002_init(sc, cfi, chip);
                break;
        default:
+               aprint_error_dev(self, "unsupported CFI cmdset %#04x\n",
+                       cfi->cfi_qry_data.id_pri);
                return -1;
        }
 
@@ -607,6 +713,30 @@
 }
 
 static void
+cfi_jedec_id_1(struct cfi * const cfi)
+{
+       struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
+       uint8_t data[0x10];
+
+       bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
+               __arraycount(data));
+
+       CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
+
+       idp->id_mid = (uint16_t)data[0];
+       idp->id_did[0] = (uint16_t)data[1];
+       idp->id_did[1] = (uint16_t)data[0xe];
+       idp->id_did[2] = (uint16_t)data[0xf];
+       idp->id_prot_state = (uint16_t)data[2];
+       idp->id_indicators = (uint16_t)data[3];
+
+       /* software bits, upper and lower */
+       idp->id_swb_lo = data[0xc];
+       idp->id_swb_hi = data[0xd];
+
+}
+
+static void
 cfi_jedec_id_2(struct cfi * const cfi)
 {
        struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;



Home | Main Index | Thread Index | Old Index