Add support for legacy devices not supporting the ONFI READ_PARAMETER_PAGE
command with example usage for Micron chips
This commit is contained in:
parent
a30ace437f
commit
14ce4ecc83
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.nand,v 1.1 2011/02/26 18:07:31 ahoka Exp $
|
||||
# $NetBSD: files.nand,v 1.2 2011/03/09 10:05:08 ahoka Exp $
|
||||
|
||||
define nandbus { }
|
||||
|
||||
|
@ -9,6 +9,7 @@ file dev/nand/nand_io.c nand
|
|||
file dev/nand/hamming.c nand
|
||||
file dev/nand/nand_bbt.c nand
|
||||
file dev/nand/nand_crc.c nand
|
||||
file dev/nand/nand_micron.c nand
|
||||
|
||||
defpseudodev nandemulator: nandbus
|
||||
file dev/nand/nandemulator.c nandemulator
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nand.c,v 1.2 2011/03/09 07:49:15 ahoka Exp $ */
|
||||
/* $NetBSD: nand.c,v 1.3 2011/03/09 10:05:08 ahoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010 Department of Software Engineering,
|
||||
|
@ -34,7 +34,7 @@
|
|||
/* Common driver for NAND chips implementing the ONFI 2.2 specification */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.2 2011/03/09 07:49:15 ahoka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.3 2011/03/09 10:05:08 ahoka Exp $");
|
||||
|
||||
#include "locators.h"
|
||||
|
||||
|
@ -117,8 +117,10 @@ nand_attach(device_t parent, device_t self, void *aux)
|
|||
aprint_error("NAND chip is write protected!\n");
|
||||
return;
|
||||
}
|
||||
if (nand_scan_media(self, chip))
|
||||
|
||||
if (nand_scan_media(self, chip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate cache */
|
||||
chip->nc_oob_cache = kmem_alloc(chip->nc_spare_size, KM_SLEEP);
|
||||
|
@ -281,6 +283,19 @@ nand_quirks(device_t self, struct nand_chip *chip)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
nand_read_legacy_parameters(device_t self, struct nand_chip *chip)
|
||||
{
|
||||
switch (chip->nc_manf_id) {
|
||||
case NAND_MFR_MICRON:
|
||||
return nand_read_parameters_micron(self, chip);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scan media to determine the chip's properties
|
||||
* this function resets the device
|
||||
|
@ -296,6 +311,7 @@ nand_scan_media(device_t self, struct nand_chip *chip)
|
|||
nand_command(self, ONFI_RESET);
|
||||
nand_select(self, false);
|
||||
|
||||
/* check if the device implements the ONFI standard */
|
||||
nand_select(self, true);
|
||||
nand_command(self, ONFI_READ_ID);
|
||||
nand_address(self, 0x20);
|
||||
|
@ -307,24 +323,48 @@ nand_scan_media(device_t self, struct nand_chip *chip)
|
|||
|
||||
if (onfi_signature[0] != 'O' || onfi_signature[1] != 'N' ||
|
||||
onfi_signature[2] != 'F' || onfi_signature[3] != 'I') {
|
||||
aprint_error_dev(self,
|
||||
"device does not support the ONFI specification\n");
|
||||
chip->nc_isonfi = false;
|
||||
|
||||
aprint_normal(": Legacy NAND Flash\n");
|
||||
|
||||
nand_readid(self, chip);
|
||||
|
||||
return 1;
|
||||
if (nand_read_legacy_parameters(self, chip)) {
|
||||
aprint_error_dev(self,
|
||||
"can't read device parameters for legacy chip\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
chip->nc_isonfi = true;
|
||||
|
||||
aprint_normal(": ONFI NAND Flash\n");
|
||||
|
||||
nand_readid(self, chip);
|
||||
nand_read_parameter_page(self, chip);
|
||||
}
|
||||
|
||||
nand_readid(self, chip);
|
||||
|
||||
aprint_normal(": NAND Flash\n");
|
||||
|
||||
aprint_debug_dev(self,
|
||||
#ifdef NAND_VERBOSE
|
||||
aprint_normal_dev(self,
|
||||
"manufacturer id: 0x%.2x (%s), device id: 0x%.2x\n",
|
||||
chip->nc_manf_id,
|
||||
nand_midtoname(chip->nc_manf_id),
|
||||
chip->nc_dev_id);
|
||||
#endif
|
||||
|
||||
nand_read_parameter_page(self, chip);
|
||||
aprint_normal_dev(self,
|
||||
"page size: %u bytes, spare size: %u bytes, block size: %u bytes\n",
|
||||
chip->nc_page_size, chip->nc_spare_size, chip->nc_block_size);
|
||||
|
||||
aprint_normal_dev(self,
|
||||
"LUN size: %u blocks, LUNs: %u, total storage size: %u MB\n",
|
||||
chip->nc_lun_blocks, chip->nc_num_luns,
|
||||
chip->nc_size / 1024 / 1024);
|
||||
|
||||
#ifdef NAND_VERBOSE
|
||||
aprint_normal_dev(self, "column cycles: %d, row cycles: %d\n",
|
||||
chip->nc_addr_cycles_column, chip->nc_addr_cycles_row);
|
||||
#endif
|
||||
|
||||
ecc = chip->nc_ecc = &sc->nand_if->ecc;
|
||||
|
||||
/*
|
||||
|
@ -388,12 +428,13 @@ nand_readid(device_t self, struct nand_chip *chip)
|
|||
nand_select(self, true);
|
||||
nand_command(self, ONFI_READ_ID);
|
||||
nand_address(self, 0x00);
|
||||
|
||||
nand_read_byte(self, &chip->nc_manf_id);
|
||||
nand_read_byte(self, &chip->nc_dev_id);
|
||||
|
||||
nand_select(self, false);
|
||||
}
|
||||
|
||||
/* read the parameter page. TODO: check CRC! */
|
||||
static void
|
||||
nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
||||
{
|
||||
|
@ -435,20 +476,10 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
|
||||
aprint_normal_dev(self, "vendor: %s, model: %s\n", vendor, model);
|
||||
|
||||
aprint_normal_dev(self,
|
||||
"page size: %u bytes, spare size: %u bytes, block size: %u bytes\n",
|
||||
params.param_pagesize, params.param_sparesize,
|
||||
params.param_blocksize * params.param_pagesize);
|
||||
|
||||
aprint_normal_dev(self,
|
||||
"LUN size: %u blocks, LUNs: %u, total storage size: %u MB\n",
|
||||
params.param_lunsize, params.param_numluns,
|
||||
params.param_blocksize * params.param_pagesize *
|
||||
params.param_lunsize * params.param_numluns / 1024 / 1024);
|
||||
|
||||
/* XXX TODO multiple LUNs */
|
||||
if (__predict_false(params.param_numluns != 1))
|
||||
if (__predict_false(params.param_numluns != 1)) {
|
||||
panic("more than one LUNs are not supported yet!\n");
|
||||
}
|
||||
|
||||
chip->nc_size = params.param_pagesize * params.param_blocksize *
|
||||
params.param_lunsize * params.param_numluns;
|
||||
|
@ -457,17 +488,14 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
chip->nc_block_pages = params.param_blocksize;
|
||||
chip->nc_block_size = params.param_blocksize * params.param_pagesize;
|
||||
chip->nc_spare_size = params.param_sparesize;
|
||||
chip->nc_lun_blocks = params.param_lunsize;
|
||||
chip->nc_num_luns = params.param_numluns;
|
||||
|
||||
/* the lower 4 bits contain the row address cycles */
|
||||
chip->nc_addr_cycles_row = params.param_addr_cycles & 0x07;
|
||||
/* the upper 4 bits contain the column address cycles */
|
||||
chip->nc_addr_cycles_column = (params.param_addr_cycles & ~0x07) >> 4;
|
||||
|
||||
#ifdef NAND_VERBOSE
|
||||
aprint_normal_dev(self, "column cycles: %d, row cycles: %d\n",
|
||||
chip->nc_addr_cycles_column, chip->nc_addr_cycles_row);
|
||||
#endif
|
||||
|
||||
if (params.param_features & ONFI_FEATURE_16BIT)
|
||||
chip->nc_flags |= NC_BUSWIDTH_16;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nand.h,v 1.2 2011/03/05 06:28:29 jruoho Exp $ */
|
||||
/* $NetBSD: nand.h,v 1.3 2011/03/09 10:05:08 ahoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010 Department of Software Engineering,
|
||||
|
@ -64,7 +64,7 @@ bool nand_isbad(device_t, flash_addr_t);
|
|||
void nand_markbad(device_t, size_t);
|
||||
|
||||
int nand_read_page(device_t, size_t, uint8_t *);
|
||||
int nand_read_oob(device_t self, size_t page, void *oob);
|
||||
int nand_read_oob(device_t, size_t, void *);
|
||||
|
||||
/*
|
||||
* default functions for driver development
|
||||
|
@ -154,6 +154,7 @@ struct nand_ecc {
|
|||
* about the NAND chip.
|
||||
*/
|
||||
struct nand_chip {
|
||||
struct nand_ecc *nc_ecc; /* ecc information */
|
||||
uint8_t *nc_oob_cache; /* buffer for oob cache */
|
||||
uint8_t *nc_page_cache; /* buffer for page cache */
|
||||
uint8_t *nc_ecc_cache;
|
||||
|
@ -162,19 +163,20 @@ struct nand_chip {
|
|||
size_t nc_block_pages; /* block size in pages */
|
||||
size_t nc_block_size; /* block size in bytes */
|
||||
size_t nc_spare_size; /* spare (oob) size in bytes */
|
||||
uint32_t nc_lun_blocks; /* LUN size in blocks */
|
||||
uint32_t nc_flags; /* bitfield flags */
|
||||
uint32_t nc_quirks; /* bitfield quirks */
|
||||
unsigned int nc_page_shift; /* page shift for page alignment */
|
||||
unsigned int nc_page_mask; /* page mask for page alignment */
|
||||
unsigned int nc_block_shift; /* write shift */
|
||||
unsigned int nc_block_mask; /* write mask */
|
||||
uint8_t nc_num_luns; /* number of LUNs */
|
||||
uint8_t nc_manf_id; /* manufacturer id */
|
||||
uint8_t nc_dev_id; /* device id */
|
||||
uint8_t nc_addr_cycles_row; /* row cycles for addressing */
|
||||
uint8_t nc_addr_cycles_column; /* column cycles for addressing */
|
||||
uint8_t nc_badmarker_offs; /* offset for marking bad blocks */
|
||||
|
||||
struct nand_ecc *nc_ecc;
|
||||
bool nc_isonfi; /* if the device is onfi compliant */
|
||||
};
|
||||
|
||||
struct nand_write_cache {
|
||||
|
@ -450,6 +452,13 @@ struct nand_manufacturer {
|
|||
|
||||
extern const struct nand_manufacturer nand_mfrs[];
|
||||
|
||||
/*
|
||||
* Manufacturer specific parameter functions
|
||||
*/
|
||||
int nand_read_parameters_micron(device_t, struct nand_chip *);
|
||||
|
||||
/* debug inlines */
|
||||
|
||||
static inline void
|
||||
nand_dump_data(const char *name, void *data, size_t len)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*-
|
||||
* Copyright (c) 2011 Department of Software Engineering,
|
||||
* University of Szeged, Hungary
|
||||
* Copyright (c) 2011 Adam Hoka <ahoka@NetBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by the Department of Software Engineering, University of Szeged, Hungary
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device specific functions for legacy Micron NAND chips
|
||||
*
|
||||
* Currently supported:
|
||||
* MT29F2G08AACWP, MT29F4G08BACWP, MT29F8G08FACWP
|
||||
*/
|
||||
|
||||
#include "nand.h"
|
||||
#include "onfi.h"
|
||||
|
||||
int
|
||||
nand_read_parameters_micron(device_t self, struct nand_chip *chip)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
KASSERT(chip->nc_manf_id == NAND_MFR_MICRON);
|
||||
|
||||
nand_select(self, true);
|
||||
nand_command(self, ONFI_READ_ID);
|
||||
nand_address(self, 0x00);
|
||||
|
||||
switch (chip->nc_manf_id) {
|
||||
/* three dummy reads */
|
||||
nand_read_byte(self, &byte); /* vendor */
|
||||
nand_read_byte(self, &byte); /* device */
|
||||
nand_read_byte(self, &byte); /* unused */
|
||||
|
||||
/* this is the interesting one */
|
||||
nand_read_byte(self, &byte);
|
||||
/* TODO actually get info */
|
||||
nand_select(self, false);
|
||||
return 1;
|
||||
|
||||
break;
|
||||
default:
|
||||
nand_select(self, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
chip->nc_num_luns = 1;
|
||||
chip->nc_lun_blocks = chip->nc_size / chip->nc_block_size;
|
||||
|
||||
nand_select(self, false);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue