Initial support of driver brcmnand (from kernel 4.18)
Subsystems (5)
cover Initial support of driver brcmnand (from kernel 4.18)
This serie is a RFC to port the support of driver brcmnand from kernel 4.18 to u-boot. I've tried to stay as close as possible to the kernel. In this first port, I haven't ported the support of DMA, it's not mandatory in the first step and it could be added later.
This code has been tested on bcm6838 (mips) and bcm6858 (arm64). This code isn't clean enough to be integrated. I just send this serie to show the code and ask some question.
In the code, I've used "#ifndef __UBOOT__" to show the difference between the kernel code. Is it a good way or is it better to just replace the code ?
I've also added a file with brcmnand_compat.[hc] to compat
function with the kernel (for example platform_get_resource_byname). What is the prefered way to support this function on u-boot ?
- just replace them by other code on u-boot
- just add this function on the brcmnand driver
- share this code for others driver (adding compat file for platform device, ...)
Boris Brezillon (1):
mtd: nand: provide several helpers to do common NAND operations
Brian Norris (1):
mtd: add get/set of_node/flash_node helpers
Marc Gonzalez (1):
mtd: nand: import nand_hw_control_init()
Philippe Reynes (4):
arm: asm: io.h: define readX_relaxed and writeX_relaxed
drivers: nand: brcmnand: add initial support
drivers: nand: brcmnand: add parameter parameter-page-big-endian
drivers: nand: brcmnand: add an option to read the write-protect from
device tree
arch/arm/include/asm/io.h | 15 + drivers/mtd/nand/raw/Kconfig | 19 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/brcmnand/Makefile | 6 + drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c | 124 + drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c | 126 + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2781 +++++++++++++++++++++++ drivers/mtd/nand/raw/brcmnand/brcmnand.h | 63 + drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c | 116 + drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h | 32 + drivers/mtd/nand/raw/nand_base.c | 1013 +++++++-- include/linux/mtd/rawnand.h | 49 + 12 files changed, 4185 insertions(+), 160 deletions(-) create mode 100644 drivers/mtd/nand/raw/brcmnand/Makefile create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.h create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
Signature · 1 line
2.7.4
RFC PATCH 1/7 mtd: add get/set of_node/flash_node helpers
From: Brian Norris <[email protected]>
We are going to begin using the mtd->dev.of_node field for MTD device nodes, so let's add helpers for it. Also, we'll be making some conversions on spi_nor (and nand_chip eventually) too, so get that ready with their own helpers.
--- include/linux/mtd/rawnand.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
include/linux/mtd/rawnand.h +12 -0
@@ -15,6 +15,7 @@#include <config.h> +#include <dm/device.h> #include <linux/compat.h> #include <linux/mtd/mtd.h> #include <linux/mtd/flashchip.h>
@@ -961,6 +962,17 @@ struct nand_chip {void *priv; }; +static inline void nand_set_flash_node (struct nand_chip *chip, +ofnode node) +{ + chip->flash_node =ofnode_to_offset (node); +} + +static inline ofnode nand_get_flash_node (struct nand_chip *chip) +{ +return offset_to_ofnode (chip->flash_node); +} +static inline struct nand_chip *mtd_to_nand (struct mtd_info *mtd) { return container_of(mtd, struct nand_chip, mtd);
Signature · 1 line
2.7.4
RFC PATCH 2/7 mtd: nand: import nand_hw_control_init()
In reply to Philippe ReynesFrom: Marc Gonzalez <[email protected]>
The code to initialize a struct nand_hw_control is duplicated across several drivers. Factorize it using an inline function.
--- include/linux/mtd/rawnand.h | 7 +++++++ 1 file changed, 7 insertions(+)
include/linux/mtd/rawnand.h +7 -0
@@ -499,6 +499,13 @@ struct nand_hw_control {struct nand_chip *active; }; +static inline void nand_hw_control_init (struct nand_hw_control *nfc) +{ + nfc->active =NULL ; +spin_lock_init (&nfc->lock); +init_waitqueue_head (&nfc->wq); +} +/** * struct nand_ecc_step_info - ECC step information of ECC engine * @stepsize: data bytes per ECC step
Signature · 1 line
2.7.4
RFC PATCH 3/7 mtd: nand: provide several helpers to do common NAND operations
In reply to Philippe ReynesFrom: Boris Brezillon <[email protected]>
This is part of the process of removing direct calls to ->cmdfunc() outside of the core in order to introduce a better interface to execute NAND operations.
Here we provide several helpers and make use of them to remove all direct calls to ->cmdfunc(). This way, we can easily modify those helpers to make use of the new ->exec_op() interface when available.
--- drivers/mtd/nand/raw/nand_base.c | 1013 ++++++++++++++++++++++++++++++++------ include/linux/mtd/rawnand.h | 30 ++ 2 files changed, 883 insertions(+), 160 deletions(-)
drivers/mtd/nand/raw/nand_base.c +853 -160
@@ -484,14 +484,19 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)static int nand_check_wp (struct mtd_info *mtd) {struct nand_chip *chip =mtd_to_nand (mtd); +u8 status; +int ret;/* Broken xD cards report WP despite being writable */ if (chip->options &NAND_BROKEN_XD )return 0 ;/* Check the WP bit */ - chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); -return (chip->read_byte (mtd) &NAND_STATUS_WP ) ?0 :1 ; + ret =nand_status_op (chip, &status); +if (ret) +return ret; + +return status &NAND_STATUS_WP ?0 :1 ; }/**
@@ -573,11 +578,18 @@ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) { registerstruct nand_chip *chip =mtd_to_nand (mtd);u32 time_start; +int ret; timeo = (CONFIG_SYS_HZ * timeo) /1000 ; time_start =get_timer (0 );while (get_timer (time_start) < timeo) { -if ((chip->read_byte (mtd) &NAND_STATUS_READY )) +u8 status; + + ret =nand_read_data_op (chip, &status,sizeof (status), true); +if (ret) +return ; + +if (status &NAND_STATUS_READY )break ;WATCHDOG_RESET (); }
@@ -849,7 +861,15 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,if (chip->dev_ready (mtd))break ; }else { -if (chip->read_byte (mtd) &NAND_STATUS_READY ) +int ret; +u8 status; + + ret =nand_read_data_op (chip, &status,sizeof (status), + true); +if (ret) +return ; + +if (status &NAND_STATUS_READY )break ; }mdelay (1 );
@@ -865,8 +885,9 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,*/ static int nand_wait (struct mtd_info *mtd,struct nand_chip *chip) { -int status;unsigned long timeo =400 ; +u8 status; +int ret;led_trigger_event (nand_led_trigger,LED_FULL );
@@ -876,7 +897,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)*/ ndelay (100 ); - chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); + ret =nand_status_op (chip,NULL ); +if (ret) +return ret;u32 timer = (CONFIG_SYS_HZ * timeo) /1000 ;u32 time_start;
@@ -887,13 +910,21 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)if (chip->dev_ready (mtd))break ; }else { -if (chip->read_byte (mtd) &NAND_STATUS_READY ) + ret =nand_read_data_op (chip, &status, +sizeof (status), true); +if (ret) +return ret; + +if (status &NAND_STATUS_READY )break ; } }led_trigger_event (nand_led_trigger,LED_OFF ); - status = (int )chip->read_byte (mtd); + ret =nand_read_data_op (chip, &status,sizeof (status), true); +if (ret) +return ret; +/* This can happen if in case of timeout or buggy dev_ready */ WARN_ON (!(status &NAND_STATUS_READY ));return status;
@@ -1046,6 +1077,516 @@ static void __maybe_unused nand_release_data_interface(struct nand_chip *chip) }/** +* nand_read_page_op - Do a READ PAGE operation +* @chip: The NAND chip +* @page: page to read +* @offset_in_page: offset within the page +* @buf: buffer used to store the data +* @len: length of the buffer +* +* This function issues a READ PAGE operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_read_page_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,void *buf,unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (len && !buf) +return -EINVAL ; + +if (offset_in_page + len > mtd->writesize + mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_READ0 , offset_in_page, page); +if (len) + chip->read_buf (mtd, buf, len); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_read_page_op); + +/** +* nand_read_param_page_op - Do a READ PARAMETER PAGE operation +* @chip: The NAND chip +* @page: parameter page to read +* @buf: buffer used to store the data +* @len: length of the buffer +* +* This function issues a READ PARAMETER PAGE operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +static int nand_read_param_page_op (struct nand_chip *chip,u8 page,void *buf, +unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +unsigned int i; +u8 *p = buf; + +if (len && !buf) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_PARAM , page,-1 ); +for (i =0 ; i < len; i++) + p[i] = chip->read_byte (mtd); + +return 0 ; +} + +/** +* nand_change_read_column_op - Do a CHANGE READ COLUMN operation +* @chip: The NAND chip +* @offset_in_page: offset within the page +* @buf: buffer used to store the data +* @len: length of the buffer +* @force_8bit: force 8-bit bus access +* +* This function issues a CHANGE READ COLUMN operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_change_read_column_op (struct nand_chip *chip, +unsigned int offset_in_page,void *buf, +unsigned int len,bool force_8bit) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (len && !buf) +return -EINVAL ; + +if (offset_in_page + len > mtd->writesize + mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_RNDOUT , offset_in_page,-1 ); +if (len) + chip->read_buf (mtd, buf, len); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_change_read_column_op); + +/** +* nand_read_oob_op - Do a READ OOB operation +* @chip: The NAND chip +* @page: page to read +* @offset_in_oob: offset within the OOB area +* @buf: buffer used to store the data +* @len: length of the buffer +* +* This function issues a READ OOB operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_read_oob_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_oob,void *buf,unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (len && !buf) +return -EINVAL ; + +if (offset_in_oob + len > mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_READOOB , offset_in_oob, page); +if (len) + chip->read_buf (mtd, buf, len); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_read_oob_op); + +/** +* nand_prog_page_begin_op - starts a PROG PAGE operation +* @chip: The NAND chip +* @page: page to write +* @offset_in_page: offset within the page +* @buf: buffer containing the data to write to the page +* @len: length of the buffer +* +* This function issues the first half of a PROG PAGE operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_prog_page_begin_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,const void *buf, +unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (len && !buf) +return -EINVAL ; + +if (offset_in_page + len > mtd->writesize + mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_SEQIN , offset_in_page, page); + +if (buf) + chip->write_buf (mtd, buf, len); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_prog_page_begin_op); + +/** +* nand_prog_page_end_op - ends a PROG PAGE operation +* @chip: The NAND chip +* +* This function issues the second half of a PROG PAGE operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_prog_page_end_op (struct nand_chip *chip) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +int status; + + chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); + + status = chip->waitfunc (mtd, chip); +if (status &NAND_STATUS_FAIL ) +return -EIO ; + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_prog_page_end_op); + +/** +* nand_prog_page_op - Do a full PROG PAGE operation +* @chip: The NAND chip +* @page: page to write +* @offset_in_page: offset within the page +* @buf: buffer containing the data to write to the page +* @len: length of the buffer +* +* This function issues a full PROG PAGE operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_prog_page_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,const void *buf, +unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +int status; + +if (!len || !buf) +return -EINVAL ; + +if (offset_in_page + len > mtd->writesize + mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_SEQIN , offset_in_page, page); + chip->write_buf (mtd, buf, len); + chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); + + status = chip->waitfunc (mtd, chip); +if (status &NAND_STATUS_FAIL ) +return -EIO ; + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_prog_page_op); + +/** +* nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation +* @chip: The NAND chip +* @offset_in_page: offset within the page +* @buf: buffer containing the data to send to the NAND +* @len: length of the buffer +* @force_8bit: force 8-bit bus access +* +* This function issues a CHANGE WRITE COLUMN operation. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_change_write_column_op (struct nand_chip *chip, +unsigned int offset_in_page, +const void *buf,unsigned int len, +bool force_8bit) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (len && !buf) +return -EINVAL ; + +if (offset_in_page + len > mtd->writesize + mtd->oobsize) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_RNDIN , offset_in_page,-1 ); +if (len) + chip->write_buf (mtd, buf, len); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_change_write_column_op); + +/** +* nand_readid_op - Do a READID operation +* @chip: The NAND chip +* @addr: address cycle to pass after the READID command +* @buf: buffer used to store the ID +* @len: length of the buffer +* +* This function sends a READID command and reads back the ID returned by the +* NAND. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_readid_op (struct nand_chip *chip,u8 addr,void *buf, +unsigned int len) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +unsigned int i; +u8 *id = buf; + +if (len && !buf) +return -EINVAL ; + + chip->cmdfunc (mtd,NAND_CMD_READID , addr,-1 ); + +for (i =0 ; i < len; i++) + id[i] = chip->read_byte (mtd); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_readid_op); + +/** +* nand_status_op - Do a STATUS operation +* @chip: The NAND chip +* @status: out variable to store the NAND status +* +* This function sends a STATUS command and reads back the status returned by +* the NAND. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_status_op (struct nand_chip *chip,u8 *status) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + + chip->cmdfunc (mtd,NAND_CMD_STATUS ,-1 ,-1 ); +if (status) + *status = chip->read_byte (mtd); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_status_op); + +/** +* nand_exit_status_op - Exit a STATUS operation +* @chip: The NAND chip +* +* This function sends a READ0 command to cancel the effect of the STATUS +* command to avoid reading only the status until a new read command is sent. +* +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_exit_status_op (struct nand_chip *chip) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + + chip->cmdfunc (mtd,NAND_CMD_READ0 ,-1 ,-1 ); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_exit_status_op); + +/** +* nand_erase_op - Do an erase operation +* @chip: The NAND chip +* @eraseblock: block to erase +* +* This function sends an ERASE command and waits for the NAND to be ready +* before returning. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_erase_op (struct nand_chip *chip,unsigned int eraseblock) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +unsigned int page = eraseblock << + (chip->phys_erase_shift - chip->page_shift); +int status; + + chip->cmdfunc (mtd,NAND_CMD_ERASE1 ,-1 , page); + chip->cmdfunc (mtd,NAND_CMD_ERASE2 ,-1 ,-1 ); + + status = chip->waitfunc (mtd, chip); +if (status <0 ) +return status; + +if (status &NAND_STATUS_FAIL ) +return -EIO ; + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_erase_op); + +/** +* nand_set_features_op - Do a SET FEATURES operation +* @chip: The NAND chip +* @feature: feature id +* @data: 4 bytes of data +* +* This function sends a SET FEATURES command and waits for the NAND to be +* ready before returning. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +static int nand_set_features_op (struct nand_chip *chip,u8 feature, +const void *data) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +const u8 *params = data; +int i, status; + + chip->cmdfunc (mtd,NAND_CMD_SET_FEATURES , feature,-1 ); +for (i =0 ; i <ONFI_SUBFEATURE_PARAM_LEN ; ++i) + chip->write_byte (mtd, params[i]); + + status = chip->waitfunc (mtd, chip); +if (status &NAND_STATUS_FAIL ) +return -EIO ; + +return 0 ; +} + +/** +* nand_get_features_op - Do a GET FEATURES operation +* @chip: The NAND chip +* @feature: feature id +* @data: 4 bytes of data +* +* This function sends a GET FEATURES command and waits for the NAND to be +* ready before returning. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +static int nand_get_features_op (struct nand_chip *chip,u8 feature, +void *data) +{ +struct mtd_info *mtd =nand_to_mtd (chip); +u8 *params = data; +int i; + + chip->cmdfunc (mtd,NAND_CMD_GET_FEATURES , feature,-1 ); +for (i =0 ; i <ONFI_SUBFEATURE_PARAM_LEN ; ++i) + params[i] = chip->read_byte (mtd); + +return 0 ; +} + +/** +* nand_reset_op - Do a reset operation +* @chip: The NAND chip +* +* This function sends a RESET command and waits for the NAND to be ready +* before returning. +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_reset_op (struct nand_chip *chip) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + + chip->cmdfunc (mtd,NAND_CMD_RESET ,-1 ,-1 ); + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_reset_op); + +/** +* nand_read_data_op - Read data from the NAND +* @chip: The NAND chip +* @buf: buffer used to store the data +* @len: length of the buffer +* @force_8bit: force 8-bit bus access +* +* This function does a raw data read on the bus. Usually used after launching +* another NAND operation like nand_read_page_op(). +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_read_data_op (struct nand_chip *chip,void *buf,unsigned int len, +bool force_8bit) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (!len || !buf) +return -EINVAL ; + +if (force_8bit) { +u8 *p = buf; +unsigned int i; + +for (i =0 ; i < len; i++) + p[i] = chip->read_byte (mtd); + }else { + chip->read_buf (mtd, buf, len); + } + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_read_data_op); + +/** +* nand_write_data_op - Write data from the NAND +* @chip: The NAND chip +* @buf: buffer containing the data to send on the bus +* @len: length of the buffer +* @force_8bit: force 8-bit bus access +* +* This function does a raw data write on the bus. Usually used after launching +* another NAND operation like nand_write_page_begin_op(). +* This function does not select/unselect the CS line. +* +* Returns 0 on success, a negative error code otherwise. +*/ +int nand_write_data_op (struct nand_chip *chip,const void *buf, +unsigned int len,bool force_8bit) +{ +struct mtd_info *mtd =nand_to_mtd (chip); + +if (!len || !buf) +return -EINVAL ; + +if (force_8bit) { +const u8 *p = buf; +unsigned int i; + +for (i =0 ; i < len; i++) + chip->write_byte (mtd, p[i]); + }else { + chip->write_buf (mtd, buf, len); + } + +return 0 ; +} +EXPORT_SYMBOL_GPL (nand_write_data_op); + +/** * nand_reset - Reset and initialize a NAND device * @chip: The NAND chip * @chipnr: Internal die id
@@ -1066,8 +1607,10 @@ int nand_reset(struct nand_chip *chip, int chipnr)* interface settings, hence this weird ->select_chip() dance. */ chip->select_chip (mtd, chipnr); - chip->cmdfunc (mtd,NAND_CMD_RESET ,-1 ,-1 ); + ret =nand_reset_op (chip); chip->select_chip (mtd,-1 ); +if (ret) +return ret; chip->select_chip (mtd, chipnr); ret =nand_setup_data_interface (chip, chipnr);
@@ -1218,9 +1761,19 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);static int nand_read_page_raw (struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf,int oob_required,int page) { - chip->read_buf (mtd, buf, mtd->writesize); -if (oob_required) - chip->read_buf (mtd, chip->oob_poi, mtd->oobsize); +int ret; + + ret =nand_read_data_op (chip, buf, mtd->writesize, false); +if (ret) +return ret; + +if (oob_required) { + ret =nand_read_data_op (chip, chip->oob_poi, mtd->oobsize, + false); +if (ret) +return ret; + } +return 0 ; }
@@ -1241,29 +1794,46 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,int eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;uint8_t *oob = chip->oob_poi; -int steps, size; +int steps, size, ret;for (steps = chip->ecc.steps; steps >0 ; steps--) { - chip->read_buf (mtd, buf, eccsize); + ret =nand_read_data_op (chip, buf, eccsize, false); +if (ret) +return ret; + buf += eccsize;if (chip->ecc.prepad) { - chip->read_buf (mtd, oob, chip->ecc.prepad); + ret =nand_read_data_op (chip, oob, chip->ecc.prepad, + false); +if (ret) +return ret; + oob += chip->ecc.prepad; } - chip->read_buf (mtd, oob, eccbytes); + ret =nand_read_data_op (chip, oob, eccbytes, false); +if (ret) +return ret; + oob += eccbytes;if (chip->ecc.postpad) { - chip->read_buf (mtd, oob, chip->ecc.postpad); + ret =nand_read_data_op (chip, oob, chip->ecc.postpad, + false); +if (ret) +return ret; + oob += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); -if (size) - chip->read_buf (mtd, oob, size); +if (size) { + ret =nand_read_data_op (chip, oob, size, false); +if (ret) +return ret; + }return 0 ; }
@@ -1334,6 +1904,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,int busw = (chip->options &NAND_BUSWIDTH_16 ) ?2 :1 ;int index;unsigned int max_bitflips =0 ; +int ret;/* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size;
@@ -1351,7 +1922,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc (mtd,NAND_CMD_RNDOUT , data_col_addr,-1 ); p = bufpoi + data_col_addr; - chip->read_buf (mtd, p, datafrag_len); + ret =nand_read_data_op (chip, p, datafrag_len, false); +if (ret) +return ret;/* Calculate ECC */ for (i =0 ; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
@@ -1368,8 +1941,11 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } }if (gaps) { - chip->cmdfunc (mtd,NAND_CMD_RNDOUT , mtd->writesize,-1 ); - chip->read_buf (mtd, chip->oob_poi, mtd->oobsize); + ret =nand_change_read_column_op (chip, mtd->writesize, + chip->oob_poi, mtd->oobsize, + false); +if (ret) +return ret; }else {/* * Send the command to read the particular ECC bytes take care
@@ -1382,9 +1958,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw -1 )) aligned_len++; - chip->cmdfunc (mtd,NAND_CMD_RNDOUT , - mtd->writesize + aligned_pos,-1 ); - chip->read_buf (mtd, &chip->oob_poi[aligned_pos], aligned_len); + ret =nand_change_read_column_op (chip, + mtd->writesize + aligned_pos, + &chip->oob_poi[aligned_pos], + aligned_len, false); +if (ret) +return ret; }for (i =0 ; i < eccfrag_len; i++)
@@ -1437,13 +2016,21 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,uint8_t *ecc_code = chip->buffers->ecccode;uint32_t *eccpos = chip->ecc.layout->eccpos;unsigned int max_bitflips =0 ; +int ret;for (i =0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl (mtd,NAND_ECC_READ ); - chip->read_buf (mtd, p, eccsize); + + ret =nand_read_data_op (chip, p, eccsize, false); +if (ret) +return ret; + chip->ecc.calculate (mtd, p, &ecc_calc[i]); } - chip->read_buf (mtd, chip->oob_poi, mtd->oobsize); + + ret =nand_read_data_op (chip, chip->oob_poi, mtd->oobsize, false); +if (ret) +return ret;for (i =0 ; i < chip->ecc.total; i++) ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1499,11 +2086,16 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,uint32_t *eccpos = chip->ecc.layout->eccpos;uint8_t *ecc_calc = chip->buffers->ecccalc;unsigned int max_bitflips =0 ; +int ret;/* Read the OOB area first */ - chip->cmdfunc (mtd,NAND_CMD_READOOB ,0 , page); - chip->read_buf (mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc (mtd,NAND_CMD_READ0 ,0 , page); + ret =nand_read_oob_op (chip, page,0 , chip->oob_poi, mtd->oobsize); +if (ret) +return ret; + + ret =nand_read_page_op (chip, page,0 ,NULL ,0 ); +if (ret) +return ret;for (i =0 ; i < chip->ecc.total; i++) ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1512,7 +2104,11 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,int stat; chip->ecc.hwctl (mtd,NAND_ECC_READ ); - chip->read_buf (mtd, p, eccsize); + + ret =nand_read_data_op (chip, p, eccsize, false); +if (ret) +return ret; + chip->ecc.calculate (mtd, p, &ecc_calc[i]); stat = chip->ecc.correct (mtd, p, &ecc_code[i],NULL );
@@ -1549,7 +2145,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,static int nand_read_page_syndrome (struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf,int oob_required,int page) { -int i, eccsize = chip->ecc.size; +int ret, i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
@@ -1561,21 +2157,36 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,int stat; chip->ecc.hwctl (mtd,NAND_ECC_READ ); - chip->read_buf (mtd, p, eccsize); + + ret =nand_read_data_op (chip, p, eccsize, false); +if (ret) +return ret;if (chip->ecc.prepad) { - chip->read_buf (mtd, oob, chip->ecc.prepad); + ret =nand_read_data_op (chip, oob, chip->ecc.prepad, + false); +if (ret) +return ret; + oob += chip->ecc.prepad; } chip->ecc.hwctl (mtd,NAND_ECC_READSYN ); - chip->read_buf (mtd, oob, eccbytes); + + ret =nand_read_data_op (chip, oob, eccbytes, false); +if (ret) +return ret; + stat = chip->ecc.correct (mtd, p, oob,NULL ); oob += eccbytes;if (chip->ecc.postpad) { - chip->read_buf (mtd, oob, chip->ecc.postpad); + ret =nand_read_data_op (chip, oob, chip->ecc.postpad, + false); +if (ret) +return ret; + oob += chip->ecc.postpad; }
@@ -1599,8 +2210,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,/* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); -if (i) - chip->read_buf (mtd, oob, i); +if (i) { + ret =nand_read_data_op (chip, oob, i, false); +if (ret) +return ret; + }return max_bitflips; }
@@ -1737,8 +2351,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, __func__, buf); read_retry: -if (nand_standard_page_accessors (&chip->ecc)) - chip->cmdfunc (mtd,NAND_CMD_READ0 ,0x00 , page); +if (nand_standard_page_accessors (&chip->ecc)) { + ret =nand_read_page_op (chip, page,0 ,NULL ,0 ); +if (ret) +break ; + }/* * Now read the page into the buffer. Absent an error,
@@ -1872,9 +2489,7 @@ read_retry:static int nand_read_oob_std (struct mtd_info *mtd,struct nand_chip *chip,int page) { - chip->cmdfunc (mtd,NAND_CMD_READOOB ,0 , page); - chip->read_buf (mtd, chip->oob_poi, mtd->oobsize); -return 0 ; +return nand_read_oob_op (chip, page,0 , chip->oob_poi, mtd->oobsize); }/**
@@ -1891,25 +2506,43 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;int eccsize = chip->ecc.size;uint8_t *bufpoi = chip->oob_poi; -int i, toread, sndrnd =0 , pos; +int i, toread, sndrnd =0 , pos, ret; + + ret =nand_read_page_op (chip, page, chip->ecc.size,NULL ,0 ); +if (ret) +return ret; - chip->cmdfunc (mtd,NAND_CMD_READ0 , chip->ecc.size, page);for (i =0 ; i < chip->ecc.steps; i++) {if (sndrnd) { +int ret; + pos = eccsize + i * (eccsize + chunk);if (mtd->writesize >512 ) - chip->cmdfunc (mtd,NAND_CMD_RNDOUT , pos,-1 ); + ret =nand_change_read_column_op (chip, pos, +NULL ,0 , + false);else - chip->cmdfunc (mtd,NAND_CMD_READ0 , pos, page); + ret =nand_read_page_op (chip, page, pos,NULL , +0 ); + +if (ret) +return ret; }else sndrnd =1 ; toread =min_t (int, length, chunk); - chip->read_buf (mtd, bufpoi, toread); + + ret =nand_read_data_op (chip, bufpoi, toread, false); +if (ret) +return ret; + bufpoi += toread; length -= toread; } -if (length >0 ) - chip->read_buf (mtd, bufpoi, length); +if (length >0 ) { + ret =nand_read_data_op (chip, bufpoi, length, false); +if (ret) +return ret; + }return 0 ; }
@@ -1923,18 +2556,8 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,static int nand_write_oob_std (struct mtd_info *mtd,struct nand_chip *chip,int page) { -int status =0 ; -const uint8_t *buf = chip->oob_poi; -int length = mtd->oobsize; - - chip->cmdfunc (mtd,NAND_CMD_SEQIN , mtd->writesize, page); - chip->write_buf (mtd, buf, length); -/* Send command to program the OOB data */ - chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); - - status = chip->waitfunc (mtd, chip); - -return status &NAND_STATUS_FAIL ? -EIO :0 ; +return nand_prog_page_op (chip, page, mtd->writesize, chip->oob_poi, + mtd->oobsize); }/**
@@ -1949,7 +2572,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, {int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;int eccsize = chip->ecc.size, length = mtd->oobsize; -int i, len, pos, status =0 , sndcmd =0 , steps = chip->ecc.steps; +int ret, i, len, pos, sndcmd =0 , steps = chip->ecc.steps;const uint8_t *bufpoi = chip->oob_poi;/*
@@ -1963,7 +2586,10 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, }else pos = eccsize; - chip->cmdfunc (mtd,NAND_CMD_SEQIN , pos, page); + ret =nand_prog_page_begin_op (chip, page, pos,NULL ,0 ); +if (ret) +return ret; +for (i =0 ; i < steps; i++) {if (sndcmd) {if (mtd->writesize <=512 ) {
@@ -1972,28 +2598,40 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, len = eccsize;while (len >0 ) {int num =min_t (int, len,4 ); - chip->write_buf (mtd, (uint8_t *)&fill, - num); + + ret =nand_write_data_op (chip, &fill, + num, false); +if (ret) +return ret; + len -= num; } }else { pos = eccsize + i * (eccsize + chunk); - chip->cmdfunc (mtd,NAND_CMD_RNDIN , pos,-1 ); + ret =nand_change_write_column_op (chip, pos, +NULL ,0 , + false); +if (ret) +return ret; } }else sndcmd =1 ; len =min_t (int, length, chunk); - chip->write_buf (mtd, bufpoi, len); + + ret =nand_write_data_op (chip, bufpoi, len, false); +if (ret) +return ret; + bufpoi += len; length -= len; } -if (length >0 ) - chip->write_buf (mtd, bufpoi, length); - - chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); - status = chip->waitfunc (mtd, chip); +if (length >0 ) { + ret =nand_write_data_op (chip, bufpoi, length, false); +if (ret) +return ret; + } -return status &NAND_STATUS_FAIL ? -EIO :0 ; +return nand_prog_page_end_op (chip); }/**
@@ -2152,9 +2790,18 @@ out:static int nand_write_page_raw (struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf,int oob_required,int page) { - chip->write_buf (mtd, buf, mtd->writesize); -if (oob_required) - chip->write_buf (mtd, chip->oob_poi, mtd->oobsize); +int ret; + + ret =nand_write_data_op (chip, buf, mtd->writesize, false); +if (ret) +return ret; + +if (oob_required) { + ret =nand_write_data_op (chip, chip->oob_poi, mtd->oobsize, + false); +if (ret) +return ret; + }return 0 ; }
@@ -2177,29 +2824,46 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,int eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;uint8_t *oob = chip->oob_poi; -int steps, size; +int steps, size, ret;for (steps = chip->ecc.steps; steps >0 ; steps--) { - chip->write_buf (mtd, buf, eccsize); + ret =nand_write_data_op (chip, buf, eccsize, false); +if (ret) +return ret; + buf += eccsize;if (chip->ecc.prepad) { - chip->write_buf (mtd, oob, chip->ecc.prepad); + ret =nand_write_data_op (chip, oob, chip->ecc.prepad, + false); +if (ret) +return ret; + oob += chip->ecc.prepad; } - chip->write_buf (mtd, oob, eccbytes); + ret =nand_write_data_op (chip, oob, eccbytes, false); +if (ret) +return ret; + oob += eccbytes;if (chip->ecc.postpad) { - chip->write_buf (mtd, oob, chip->ecc.postpad); + ret =nand_write_data_op (chip, oob, chip->ecc.postpad, + false); +if (ret) +return ret; + oob += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); -if (size) - chip->write_buf (mtd, oob, size); +if (size) { + ret =nand_write_data_op (chip, oob, size, false); +if (ret) +return ret; + }return 0 ; }
@@ -2250,17 +2914,24 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,uint8_t *ecc_calc = chip->buffers->ecccalc;const uint8_t *p = buf;uint32_t *eccpos = chip->ecc.layout->eccpos; +int ret;for (i =0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl (mtd,NAND_ECC_WRITE ); - chip->write_buf (mtd, p, eccsize); + + ret =nand_write_data_op (chip, p, eccsize, false); +if (ret) +return ret; + chip->ecc.calculate (mtd, p, &ecc_calc[i]); }for (i =0 ; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->write_buf (mtd, chip->oob_poi, mtd->oobsize); + ret =nand_write_data_op (chip, chip->oob_poi, mtd->oobsize, false); +if (ret) +return ret;return 0 ; }
@@ -2291,13 +2962,16 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,uint32_t end_step = (offset + data_len -1 ) / ecc_size;int oob_bytes = mtd->oobsize / ecc_steps;int step, i; +int ret;for (step =0 ; step < ecc_steps; step++) {/* configure controller for WRITE access */ chip->ecc.hwctl (mtd,NAND_ECC_WRITE );/* write data (untouched subpages already masked by 0xFF) */ - chip->write_buf (mtd, buf, ecc_size); + ret =nand_write_data_op (chip, buf, ecc_size, false); +if (ret) +return ret;/* mask ECC of un-touched subpages by padding 0xFF */ if ((step < start_step) || (step > end_step))
@@ -2322,7 +2996,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, chip->oob_poi[eccpos[i]] = ecc_calc[i];/* write OOB buffer to NAND device */ - chip->write_buf (mtd, chip->oob_poi, mtd->oobsize); + ret =nand_write_data_op (chip, chip->oob_poi, mtd->oobsize, false); +if (ret) +return ret;return 0 ; }
@@ -2349,31 +3025,49 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,int eccsteps = chip->ecc.steps;const uint8_t *p = buf;uint8_t *oob = chip->oob_poi; +int ret;for (i =0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl (mtd,NAND_ECC_WRITE ); - chip->write_buf (mtd, p, eccsize); + + ret =nand_write_data_op (chip, p, eccsize, false); +if (ret) +return ret;if (chip->ecc.prepad) { - chip->write_buf (mtd, oob, chip->ecc.prepad); + ret =nand_write_data_op (chip, oob, chip->ecc.prepad, + false); +if (ret) +return ret; + oob += chip->ecc.prepad; } chip->ecc.calculate (mtd, p, oob); - chip->write_buf (mtd, oob, eccbytes); + + ret =nand_write_data_op (chip, oob, eccbytes, false); +if (ret) +return ret; + oob += eccbytes;if (chip->ecc.postpad) { - chip->write_buf (mtd, oob, chip->ecc.postpad); + ret =nand_write_data_op (chip, oob, chip->ecc.postpad, + false); +if (ret) +return ret; + oob += chip->ecc.postpad; } }/* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); -if (i) - chip->write_buf (mtd, oob, i); +if (i) { + ret =nand_write_data_op (chip, oob, i, false); +if (ret) +return ret; + }return 0 ; }
@@ -2401,8 +3095,11 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,else subpage =0 ; -if (nand_standard_page_accessors (&chip->ecc)) - chip->cmdfunc (mtd,NAND_CMD_SEQIN ,0x00 , page); +if (nand_standard_page_accessors (&chip->ecc)) { + status =nand_prog_page_begin_op (chip, page,0 ,NULL ,0 ); +if (status) +return status; + }if (unlikely (raw)) status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2417,13 +3114,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,if (status <0 )return status; -if (nand_standard_page_accessors (&chip->ecc)) { - chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); - - status = chip->waitfunc (mtd, chip); -if (status &NAND_STATUS_FAIL ) -return -EIO ; - } +if (nand_standard_page_accessors (&chip->ecc)) +return nand_prog_page_end_op (chip);return 0 ; }
@@ -2783,11 +3475,12 @@ out:static int single_erase (struct mtd_info *mtd,int page) {struct nand_chip *chip =mtd_to_nand (mtd); +unsigned int eraseblock; +/* Send commands to erase a block */ - chip->cmdfunc (mtd,NAND_CMD_ERASE1 ,-1 , page); - chip->cmdfunc (mtd,NAND_CMD_ERASE2 ,-1 ,-1 ); + eraseblock = page >> (chip->phys_erase_shift - chip->page_shift); -return chip->waitfunc (mtd, chip); +return nand_erase_op (chip, eraseblock); }/**
@@ -2980,9 +3673,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)static int nand_onfi_set_features (struct mtd_info *mtd,struct nand_chip *chip,int addr,uint8_t *subfeature_param) { -int status; -int i; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd)
@@ -2990,14 +3680,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,return -ENOTSUPP ;#endif - chip->cmdfunc (mtd,NAND_CMD_SET_FEATURES , addr,-1 ); -for (i =0 ; i <ONFI_SUBFEATURE_PARAM_LEN ; ++i) - chip->write_byte (mtd, subfeature_param[i]); - - status = chip->waitfunc (mtd, chip); -if (status &NAND_STATUS_FAIL ) -return -EIO ; -return 0 ; +return nand_set_features_op (chip, addr, subfeature_param); }/**
@@ -3010,8 +3693,6 @@ 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,int addr,uint8_t *subfeature_param) { -int i; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd)
@@ -3019,10 +3700,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,return -ENOTSUPP ;#endif - chip->cmdfunc (mtd,NAND_CMD_GET_FEATURES , addr,-1 ); -for (i =0 ; i <ONFI_SUBFEATURE_PARAM_LEN ; ++i) - *subfeature_param++ = chip->read_byte (mtd); -return 0 ; +return nand_get_features_op (chip, addr, subfeature_param); }/* Set default functions */
@@ -3116,7 +3794,7 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,struct onfi_ext_section *s;struct onfi_ext_ecc_info *ecc;uint8_t *cursor; -int ret = -EINVAL ; +int ret;int len;int i;
@@ -3126,14 +3804,18 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,return -ENOMEM ;/* Send our own NAND_CMD_PARAM. */ - chip->cmdfunc (mtd,NAND_CMD_PARAM ,0 ,-1 ); + ret =nand_read_param_page_op (chip,0 ,NULL ,0 ); +if (ret) + goto ext_out;/* Use the Change Read Column command to skip the ONFI param pages. */ - chip->cmdfunc (mtd,NAND_CMD_RNDOUT , -sizeof (*p) * p->num_of_param_pages ,-1 ); + ret =nand_change_read_column_op (chip, +sizeof (*p) * p->num_of_param_pages, + ep, len, true); +if (ret) + goto ext_out; -/* Read out the Extended Parameter Page. */ - chip->read_buf (mtd, (uint8_t *)ep, len); + ret = -EINVAL ;if ((onfi_crc16 (ONFI_CRC_BASE , ((uint8_t *)ep) +2 , len -2 ) !=le16_to_cpu (ep->crc))) {pr_debug ("fail in the CRC.\n" );
@@ -3210,19 +3892,23 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) {struct nand_onfi_params *p = &chip->onfi_params; -int i, j; -int val; +char id[4 ]; +int i, ret, val;/* Try ONFI for unknown chip or LP */ - chip->cmdfunc (mtd,NAND_CMD_READID ,0x20 ,-1 ); -if (chip->read_byte (mtd) !='O' || chip->read_byte (mtd) !='N' || - chip->read_byte (mtd) !='F' || chip->read_byte (mtd) !='I' ) + ret =nand_readid_op (chip,0x20 , id,sizeof (id)); +if (ret ||strncmp (id,"ONFI" ,4 )) +return 0 ; + + ret =nand_read_param_page_op (chip,0 ,NULL ,0 ); +if (ret)return 0 ; - chip->cmdfunc (mtd,NAND_CMD_PARAM ,0 ,-1 );for (i =0 ; i <3 ; i++) { -for (j =0 ; j <sizeof (*p); j++) - ((uint8_t *)p)[j] = chip->read_byte (mtd); + ret =nand_read_data_op (chip, p,sizeof (*p), true); +if (ret) +return 0 ; +if (onfi_crc16 (ONFI_CRC_BASE , (uint8_t *)p,254 ) ==le16_to_cpu (p->crc)) {break ;
@@ -3322,20 +4008,22 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip, {struct nand_jedec_params *p = &chip->jedec_params;struct jedec_ecc_info *ecc; -int val; -int i, j; +char id[5 ]; +int i, val, ret;/* Try JEDEC for unknown chip or LP */ - chip->cmdfunc (mtd,NAND_CMD_READID ,0x40 ,-1 ); -if (chip->read_byte (mtd) !='J' || chip->read_byte (mtd) !='E' || - chip->read_byte (mtd) !='D' || chip->read_byte (mtd) !='E' || - chip->read_byte (mtd) !='C' ) + ret =nand_readid_op (chip,0x40 , id,sizeof (id)); +if (ret ||strncmp (id,"JEDEC" ,sizeof (id))) +return 0 ; + + ret =nand_read_param_page_op (chip,0x40 ,NULL ,0 ); +if (ret)return 0 ; - chip->cmdfunc (mtd,NAND_CMD_PARAM ,0x40 ,-1 );for (i =0 ; i <3 ; i++) { -for (j =0 ; j <sizeof (*p); j++) - ((uint8_t *)p)[j] = chip->read_byte (mtd); + ret =nand_read_data_op (chip, p,sizeof (*p), true); +if (ret) +return 0 ;if (onfi_crc16 (ONFI_CRC_BASE , (uint8_t *)p,510 ) ==le16_to_cpu (p->crc))
@@ -3706,25 +4394,29 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int *maf_id, int *dev_id, struct nand_flash_dev *type) { - int busw; -int i, maf_idx; + int busw, ret; +int maf_idx;u8 id_data[8 ];/* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. */ -nand_reset (chip,0 ); + ret =nand_reset (chip,0 ); +if (ret) +return ERR_PTR (ret);/* Select the device */ chip->select_chip (mtd,0 );/* Send the command for reading device ID */ - chip->cmdfunc (mtd,NAND_CMD_READID ,0x00 ,-1 ); + ret =nand_readid_op (chip,0 , id_data,2 ); +if (ret) +return ERR_PTR (ret);/* Read manufacturer and device IDs */ - *maf_id = chip->read_byte (mtd); - *dev_id = chip->read_byte (mtd); + *maf_id = id_data[0 ]; + *dev_id = id_data[1 ];/* * Try again to make sure, as some systems the bus-hold or other
@@ -3733,11 +4425,10 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,* not match, ignore the device completely. */ - chip->cmdfunc (mtd,NAND_CMD_READID ,0x00 ,-1 ); -/* Read entire ID string */ -for (i =0 ; i <8 ; i++) - id_data[i] = chip->read_byte (mtd); + ret =nand_readid_op (chip,0 , id_data,8 ); +if (ret) +return ERR_PTR (ret);if (id_data[0 ] != *maf_id || id_data[1 ] != *dev_id) { pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
@@ -3997,15 +4688,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,/* Check for a chip array */ for (i =1 ; i < maxchips; i++) { +u8 id[2 ]; +/* See comment in nand_get_flash_type for reset */ nand_reset (chip, i); chip->select_chip (mtd, i);/* Send the command for reading device ID */ - chip->cmdfunc (mtd,NAND_CMD_READID ,0x00 ,-1 ); +nand_readid_op (chip,0 , id,sizeof (id)); +/* Read manufacturer and device IDs */ -if (nand_maf_id != chip->read_byte (mtd) || - nand_dev_id != chip->read_byte (mtd)) { +if (nand_maf_id != id[0 ] || nand_dev_id != id[1 ]) { chip->select_chip (mtd,-1 );break ; }
include/linux/mtd/rawnand.h +30 -0
@@ -1299,4 +1299,34 @@ int nand_maximize_ecc(struct nand_chip *chip,/* Reset and initialize a NAND device */ int nand_reset (struct nand_chip *chip,int chipnr); + +/* NAND operation helpers */ +int nand_reset_op (struct nand_chip *chip); +int nand_readid_op (struct nand_chip *chip,u8 addr,void *buf, +unsigned int len); +int nand_status_op (struct nand_chip *chip,u8 *status); +int nand_exit_status_op (struct nand_chip *chip); +int nand_erase_op (struct nand_chip *chip,unsigned int eraseblock); +int nand_read_page_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,void *buf,unsigned int len); +int nand_change_read_column_op (struct nand_chip *chip, +unsigned int offset_in_page,void *buf, +unsigned int len,bool force_8bit); +int nand_read_oob_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,void *buf,unsigned int len); +int nand_prog_page_begin_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,const void *buf, +unsigned int len); +int nand_prog_page_end_op (struct nand_chip *chip); +int nand_prog_page_op (struct nand_chip *chip,unsigned int page, +unsigned int offset_in_page,const void *buf, +unsigned int len); +int nand_change_write_column_op (struct nand_chip *chip, +unsigned int offset_in_page,const void *buf, +unsigned int len,bool force_8bit); +int nand_read_data_op (struct nand_chip *chip,void *buf,unsigned int len, +bool force_8bit); +int nand_write_data_op (struct nand_chip *chip,const void *buf, +unsigned int len,bool force_8bit); +#endif /* __LINUX_MTD_RAWNAND_H */
Signature · 1 line
2.7.4
RFC PATCH 4/7 arm: asm: io.h: define readX_relaxed and writeX_relaxed
In reply to Philippe Reynes--- arch/arm/include/asm/io.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
arch/arm/include/asm/io.h +15 -0
@@ -123,6 +123,21 @@ static inline void __raw_readsl(unsigned long addr, void *data, int longlen)#define readq (c) ({ u64 __v = __arch_getq(c); __iormb(); __v; })/* +* Relaxed I/O memory access primitives. These follow the Device memory +* ordering rules but do not guarantee any ordering relative to Normal memory +* accesses. +*/ +#define readb_relaxed (c) ({ u8 __r = __raw_readb(c); __r; }) +#define readw_relaxed (c) ({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; }) +#define readl_relaxed (c) ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; }) +#define readq_relaxed (c) ({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; }) + +#define writeb_relaxed (v,c) ((void)__raw_writeb((v),(c))) +#define writew_relaxed (v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) +#define writel_relaxed (v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) +#define writeq_relaxed (v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c))) + +/* * The compiler seems to be incapable of optimising constants * properly. Spell it out to the compiler in some cases. * These are only valid for small values of "off" (< 1<<12)
Signature · 1 line
2.7.4
RFC PATCH 5/7 drivers: nand: brcmnand: add initial support
In reply to Philippe Reynes--- drivers/mtd/nand/raw/Kconfig | 19 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/brcmnand/Makefile | 6 + drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c | 124 + drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c | 126 ++ drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2771 +++++++++++++++++++++++ drivers/mtd/nand/raw/brcmnand/brcmnand.h | 63 + drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c | 116 + drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h | 32 + 9 files changed, 3258 insertions(+) create mode 100644 drivers/mtd/nand/raw/brcmnand/Makefile create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.h create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
drivers/mtd/nand/raw/Kconfig +19 -0
@@ -16,6 +16,25 @@ config NAND_ATMEL Enable this driver for NAND flash platforms using an Atmel NAND controller. +config NAND_BRCMNAND + bool "Support Broadcom NAND controller" + depends on OF_CONTROL && DM && MTD + help + Enable the driver for NAND flash on platforms using a Broadcom NAND + controller. + +config NAND_BRCMNAND_6838 + bool "Support Broadcom NAND controller on bcm6838" + depends on NAND_BRCMNAND && ARCH_BCM6838 + help + Enable support for broadcom nand driver on bcm6838. + +config NAND_BRCMNAND_6858 + bool "Support Broadcom NAND controller on bcm6858" + depends on NAND_BRCMNAND && ARCH_BCM6858 + help + Enable support for broadcom nand driver on bcm6858. + config NAND_DAVINCI bool "Support TI Davinci NAND controller" help
drivers/mtd/nand/raw/Makefile +1 -0
@@ -41,6 +41,7 @@ obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o +obj-$(CONFIG_NAND_BRCMNAND) += brcmnand/ obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_NAND_DENALI) += denali.o obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o
drivers/mtd/nand/raw/brcmnand/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_NAND_BRCMNAND_6838) += bcm6838_nand.o +obj-$(CONFIG_NAND_BRCMNAND_6858) += bcm6858_nand.o +obj-$(CONFIG_NAND_BRCMNAND) += brcmnand.o +obj-$(CONFIG_NAND_BRCMNAND) += brcmnand_compat.o
drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c new file +124 -0
124 lines not on this page · raw message
drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c new file +126 -0
126 lines not on this page · raw message
drivers/mtd/nand/raw/brcmnand/brcmnand.c new file +2771 -0
2,712 lines not on this page · raw message
drivers/mtd/nand/raw/brcmnand/brcmnand.h new file +63 -0
63 lines not on this page · raw message
drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c new file +116 -0
116 lines not on this page · raw message
drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h new file +32 -0
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.7.4
Part of the diff is not shown here. View the raw message.
RFC PATCH 6/7 drivers: nand: brcmnand: add parameter parameter-page-big-endian
In reply to Philippe ReynesThe parameter page isn't always in big endian, so we add an option to choose the endiannes of the parameter page.
--- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/mtd/nand/raw/brcmnand/brcmnand.c +8 -1
@@ -113,6 +113,7 @@ struct brcmnand_controller {unsigned int irq;unsigned int dma_irq;int nand_version; +int parameter_page_big_endian;/* Some SoCs provide custom interrupt status register(s) */ struct brcmnand_soc *soc;
@@ -1446,7 +1447,10 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,* Flash cache is big endian for parameter pages, at * least on STB SoCs */ - flash_cache[i] =be32_to_cpu (brcmnand_read_fc (ctrl, i)); +if (ctrl->parameter_page_big_endian) + flash_cache[i] =be32_to_cpu (brcmnand_read_fc (ctrl, i)); +else + flash_cache[i] =le32_to_cpu (brcmnand_read_fc (ctrl, i));brcmnand_soc_data_bus_unprepare (ctrl->soc, true);
@@ -2554,6 +2558,9 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc)nand_hw_control_init (&ctrl->controller);INIT_LIST_HEAD (&ctrl->host_list); +/* Is parameter page in big endian ? */ + ctrl->parameter_page_big_endian =dev_read_u32_default (dev,"parameter-page-big-endian" ,1 ); +/* NAND register range */ res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); ctrl->nand_base =devm_ioremap_resource (dev, res);
Signature · 1 line
2.7.4
RFC PATCH 7/7 drivers: nand: brcmnand: add an option to read the write-protect from device tree
In reply to Philippe ReynesThe option write-protect may only change on the kernel command line, we add a property in the device tree to be more flexible.
--- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/mtd/nand/raw/brcmnand/brcmnand.c +3 -0
@@ -2650,6 +2650,9 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc)/* Disable XOR addressing */ brcmnand_rmw_reg (ctrl,BRCMNAND_CS_XOR ,0xff ,0 ,0 ); +/* Read the write-protect configuration in the device tree */ + wp_on =dev_read_u32_default (dev,"write-protect" , wp_on); +if (ctrl->features &BRCMNAND_HAS_WP ) {/* Permanently disable write protection */ if (wp_on ==2 )
Signature · 1 line
2.7.4
Miquel Raynal
maintainercover Initial support of driver brcmnand (from kernel 4.18)
In reply to Philippe ReynesHi Philippe,
Thanks for the work.
Philippe Reynes <[email protected]> wrote on Fri, 16 Nov 2018 14:56:57 +0100:
Quoted 6 lines
This serie is a RFC to port the support of driver brcmnand from kernel 4.18 to u-boot. I've tried to stay as close as possible to the kernel. In this first port, I haven't ported the support of DMA, it's not mandatory in the first step and it could be added later.
Quoted 7 lines
This code has been tested on bcm6838 (mips) and bcm6858 (arm64). This code isn't clean enough to be integrated. I just send this serie to show the code and ask some question.
In the code, I've used "#ifndef
__UBOOT__" to show the difference between the kernel code. Is it a good way or is it better to just replace the code ?
I think it is a good way. I find harder to read the code, but much easier to apply patches from Linux.
Quoted 7 lines
I've also added a file with brcmnand_compat.[hc] to compat
function with the kernel (for exampleplatform_get_resource_byname). What is the prefered way to support this function on u-boot ?
- just replace them by other code on u-boot
- just add this function on the brcmnand driver
- share this code for others driver (adding compat file for platform device, ...)
In your case, helpers might find their ways in their respective original .c/.h files. But then you can modify them to fit with U-Boot (why not with a #ifdef __UBOOT__?). Plus, I think you missed some of them that are already existing in U-Boot (even if they are dummy inline functions for instance).
Quoted 11 lines
Boris Brezillon (1):
mtd: nand: provide several helpers to do common NAND operationsBrian Norris (1):
mtd: add get/set of_node/flash_node helpersMarc Gonzalez (1):
mtd: nand: importnand_hw_control_init()
When you pick commits from other authors, what you do is:
---
* I think the [Linux commit:] is generally in the commit log itself, before the Git tags.
* You don't need this extra SoB tag at the end.
* I suggest that you always keep the entire file, even when adding unused functions, so that they will be available later if we continue backporting; so there will not be two commits with the exact same title+author in the future. If it triggers build issues, just add #ifdef statements.
Also, all patches must come with a description in the commit log (but this is a preliminary version so you probably just did not take the time).
Thanks,
Miquèl