Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Dec 2013 00:54:06 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r259371 - stable/10/sys/dev/nand
Message-ID:  <201312140054.rBE0s6eb009513@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312140054.rBE0s6eb009513>