Commit 05f78359 authored by Uwe Kleine-König's avatar Uwe Kleine-König Committed by Brian Norris

mtd: nand: don't use {read,write}_buf for 8-bit transfers

According to the Open NAND Flash Interface Specification (ONFI) Revision
3.1 "Parameters are always transferred on the lower 8-bits of the data
bus." for the Get Features and Set Features commands.

So using read_buf and write_buf is wrong for 16-bit wide nand chips as
they use I/O[15:0]. The Get Features command is easily fixed using 4
times the read_byte callback. For Set Features implement a new
overwritable callback "write_byte". Still I expect the default to work
just fine for all controllers and making it overwriteable was just done
for symmetry.
Signed-off-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
[Brian: fixed warning]
Tested-by: default avatarBrian Norris <computersforpeace@gmail.com>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent e2e6b7b7
...@@ -203,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) ...@@ -203,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
} }
} }
/**
* nand_write_byte - [DEFAULT] write single byte to chip
* @mtd: MTD device structure
* @byte: value to write
*
* Default function to write a byte to I/O[7:0]
*/
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *chip = mtd->priv;
chip->write_buf(mtd, &byte, 1);
}
/**
* nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
* @mtd: MTD device structure
* @byte: value to write
*
* Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
*/
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *chip = mtd->priv;
uint16_t word = byte;
/*
* It's not entirely clear what should happen to I/O[15:8] when writing
* a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
*
* When the host supports a 16-bit bus width, only data is
* transferred at the 16-bit width. All address and command line
* transfers shall use only the lower 8-bits of the data bus. During
* command transfers, the host may place any value on the upper
* 8-bits of the data bus. During address transfers, the host shall
* set the upper 8-bits of the data bus to 00h.
*
* One user of the write_byte callback is nand_onfi_set_features. The
* four parameters are specified to be written to I/O[7:0], but this is
* neither an address nor a command transfer. Let's assume a 0 on the
* upper I/O lines is OK.
*/
chip->write_buf(mtd, (uint8_t *)&word, 2);
}
/** /**
* nand_write_buf - [DEFAULT] write buffer to chip * nand_write_buf - [DEFAULT] write buffer to chip
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -2769,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2769,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param) int addr, uint8_t *subfeature_param)
{ {
int status; int status;
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(le16_to_cpu(chip->onfi_params.opt_cmd)
...@@ -2776,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2776,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
return -EINVAL; return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, subfeature_param[i]);
status = chip->waitfunc(mtd, chip); status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL) if (status & NAND_STATUS_FAIL)
return -EIO; return -EIO;
...@@ -2793,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2793,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param) int addr, uint8_t *subfeature_param)
{ {
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES)) & ONFI_OPT_CMD_SET_GET_FEATURES))
...@@ -2802,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2802,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0; return 0;
} }
...@@ -2865,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) ...@@ -2865,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->block_markbad = nand_default_block_markbad; chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf || chip->write_buf == nand_write_buf) if (!chip->write_buf || chip->write_buf == nand_write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->write_byte || chip->write_byte == nand_write_byte)
chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
if (!chip->read_buf || chip->read_buf == nand_read_buf) if (!chip->read_buf || chip->read_buf == nand_read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->scan_bbt) if (!chip->scan_bbt)
......
...@@ -456,6 +456,8 @@ struct nand_buffers { ...@@ -456,6 +456,8 @@ struct nand_buffers {
* flash device. * flash device.
* @read_byte: [REPLACEABLE] read one byte from the chip * @read_byte: [REPLACEABLE] read one byte from the chip
* @read_word: [REPLACEABLE] read one word from the chip * @read_word: [REPLACEABLE] read one word from the chip
* @write_byte: [REPLACEABLE] write a single byte to the chip on the
* low 8 I/O lines
* @write_buf: [REPLACEABLE] write data from the buffer to the chip * @write_buf: [REPLACEABLE] write data from the buffer to the chip
* @read_buf: [REPLACEABLE] read data from the chip into the buffer * @read_buf: [REPLACEABLE] read data from the chip into the buffer
* @select_chip: [REPLACEABLE] select chip nr * @select_chip: [REPLACEABLE] select chip nr
...@@ -548,6 +550,7 @@ struct nand_chip { ...@@ -548,6 +550,7 @@ struct nand_chip {
uint8_t (*read_byte)(struct mtd_info *mtd); uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd);
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip); void (*select_chip)(struct mtd_info *mtd, int chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment