Add support for redifining page read and program functions by drivers.
Some controllers implement read/write in one step, so this is required to support those.
This commit is contained in:
parent
2feaef06e3
commit
c68f5a8379
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.nand,v 1.2 2011/03/09 10:05:08 ahoka Exp $
|
||||
# $NetBSD: files.nand,v 1.3 2011/03/27 13:33:04 ahoka Exp $
|
||||
|
||||
define nandbus { }
|
||||
|
||||
|
@ -15,3 +15,5 @@ defpseudodev nandemulator: nandbus
|
|||
file dev/nand/nandemulator.c nandemulator
|
||||
|
||||
defflag opt_nand.h NAND_BBT
|
||||
defflag opt_nand.h NAND_DEBUG
|
||||
defflag opt_nand.h NAND_VERBOSE
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nand.c,v 1.5 2011/03/09 12:33:59 ahoka Exp $ */
|
||||
/* $NetBSD: nand.c,v 1.6 2011/03/27 13:33:04 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.5 2011/03/09 12:33:59 ahoka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.6 2011/03/27 13:33:04 ahoka Exp $");
|
||||
|
||||
#include "locators.h"
|
||||
|
||||
|
@ -63,9 +63,7 @@ int nand_print(void *, const char *);
|
|||
static int nand_search(device_t, cfdata_t, const int *, void *);
|
||||
static void nand_address_row(device_t, size_t);
|
||||
static void nand_address_column(device_t, size_t, size_t);
|
||||
static void nand_readid(device_t, struct nand_chip *);
|
||||
static void nand_read_parameter_page(device_t, struct nand_chip *);
|
||||
static const char *nand_midtoname(int);
|
||||
static int nand_fill_chip_structure(device_t, struct nand_chip *);
|
||||
static int nand_scan_media(device_t, struct nand_chip *);
|
||||
static bool nand_check_wp(device_t);
|
||||
|
||||
|
@ -79,6 +77,7 @@ int nanddebug = NAND_DEBUG;
|
|||
int nand_cachesync_timeout = 1;
|
||||
int nand_cachesync_nodenum;
|
||||
|
||||
#ifdef NAND_VERBOSE
|
||||
const struct nand_manufacturer nand_mfrs[] = {
|
||||
{ NAND_MFR_AMD, "AMD" },
|
||||
{ NAND_MFR_FUJITSU, "Fujitsu" },
|
||||
|
@ -92,6 +91,22 @@ const struct nand_manufacturer nand_mfrs[] = {
|
|||
{ NAND_MFR_UNKNOWN, "Unknown" }
|
||||
};
|
||||
|
||||
static const char *
|
||||
nand_midtoname(int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nand_mfrs[i].id != 0; i++) {
|
||||
if (nand_mfrs[i].id == id)
|
||||
return nand_mfrs[i].name;
|
||||
}
|
||||
|
||||
KASSERT(nand_mfrs[i].id == 0);
|
||||
|
||||
return nand_mfrs[i].name;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
nand_match(device_t parent, cfdata_t match, void *aux)
|
||||
|
@ -108,7 +123,7 @@ nand_attach(device_t parent, device_t self, void *aux)
|
|||
struct nand_chip *chip = &sc->sc_chip;
|
||||
|
||||
sc->sc_dev = self;
|
||||
sc->nand_dev = parent;
|
||||
sc->controller_dev = parent;
|
||||
sc->nand_if = naa->naa_nand_if;
|
||||
|
||||
aprint_naive("\n");
|
||||
|
@ -238,6 +253,7 @@ nand_print(void *aux, const char *pnp)
|
|||
return UNCONF;
|
||||
}
|
||||
|
||||
/* ask for a nand driver to attach to the controller */
|
||||
device_t
|
||||
nand_attach_mi(struct nand_interface *nand_if, device_t parent)
|
||||
{
|
||||
|
@ -245,23 +261,50 @@ nand_attach_mi(struct nand_interface *nand_if, device_t parent)
|
|||
|
||||
KASSERT(nand_if != NULL);
|
||||
|
||||
/* fill the defaults if we have null pointers */
|
||||
if (nand_if->program_page == NULL) {
|
||||
nand_if->program_page = &nand_default_program_page;
|
||||
}
|
||||
|
||||
if (nand_if->read_page == NULL) {
|
||||
nand_if->read_page = &nand_default_read_page;
|
||||
}
|
||||
|
||||
arg.naa_nand_if = nand_if;
|
||||
return config_found_ia(parent, "nandbus", &arg, nand_print);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nand_midtoname(int id)
|
||||
/* default everything to reasonable values, to ease future api changes */
|
||||
void
|
||||
nand_init_interface(struct nand_interface *interface)
|
||||
{
|
||||
int i;
|
||||
interface->select = &nand_default_select;
|
||||
interface->command = NULL;
|
||||
interface->address = NULL;
|
||||
interface->read_buf_byte = NULL;
|
||||
interface->read_buf_word = NULL;
|
||||
interface->read_byte = NULL;
|
||||
interface->read_word = NULL;
|
||||
interface->write_buf_byte = NULL;
|
||||
interface->write_buf_word = NULL;
|
||||
interface->write_byte = NULL;
|
||||
interface->write_word = NULL;
|
||||
interface->busy = NULL;
|
||||
|
||||
for (i = 0; nand_mfrs[i].id != 0; i++) {
|
||||
if (nand_mfrs[i].id == id)
|
||||
return nand_mfrs[i].name;
|
||||
}
|
||||
/*-
|
||||
* most drivers dont want to change this, but some implement
|
||||
* read/program in one step
|
||||
*/
|
||||
interface->program_page = &nand_default_program_page;
|
||||
interface->read_page = &nand_default_read_page;
|
||||
|
||||
KASSERT(nand_mfrs[i].id == 0);
|
||||
|
||||
return nand_mfrs[i].name;
|
||||
/* default to soft ecc, that should work everywhere */
|
||||
interface->ecc_compute = &nand_default_ecc_compute;
|
||||
interface->ecc_correct = &nand_default_ecc_correct;
|
||||
interface->ecc_prepare = NULL;
|
||||
interface->ecc.necc_code_size = 3;
|
||||
interface->ecc.necc_block_size = 256;
|
||||
interface->ecc.necc_type = NAND_ECC_TYPE_SW;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -284,7 +327,7 @@ nand_quirks(device_t self, struct nand_chip *chip)
|
|||
#endif
|
||||
|
||||
static int
|
||||
nand_read_legacy_parameters(device_t self, struct nand_chip *chip)
|
||||
nand_fill_chip_structure_legacy(device_t self, struct nand_chip *chip)
|
||||
{
|
||||
switch (chip->nc_manf_id) {
|
||||
case NAND_MFR_MICRON:
|
||||
|
@ -327,9 +370,9 @@ nand_scan_media(device_t self, struct nand_chip *chip)
|
|||
|
||||
aprint_normal(": Legacy NAND Flash\n");
|
||||
|
||||
nand_readid(self, chip);
|
||||
nand_read_id(self, &chip->nc_manf_id, &chip->nc_dev_id);
|
||||
|
||||
if (nand_read_legacy_parameters(self, chip)) {
|
||||
if (nand_fill_chip_structure_legacy(self, chip)) {
|
||||
aprint_error_dev(self,
|
||||
"can't read device parameters for legacy chip\n");
|
||||
return 1;
|
||||
|
@ -339,8 +382,14 @@ nand_scan_media(device_t self, struct nand_chip *chip)
|
|||
|
||||
aprint_normal(": ONFI NAND Flash\n");
|
||||
|
||||
nand_readid(self, chip);
|
||||
nand_read_parameter_page(self, chip);
|
||||
nand_read_id(self, &chip->nc_manf_id, &chip->nc_dev_id);
|
||||
|
||||
if (nand_fill_chip_structure(self, chip)) {
|
||||
aprint_error_dev(self,
|
||||
"can't read device parameters\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NAND_VERBOSE
|
||||
|
@ -425,29 +474,30 @@ nand_scan_media(device_t self, struct nand_chip *chip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nand_readid(device_t self, struct nand_chip *chip)
|
||||
void
|
||||
nand_read_id(device_t self, uint8_t *manf, uint8_t *dev)
|
||||
{
|
||||
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_read_byte(self, manf);
|
||||
nand_read_byte(self, dev);
|
||||
|
||||
nand_select(self, false);
|
||||
}
|
||||
|
||||
static void
|
||||
nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
||||
int
|
||||
nand_read_parameter_page(device_t self, struct onfi_parameter_page *params)
|
||||
{
|
||||
struct onfi_parameter_page params;
|
||||
uint8_t *bufp;
|
||||
uint8_t vendor[13], model[21];
|
||||
uint16_t crc;
|
||||
int i;
|
||||
int i;//, tries = 0;
|
||||
|
||||
KASSERT(sizeof(params) == 256);
|
||||
KASSERT(sizeof(*params) == 256);
|
||||
|
||||
//read_params:
|
||||
// tries++;
|
||||
|
||||
nand_select(self, true);
|
||||
nand_command(self, ONFI_READ_PARAMETER_PAGE);
|
||||
|
@ -455,7 +505,10 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
|
||||
nand_busy(self);
|
||||
|
||||
bufp = (uint8_t *)¶ms;
|
||||
/* TODO check the signature if it contains at least 2 letters */
|
||||
|
||||
bufp = (uint8_t *)params;
|
||||
/* XXX why i am not using read_buf? */
|
||||
for (i = 0; i < 256; i++) {
|
||||
nand_read_byte(self, &bufp[i]);
|
||||
}
|
||||
|
@ -464,9 +517,24 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
/* validate the parameter page with the crc */
|
||||
crc = nand_crc16(bufp, 254);
|
||||
|
||||
if (crc != params.param_integrity_crc) {
|
||||
if (crc != params->param_integrity_crc) {
|
||||
aprint_error_dev(self, "parameter page crc check failed\n");
|
||||
/* TODO: we should read the next parameter page copy */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nand_fill_chip_structure(device_t self, struct nand_chip *chip)
|
||||
{
|
||||
struct onfi_parameter_page params;
|
||||
uint8_t vendor[13], model[21];
|
||||
int i;
|
||||
|
||||
if (nand_read_parameter_page(self, ¶ms)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* strip manufacturer and model string */
|
||||
|
@ -480,8 +548,11 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
aprint_normal_dev(self, "vendor: %s, model: %s\n", vendor, model);
|
||||
|
||||
/* XXX TODO multiple LUNs */
|
||||
if (__predict_false(params.param_numluns != 1)) {
|
||||
panic("more than one LUNs are not supported yet!\n");
|
||||
if (params.param_numluns != 1) {
|
||||
aprint_error_dev(self,
|
||||
"more than one LUNs are not supported yet!\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
chip->nc_size = params.param_pagesize * params.param_blocksize *
|
||||
|
@ -504,6 +575,8 @@ nand_read_parameter_page(device_t self, struct nand_chip *chip)
|
|||
|
||||
if (params.param_features & ONFI_FEATURE_EXTENDED_PARAM)
|
||||
chip->nc_flags |= NC_EXTENDED_PARAM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
|
@ -583,9 +656,9 @@ nand_prepare_read(device_t self, flash_addr_t row, flash_addr_t column)
|
|||
nand_busy(self);
|
||||
}
|
||||
|
||||
/* read a page with ecc correction */
|
||||
/* read a page with ecc correction, default implementation */
|
||||
int
|
||||
nand_read_page(device_t self, size_t offset, uint8_t *data)
|
||||
nand_default_read_page(device_t self, size_t offset, uint8_t *data)
|
||||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
struct nand_chip *chip = &sc->sc_chip;
|
||||
|
@ -672,8 +745,8 @@ nand_read_page(device_t self, size_t offset, uint8_t *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nand_program_page(device_t self, size_t page, const uint8_t *data)
|
||||
int
|
||||
nand_default_program_page(device_t self, size_t page, const uint8_t *data)
|
||||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
struct nand_chip *chip = &sc->sc_chip;
|
||||
|
@ -739,8 +812,9 @@ nand_program_page(device_t self, size_t page, const uint8_t *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* read the OOB of a page */
|
||||
int
|
||||
nand_read_oob(device_t self, size_t page, void *oob)
|
||||
nand_read_oob(device_t self, size_t page, uint8_t *oob)
|
||||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
struct nand_chip *chip = &sc->sc_chip;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nand.h,v 1.3 2011/03/09 10:05:08 ahoka Exp $ */
|
||||
/* $NetBSD: nand.h,v 1.4 2011/03/27 13:33:04 ahoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010 Department of Software Engineering,
|
||||
|
@ -41,52 +41,9 @@
|
|||
#include <sys/buf.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <dev/nand/onfi.h>
|
||||
#include <dev/flash/flash.h>
|
||||
|
||||
/* flash interface implementation */
|
||||
int nand_flash_isbad(device_t, uint64_t);
|
||||
int nand_flash_markbad(device_t, uint64_t);
|
||||
int nand_flash_write(device_t, off_t, size_t, size_t *, const u_char *);
|
||||
int nand_flash_read(device_t, off_t, size_t, size_t *, uint8_t *);
|
||||
int nand_flash_erase(device_t, struct flash_erase_instruction *);
|
||||
|
||||
/* nand specific functions */
|
||||
int nand_erase_block(device_t, size_t);
|
||||
|
||||
int nand_io_submit(device_t, struct buf *);
|
||||
void nand_sync_thread(void *);
|
||||
int nand_sync_thread_start(device_t);
|
||||
void nand_sync_thread_stop(device_t);
|
||||
|
||||
bool nand_isfactorybad(device_t, flash_addr_t);
|
||||
bool nand_iswornoutbad(device_t, flash_addr_t);
|
||||
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, size_t, void *);
|
||||
|
||||
/*
|
||||
* default functions for driver development
|
||||
*/
|
||||
void nand_default_select(device_t, bool);
|
||||
int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
|
||||
int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
|
||||
const uint8_t *);
|
||||
|
||||
static inline void nand_busy(device_t);
|
||||
static inline void nand_select(device_t, bool);
|
||||
static inline void nand_command(device_t, uint8_t);
|
||||
static inline void nand_address(device_t, uint32_t);
|
||||
static inline void nand_read_buf_byte(device_t, void *, size_t);
|
||||
static inline void nand_read_buf_word(device_t, void *, size_t);
|
||||
static inline void nand_read_byte(device_t, uint8_t *);
|
||||
static inline void nand_write_buf_byte(device_t, const void *, size_t);
|
||||
static inline void nand_write_buf_word(device_t, const void *, size_t);
|
||||
//static inline bool nand_block_isbad(device_t, off_t);
|
||||
//static inline void nand_block_markbad(device_t, off_t);
|
||||
//static inline bool nand_isbusy(device_t);
|
||||
|
||||
//#define NAND_DEBUG 1
|
||||
#ifdef NAND_DEBUG
|
||||
#define DPRINTF(x) if (nanddebug) printf x
|
||||
|
@ -96,7 +53,7 @@ static inline void nand_write_buf_word(device_t, const void *, size_t);
|
|||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define NAND_VERBOSE
|
||||
//#define NAND_VERBOSE
|
||||
|
||||
/* same as in linux for compatibility */
|
||||
enum {
|
||||
|
@ -192,7 +149,7 @@ struct nand_write_cache {
|
|||
/* driver softc for nand */
|
||||
struct nand_softc {
|
||||
device_t sc_dev;
|
||||
device_t nand_dev;
|
||||
device_t controller_dev;
|
||||
struct nand_interface *nand_if;
|
||||
void *nand_softc;
|
||||
struct nand_chip sc_chip;
|
||||
|
@ -213,7 +170,8 @@ struct nand_softc {
|
|||
/* structure holding the nand api */
|
||||
struct nand_interface
|
||||
{
|
||||
void (*select) (device_t, bool);
|
||||
/* basic nand controller commands */
|
||||
void (*select) (device_t, bool); /* optional */
|
||||
void (*command) (device_t, uint8_t);
|
||||
void (*address) (device_t, uint8_t);
|
||||
void (*read_buf_byte) (device_t, void *, size_t);
|
||||
|
@ -226,12 +184,17 @@ struct nand_interface
|
|||
void (*write_word) (device_t, uint16_t);
|
||||
void (*busy) (device_t);
|
||||
|
||||
/* "smart" controllers may override read/program functions */
|
||||
int (*read_page) (device_t, size_t, uint8_t *); /* optional */
|
||||
int (*program_page) (device_t, size_t, const uint8_t *); /* optional */
|
||||
|
||||
/* functions specific to ecc computation */
|
||||
int (*ecc_prepare)(device_t, int);
|
||||
int (*ecc_prepare)(device_t, int); /* optional */
|
||||
int (*ecc_compute)(device_t, const uint8_t *, uint8_t *);
|
||||
int (*ecc_correct)(device_t, uint8_t *, const uint8_t *,
|
||||
const uint8_t *);
|
||||
|
||||
/* information for the ecc engine */
|
||||
struct nand_ecc ecc;
|
||||
|
||||
/* flash partition information */
|
||||
|
@ -244,23 +207,21 @@ struct nand_attach_args {
|
|||
struct nand_interface *naa_nand_if;
|
||||
};
|
||||
|
||||
device_t nand_attach_mi(struct nand_interface *nand_if, device_t dev);
|
||||
|
||||
static inline void
|
||||
nand_busy(device_t device)
|
||||
{
|
||||
struct nand_softc *sc = device_private(device);
|
||||
|
||||
KASSERT(sc->nand_if->select != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->select(sc->nand_dev, true);
|
||||
sc->nand_if->select(sc->controller_dev, true);
|
||||
|
||||
if (sc->nand_if->busy != NULL) {
|
||||
sc->nand_if->busy(sc->nand_dev);
|
||||
sc->nand_if->busy(sc->controller_dev);
|
||||
}
|
||||
|
||||
sc->nand_if->select(sc->nand_dev, false);
|
||||
sc->nand_if->select(sc->controller_dev, false);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -269,9 +230,9 @@ nand_select(device_t self, bool enable)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->select != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->select(sc->nand_dev, enable);
|
||||
sc->nand_if->select(sc->controller_dev, enable);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -280,9 +241,9 @@ nand_address(device_t self, uint32_t address)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->address != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->address(sc->nand_dev, address);
|
||||
sc->nand_if->address(sc->controller_dev, address);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -291,9 +252,9 @@ nand_command(device_t self, uint8_t command)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->command != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->command(sc->nand_dev, command);
|
||||
sc->nand_if->command(sc->controller_dev, command);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -302,9 +263,9 @@ nand_read_byte(device_t self, uint8_t *data)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->read_byte != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->read_byte(sc->nand_dev, data);
|
||||
sc->nand_if->read_byte(sc->controller_dev, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -313,9 +274,9 @@ nand_write_byte(device_t self, uint8_t data)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->write_byte != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->write_byte(sc->nand_dev, data);
|
||||
sc->nand_if->write_byte(sc->controller_dev, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -324,9 +285,9 @@ nand_read_word(device_t self, uint16_t *data)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->read_word != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->read_word(sc->nand_dev, data);
|
||||
sc->nand_if->read_word(sc->controller_dev, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -335,9 +296,9 @@ nand_write_word(device_t self, uint16_t data)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->write_word != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->write_word(sc->nand_dev, data);
|
||||
sc->nand_if->write_word(sc->controller_dev, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -346,9 +307,9 @@ nand_read_buf_byte(device_t self, void *buf, size_t size)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->read_buf_byte != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->read_buf_byte(sc->nand_dev, buf, size);
|
||||
sc->nand_if->read_buf_byte(sc->controller_dev, buf, size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -357,9 +318,9 @@ nand_read_buf_word(device_t self, void *buf, size_t size)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->read_buf_word != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->read_buf_word(sc->nand_dev, buf, size);
|
||||
sc->nand_if->read_buf_word(sc->controller_dev, buf, size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -368,9 +329,9 @@ nand_write_buf_byte(device_t self, const void *buf, size_t size)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->write_buf_byte != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->write_buf_byte(sc->nand_dev, buf, size);
|
||||
sc->nand_if->write_buf_byte(sc->controller_dev, buf, size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -379,9 +340,9 @@ nand_write_buf_word(device_t self, const void *buf, size_t size)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->write_buf_word != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->write_buf_word(sc->nand_dev, buf, size);
|
||||
sc->nand_if->write_buf_word(sc->controller_dev, buf, size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -391,9 +352,9 @@ nand_ecc_correct(device_t self, uint8_t *data, const uint8_t *oldcode,
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->ecc_correct != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
return sc->nand_if->ecc_correct(sc->nand_dev, data, oldcode, newcode);
|
||||
return sc->nand_if->ecc_correct(sc->controller_dev, data, oldcode, newcode);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -402,9 +363,9 @@ nand_ecc_compute(device_t self, const uint8_t *data, uint8_t *code)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->ecc_compute != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
sc->nand_if->ecc_compute(sc->nand_dev, data, code);
|
||||
sc->nand_if->ecc_compute(sc->controller_dev, data, code);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -412,10 +373,30 @@ nand_ecc_prepare(device_t self, int mode)
|
|||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
if (sc->nand_if->ecc_prepare != NULL)
|
||||
sc->nand_if->ecc_prepare(sc->nand_dev, mode);
|
||||
sc->nand_if->ecc_prepare(sc->controller_dev, mode);
|
||||
}
|
||||
|
||||
static inline int
|
||||
nand_program_page(device_t self, size_t offset, const uint8_t *data)
|
||||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->program_page != NULL);
|
||||
|
||||
return sc->nand_if->program_page(self, offset, data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
nand_read_page(device_t self, size_t offset, uint8_t *data)
|
||||
{
|
||||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->read_page != NULL);
|
||||
|
||||
return sc->nand_if->read_page(self, offset, data);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -425,9 +406,9 @@ nand_block_isbad(device_t self, off_t block)
|
|||
struct nand_softc *sc = device_private(self);
|
||||
|
||||
KASSERT(sc->nand_if->block_isbad != NULL);
|
||||
KASSERT(sc->nand_dev != NULL);
|
||||
KASSERT(sc->controller_dev != NULL);
|
||||
|
||||
return sc->nand_if->block_isbad(sc->nand_dev, block);
|
||||
return sc->nand_if->block_isbad(sc->controller_dev, block);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -473,4 +454,58 @@ nand_dump_data(const char *name, void *data, size_t len)
|
|||
printf("\n--------------\n");
|
||||
}
|
||||
|
||||
/* flash interface implementation */
|
||||
int nand_flash_isbad(device_t, uint64_t);
|
||||
int nand_flash_markbad(device_t, uint64_t);
|
||||
int nand_flash_write(device_t, off_t, size_t, size_t *, const u_char *);
|
||||
int nand_flash_read(device_t, off_t, size_t, size_t *, uint8_t *);
|
||||
int nand_flash_erase(device_t, struct flash_erase_instruction *);
|
||||
|
||||
/* nand specific functions */
|
||||
int nand_erase_block(device_t, size_t);
|
||||
|
||||
int nand_io_submit(device_t, struct buf *);
|
||||
void nand_sync_thread(void *);
|
||||
int nand_sync_thread_start(device_t);
|
||||
void nand_sync_thread_stop(device_t);
|
||||
|
||||
bool nand_isfactorybad(device_t, flash_addr_t);
|
||||
bool nand_iswornoutbad(device_t, flash_addr_t);
|
||||
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, size_t, uint8_t *);
|
||||
//int nand_program_page(device_t, size_t, const uint8_t *);
|
||||
|
||||
device_t nand_attach_mi(struct nand_interface *, device_t);
|
||||
void nand_init_interface(struct nand_interface *);
|
||||
|
||||
/* controller drivers may use these functions to get info about the chip */
|
||||
void nand_read_id(device_t, uint8_t *, uint8_t *);
|
||||
int nand_read_parameter_page(device_t, struct onfi_parameter_page *);
|
||||
|
||||
/*
|
||||
* default functions for driver development
|
||||
*/
|
||||
void nand_default_select(device_t, bool);
|
||||
int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
|
||||
int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
|
||||
const uint8_t *);
|
||||
int nand_default_read_page(device_t, size_t, uint8_t *);
|
||||
int nand_default_program_page(device_t, size_t, const uint8_t *);
|
||||
|
||||
static inline void nand_busy(device_t);
|
||||
static inline void nand_select(device_t, bool);
|
||||
static inline void nand_command(device_t, uint8_t);
|
||||
static inline void nand_address(device_t, uint32_t);
|
||||
static inline void nand_read_buf_byte(device_t, void *, size_t);
|
||||
static inline void nand_read_buf_word(device_t, void *, size_t);
|
||||
static inline void nand_read_byte(device_t, uint8_t *);
|
||||
static inline void nand_write_buf_byte(device_t, const void *, size_t);
|
||||
static inline void nand_write_buf_word(device_t, const void *, size_t);
|
||||
//static inline bool nand_block_isbad(device_t, off_t);
|
||||
//static inline void nand_block_markbad(device_t, off_t);
|
||||
//static inline bool nand_isbusy(device_t);
|
||||
|
||||
#endif /* _NAND_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nandemulator.c,v 1.1 2011/02/26 18:07:31 ahoka Exp $ */
|
||||
/* $NetBSD: nandemulator.c,v 1.2 2011/03/27 13:33:04 ahoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011 Department of Software Engineering,
|
||||
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: nandemulator.c,v 1.1 2011/02/26 18:07:31 ahoka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: nandemulator.c,v 1.2 2011/03/27 13:33:04 ahoka Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/device.h>
|
||||
|
@ -182,7 +182,8 @@ nandemulator_attach(device_t parent, device_t self, void *aux)
|
|||
|
||||
sc->sc_dev = self;
|
||||
|
||||
sc->sc_nand_if.select = &nand_default_select;
|
||||
nand_init_interface(&sc->sc_nand_if);
|
||||
|
||||
sc->sc_nand_if.command = &nandemulator_command;
|
||||
sc->sc_nand_if.address = &nandemulator_address;
|
||||
sc->sc_nand_if.read_buf_byte = &nandemulator_read_buf_byte;
|
||||
|
@ -195,12 +196,8 @@ nandemulator_attach(device_t parent, device_t self, void *aux)
|
|||
sc->sc_nand_if.write_word = &nandemulator_write_word;
|
||||
sc->sc_nand_if.busy = &nandemulator_busy;
|
||||
|
||||
sc->sc_nand_if.ecc_compute = &nand_default_ecc_compute;
|
||||
sc->sc_nand_if.ecc_correct = &nand_default_ecc_correct;
|
||||
sc->sc_nand_if.ecc_prepare = NULL;
|
||||
sc->sc_nand_if.ecc.necc_code_size = 3;
|
||||
sc->sc_nand_if.ecc.necc_block_size = 256;
|
||||
sc->sc_nand_if.ecc.necc_type = NAND_ECC_TYPE_SW;
|
||||
|
||||
if (!pmf_device_register1(sc->sc_dev, NULL, NULL, NULL))
|
||||
aprint_error_dev(sc->sc_dev,
|
||||
|
|
Loading…
Reference in New Issue