Author: ian
Date: Sat Dec 14 00:54:05 2013
New Revision: 259371
URL: http://svnweb.freebsd.org/changeset/base/259371

Log:
  MFC r257892, r258196, r258197, r258199, r258200, r258201, r258202:
  
    Add ONFI signature check.
  
    Add Micron chip found in Freescale Vybrid Family Phytec COSMIC board.
  
    The vendor specified field is 88 bytes, not 8 bytes.
  
    Update the onfi_params struct to ONFI revision 3.2 (06 12 2013).
  
    Search for and validate the ONFI params as specified in the standard.
  
    ONFI parameters are little-endian, hence we must take care to convert them
    to native endianness.  We must also pay attention to unaligned accesses.
  
    Rework the routine that returns a pointer to the table of software ECC
    byte positions within the OOB area to support chips with unusual OOB
    sizes such as 218 or 224 bytes.

Modified:
  stable/10/sys/dev/nand/nand.c
  stable/10/sys/dev/nand/nand.h
  stable/10/sys/dev/nand/nand_generic.c
  stable/10/sys/dev/nand/nand_id.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/nand/nand.c
==============================================================================
--- stable/10/sys/dev/nand/nand.c       Sat Dec 14 00:40:47 2013        
(r259370)
+++ stable/10/sys/dev/nand/nand.c       Sat Dec 14 00:54:05 2013        
(r259371)
@@ -115,7 +115,7 @@ nand_init(struct nand_softc *nand, devic
 }
 
 void
-nand_onfi_set_params(struct nand_chip *chip, struct onfi_params *params)
+nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params)
 {
        struct chip_geom *cg;
 
@@ -309,23 +309,22 @@ nand_get_chip_param(struct nand_chip *ch
 static uint16_t *
 default_software_ecc_positions(struct nand_chip *chip)
 {
-       struct nand_ecc_data *eccd;
-
-       eccd = &chip->nand->ecc;
-
-       if (eccd->eccpositions)
-               return (eccd->eccpositions);
-
-       switch (chip->chip_geom.oob_size) {
-       case 16:
-               return ((uint16_t *)&default_software_ecc_positions_16);
-       case 64:
-               return ((uint16_t *)&default_software_ecc_positions_64);
-       case 128:
-               return ((uint16_t *)&default_software_ecc_positions_128);
-       default:
-               return (NULL); /* No ecc bytes positions defs available */
-       }
+       /* If positions have been set already, use them. */
+       if (chip->nand->ecc.eccpositions)
+               return (chip->nand->ecc.eccpositions);
+
+       /*
+        * XXX Note that the following logic isn't really sufficient, especially
+        * in the ONFI case where the number of ECC bytes can be dictated by
+        * values in the parameters page, and that could lead to needing more
+        * byte positions than exist within the tables of software-ecc defaults.
+        */
+       if (chip->chip_geom.oob_size >= 128)
+               return (default_software_ecc_positions_128);
+       if (chip->chip_geom.oob_size >= 64)
+               return (default_software_ecc_positions_64);
+       else if (chip->chip_geom.oob_size >= 16)
+               return (default_software_ecc_positions_16);
 
        return (NULL);
 }

Modified: stable/10/sys/dev/nand/nand.h
==============================================================================
--- stable/10/sys/dev/nand/nand.h       Sat Dec 14 00:40:47 2013        
(r259370)
+++ stable/10/sys/dev/nand/nand.h       Sat Dec 14 00:54:05 2013        
(r259371)
@@ -31,6 +31,7 @@
 
 #include <sys/bus.h>
 #include <sys/param.h>
+#include <sys/systm.h>
 #include <sys/lock.h>
 #include <sys/sx.h>
 #include <sys/taskqueue.h>
@@ -122,7 +123,8 @@ MALLOC_DECLARE(M_NAND);
 
 #define NAND_MAN_SAMSUNG               0xec
 #define NAND_MAN_HYNIX                 0xad
-#define        NAND_MAN_STMICRO                0x20
+#define NAND_MAN_STMICRO               0x20
+#define NAND_MAN_MICRON                        0x2c
 
 struct nand_id {
        uint8_t man_id;
@@ -176,12 +178,17 @@ struct onfi_params {
        uint16_t        rev;
        uint16_t        features;
        uint16_t        optional_commands;
-       uint8_t         res1[22];
+       uint8_t         primary_advanced_command;
+       uint8_t         res1;
+       uint16_t        extended_parameter_page_length;
+       uint8_t         parameter_page_count;
+       uint8_t         res2[17];
        char            manufacturer_name[12];
        char            device_model[20];
        uint8_t         manufacturer_id;
-       uint16_t        date;
-       uint8_t         res2[13];
+       uint8_t         manufacture_date_yy;
+       uint8_t         manufacture_date_ww;
+       uint8_t         res3[13];
        uint32_t        bytes_per_page;
        uint16_t        spare_bytes_per_page;
        uint32_t        bytes_per_partial_page;
@@ -200,7 +207,8 @@ struct onfi_params {
        uint8_t         bits_of_ecc;
        uint8_t         interleaved_addr_bits;
        uint8_t         interleaved_oper_attr;
-       uint8_t         res3[13];
+       uint8_t         eznand_support;
+       uint8_t         res4[12];
        uint8_t         pin_capacitance;
        uint16_t        asynch_timing_mode_support;
        uint16_t        asynch_prog_cache_timing_mode_support;
@@ -215,11 +223,31 @@ struct onfi_params {
        uint16_t        input_capacitance;
        uint8_t         input_capacitance_max;
        uint8_t         driver_strength_support;
-       uint8_t         res4[12];
+       uint16_t        t_r_interleaved;
+       uint16_t        t_adl;
+       uint16_t        t_r_eznand;
+       uint8_t         nv_ddr2_features;
+       uint8_t         nv_ddr2_warmup_cycles;
+       uint8_t         res5[4];
        uint16_t        vendor_rev;
-       uint8_t         vendor_spec[8];
+       uint8_t         vendor_spec[88];
        uint16_t        crc;
 }__attribute__((packed));
+CTASSERT(sizeof(struct onfi_params) == 256);
+
+struct onfi_chip_params {
+       uint32_t blocks_per_lun;
+       uint32_t pages_per_block;
+       uint32_t bytes_per_page;
+       uint32_t spare_bytes_per_page;
+       uint16_t t_bers;
+       uint16_t t_prog;
+       uint16_t t_r;
+       uint16_t t_ccs;
+       uint16_t features;
+       uint8_t address_cycles;
+       uint8_t luns;
+};
 
 struct nand_ecc_data {
        int     eccsize;                /* Number of data bytes per ECC step */
@@ -353,7 +381,7 @@ void nand_init(struct nand_softc *nand, 
 void nand_detach(struct nand_softc *nand);
 struct nand_params *nand_get_params(struct nand_id *id);
 
-void nand_onfi_set_params(struct nand_chip *chip, struct onfi_params *params);
+void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params 
*params);
 void nand_set_params(struct nand_chip *chip, struct nand_params *params);
 int  nand_init_stat(struct nand_chip *chip);
 void nand_destroy_stat(struct nand_chip *chip);

Modified: stable/10/sys/dev/nand/nand_generic.c
==============================================================================
--- stable/10/sys/dev/nand/nand_generic.c       Sat Dec 14 00:40:47 2013        
(r259370)
+++ stable/10/sys/dev/nand/nand_generic.c       Sat Dec 14 00:54:05 2013        
(r259371)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/proc.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
+#include <sys/endian.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/rman.h>
@@ -73,7 +74,7 @@ static int small_program_page(device_t, 
 static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t);
 
 static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *);
-static int onfi_read_parameter(struct nand_chip *, struct onfi_params *);
+static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *);
 
 static int nand_send_address(device_t, int32_t, int32_t, int8_t);
 
@@ -206,7 +207,7 @@ generic_nand_attach(device_t dev)
 {
        struct nand_chip *chip;
        struct nandbus_ivar *ivar;
-       struct onfi_params *onfi_params;
+       struct onfi_chip_params *onfi_chip_params;
        device_t nandbus, nfc;
        int err;
 
@@ -225,25 +226,24 @@ generic_nand_attach(device_t dev)
        chip->nand = device_get_softc(nfc);
 
        if (ivar->is_onfi) {
-               onfi_params = malloc(sizeof(struct onfi_params),
+               onfi_chip_params = malloc(sizeof(struct onfi_chip_params),
                    M_NAND, M_WAITOK | M_ZERO);
-               if (onfi_params == NULL)
-                       return (ENXIO);
+               if (onfi_chip_params == NULL)
+                       return (ENOMEM);
 
-               if (onfi_read_parameter(chip, onfi_params)) {
+               if (onfi_read_parameter(chip, onfi_chip_params)) {
                        nand_debug(NDBG_GEN,"Could not read parameter page!\n");
-                       free(onfi_params, M_NAND);
+                       free(onfi_chip_params, M_NAND);
                        return (ENXIO);
                }
 
-               nand_onfi_set_params(chip, onfi_params);
+               nand_onfi_set_params(chip, onfi_chip_params);
                /* Set proper column and row cycles */
-               ivar->cols = (onfi_params->address_cycles >> 4) & 0xf;
-               ivar->rows = onfi_params->address_cycles & 0xf;
-               free(onfi_params, M_NAND);
+               ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf;
+               ivar->rows = onfi_chip_params->address_cycles & 0xf;
+               free(onfi_chip_params, M_NAND);
 
        } else {
-
                nand_set_params(chip, ivar->params);
        }
 
@@ -319,10 +319,32 @@ check_fail(device_t nandbus)
        return (0);
 }
 
+static uint16_t
+onfi_crc(const void *buf, size_t buflen)
+{
+       int i, j;
+       uint16_t crc;
+       const uint8_t *bufptr;
+
+       bufptr = buf;
+       crc = 0x4f4e;
+       for (j = 0; j < buflen; j++) {
+               crc ^= *bufptr++ << 8;
+               for (i = 0; i < 8; i++)
+                       if (crc & 0x8000)
+                               crc = (crc << 1) ^ 0x8005;
+                       else
+                               crc <<= 1;
+       }
+       return crc;
+}
+
 static int
-onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params)
+onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params 
*chip_params)
 {
        device_t nandbus;
+       struct onfi_params params;
+       int found, sigcount, trycopy;
 
        nand_debug(NDBG_GEN,"read parameter");
 
@@ -339,12 +361,44 @@ onfi_read_parameter(struct nand_chip *ch
        if (NANDBUS_START_COMMAND(nandbus))
                return (ENXIO);
 
-       NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params));
-
-       /* TODO */
-       /* Check for signature */
-       /* Check CRC */
-       /* Use redundant page if necessary */
+       /*
+        * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's
+        * not accessible from here (static to nandbus).
+        */
+       DELAY(1000);
+
+       /*
+        * The ONFI spec mandates a minimum of three copies of the parameter
+        * data, so loop up to 3 times trying to find good data.  Each copy is
+        * validated by a signature of "ONFI" and a crc. There is a very strange
+        * rule that the signature is valid if any 2 of the 4 bytes are correct.
+        */
+       for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) {
+               NANDBUS_READ_BUFFER(nandbus, &params, sizeof(struct 
onfi_params));
+               sigcount  = params.signature[0] == 'O';
+               sigcount += params.signature[1] == 'N';
+               sigcount += params.signature[2] == 'F';
+               sigcount += params.signature[3] == 'I';
+               if (sigcount < 2)
+                       continue;
+               if (onfi_crc(&params, 254) != params.crc)
+                       continue;
+               found = 1;
+       }
+       if (!found)
+               return (ENXIO);
+
+       chip_params->luns = params.luns;
+       chip_params->blocks_per_lun = le32dec(&params.blocks_per_lun);
+       chip_params->pages_per_block = le32dec(&params.pages_per_block);
+       chip_params->bytes_per_page = le32dec(&params.bytes_per_page);
+       chip_params->spare_bytes_per_page = 
le32dec(&params.spare_bytes_per_page);
+       chip_params->t_bers = le16dec(&params.t_bers);
+       chip_params->t_prog = le16dec(&params.t_prog);
+       chip_params->t_r = le16dec(&params.t_r);
+       chip_params->t_ccs = le16dec(&params.t_ccs);
+       chip_params->features = le16dec(&params.features);
+       chip_params->address_cycles = params.address_cycles;
 
        return (0);
 }

Modified: stable/10/sys/dev/nand/nand_id.c
==============================================================================
--- stable/10/sys/dev/nand/nand_id.c    Sat Dec 14 00:40:47 2013        
(r259370)
+++ stable/10/sys/dev/nand/nand_id.c    Sat Dec 14 00:54:05 2013        
(r259371)
@@ -47,6 +47,8 @@ struct nand_params nand_ids[] = {
            0x80, 0x200, 0x10, 0x20, 0 },
        { { NAND_MAN_STMICRO, 0xf1 }, "STMicro 128MB 3,3V 8-bit",
            0x80, 2048, 64, 0x40, 0 },
+       { { NAND_MAN_MICRON, 0xcc }, "Micron NAND 512MiB 3,3V 16-bit",
+           0x200, 2048, 64, 0x40, 0 },
 };
 
 struct nand_params *nand_get_params(struct nand_id *id)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to