block fortress联机ops 2怎么联机

Add isbad and markbad support for SPI NAND. And do noterase bad blocks in spi_nand_erase.Signed-off-by: Peter Pan &***@&---drivers/mtd/nand/spi/spinand_base.c | 116 ++++++++++++++++++++++++++++++++++++1 file changed, 116 insertions(+)diff --git a/drivers/mtd/nand/spi/spinand_base.c b/drivers/mtd/nand/spi/spinand_base.cindex 1bc57e9..0644--- a/drivers/mtd/nand/spi/spinand_base.c+++ b/drivers/mtd/nand/spi/spinand_base.c@@ -03,113 @@ static int spinand_write_oob(struct mtd_info *mtd, loff_t to,}+/**+ * spinand_block_bad - Check if block at offset is bad+ * @mtd: MTD device structure+ * @offs: offset relative to mtd start+ * @getchip: 0, if the chip is already selected+ */+static int spinand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)+{+ struct nand_device *nand = mtd_to_nand(mtd);+ struct mtd_oob_ops ops = {0};+ u32 block_+ u8 bad[2] = {0, 0};+ u8 ret = 0;++ block_addr = nand_offs_to_eraseblock(nand, ofs);+ ops.mode = MTD_OPS_PLACE_OOB;+ ops.ooblen = 2;+ ops.oobbuf =++ if (getchip)+
spinand_get_device(mtd_to_spinand(mtd));+ spinand_do_read_ops(mtd, nand_eraseblock_to_offs(nand, block_addr), &ops);+ if (getchip)+
spinand_release_device(mtd_to_spinand(mtd));+ if (bad[0] != 0xFF || bad[1] != 0xFF)+
1;++ +}++/**+ * spinand_block_isbad - [MTD Interface] Check if block at offset is bad+ * @mtd: MTD device structure+ * @offs: offset relative to mtd start+ */+static int spinand_block_isbad(struct mtd_info *mtd, loff_t offs)+{+ return spinand_block_bad(mtd, offs, 1);+}++/**+ * spinand_block_markbad_lowlevel - mark a block bad+ * @mtd: MTD device structure+ * @ofs: offset from device start+ *+ * This function performs the generic bad block marking steps (i.e., bad+ * block table(s) and/or marker(s)). We only allow the hardware driver to+ * specify how to write bad block markers to OOB (chip-&block_markbad).+ *+ * We try operations in the following order:+ *
(1) erase the affected block, to allow OOB marker to be written cleanly+ *
(2) write bad block marker to OOB area of affected block (unless flag+ *
NAND_BBT_NO_OOB_BBM is present)+ *
(3) update the BBT+ * Note that we retain the first error encountered in (2) or (3), finish the+ * procedures, and dump the error in the end.+*/+static int spinand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)+{+ struct nand_device *nand = mtd_to_nand(mtd);+ struct mtd_oob_ops ops = {0};+ struct erase_info einfo = {0};+ u32 block_+ u8 buf[2] = {0, 0};+ int ret = 0;++ /*erase bad block before mark bad block*/+ einfo.mtd =+ einfo.addr =+ einfo.len = nand_eraseblock_size(nand);+ spinand_erase(mtd, &einfo);++ block_addr = nand_offs_to_eraseblock(nand, ofs);+ ops.mode = MTD_OPS_PLACE_OOB;+ ops.ooblen = 2;+ ops.oobbuf =+ spinand_get_device(mtd_to_spinand(mtd));+ ret = spinand_do_write_ops(mtd,+
nand_eraseblock_to_offs(nand, block_addr), &ops);+ spinand_release_device(mtd_to_spinand(mtd));++ if (!ret)+
mtd-&ecc_stats.badblocks++;++ +}++/**+ * spinand_block_markbad - [MTD Interface] Mark block at the given offset+ * as bad+ * @mtd: MTD device structure+ * @ofs: offset relative to mtd start+ */+static int spinand_block_markbad(struct mtd_info *mtd, loff_t ofs)+{+ ++ ret = spinand_block_isbad(mtd, ofs);+ if (ret) {+
/* If it was bad already, return success and do nothing */+
if (ret & 0)+
return 0;+
+ }++ return spinand_block_markbad_lowlevel(mtd, ofs);+}/*** spinand_erase - [MTD Interface] erase block(s)@@ -51,13 @@ static int spinand_erase(struct mtd_info *mtd, struct erase_info *einfo)einfo-&state = MTD_ERASING;while (len) {+
/* Check if we have a bad block, we do not erase bad blocks! */+
if (spinand_block_bad(mtd, offs, 0)) {+
pr_warn("%s: attempt to erase a bad block at 0x%012llx\n",+
__func__, offs);+
einfo-&state = MTD_ERASE_FAILED;+
goto erase_+
}spinand_write_enable(chip);spinand_erase_block(chip, nand_offs_to_page(nand, offs));ret = spinand_wait(chip, &status);@@ -16,8 @@ int spinand_scan_tail(struct spinand_device *chip)mtd-&_write = spinand_mtd-&_read_oob = spinand_read_mtd-&_write_oob = spinand_write_+ mtd-&_block_isbad = spinand_block_+ mtd-&_block_markbad = spinand_block_if (!mtd-&bitflip_threshold)mtd-&bitflip_threshold = DIV_ROUND_UP(mtd-&ecc_strength * 3, 4);--1.9.1
Raw Message
This commit is to add support for Micron MT29F2G01ABAGDspi nand chip.Signed-off-by: Peter Pan &***@&---drivers/mtd/nand/spi/Makefile
1 +drivers/mtd/nand/spi/spinand_ids.c
5 ++drivers/mtd/nand/spi/spinand_micron.c | 133 ++++++++++++++++++++++++++++++++++3 files changed, 139 insertions(+)create mode 100644 drivers/mtd/nand/spi/spinand_micron.cdiff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefileindex 6f0d622..84b9bcc 100644--- a/drivers/mtd/nand/spi/Makefile+++ b/drivers/mtd/nand/spi/Makefile@@ -1,2 +1,3 @@obj-$(CONFIG_MTD_SPI_NAND) += spinand_base.oobj-$(CONFIG_MTD_SPI_NAND) += spinand_ids.o+obj-$(CONFIG_MTD_SPI_NAND) += spinand_micron.odiff --git a/drivers/mtd/nand/spi/spinand_ids.c b/drivers/mtd/nand/spi/spinand_ids.cindex f74f1 100644--- a/drivers/mtd/nand/spi/spinand_ids.c+++ b/drivers/mtd/nand/spi/spinand_ids.c@@ -18,11 +18,16 @@#include &linux/mtd/spinand.h&struct spinand_flash spinand_table[] = {+ SPI_NAND_INFO("MT29F2G01ABAGD", 0x2C, 0x24, , 64, 2048,+
1, 8, SPINAND_OP_COMMON),{.name = NULL},};+extern struct spinand_manufacturer_ops micron_spinand_manuf_+struct spinand_manufacturer spinand_manuf_ids[] = {+ {SPINAND_MFR_MICRON, "Micron", &micron_spinand_manuf_ops},{0x0, "Unknown"}};diff --git a/drivers/mtd/nand/spi/spinand_micron.c b/drivers/mtd/nand/spi/spinand_micron.cnew file mode 100644index 0000000..d978935--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_micron.c@@ -0,0 +1,133 @@+/**+* spi-nand-base.c+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#include &linux/mtd/spinand.h&++#define SPI_NAND_MT29F_ECC_MASK
0x70+#define SPI_NAND_MT29F_ECC_0_BIT 0x00+#define SPI_NAND_MT29F_ECC_1_3_BIT 0x10+#define SPI_NAND_MT29F_ECC_4_6_BIT 0x30+#define SPI_NAND_MT29F_ECC_7_8_BIT 0x50+#define SPI_NAND_MT29F_ECC_UNCORR 0x20+++static int micron_ooblayout_ecc_128(struct mtd_info *mtd, int section,+
struct mtd_oob_region *oobregion)+{+ if (section)+
return -ERANGE;++ oobregion-&length = 64;+ oobregion-&offset = 64;++ return 0;+}++static int micron_ooblayout_free_128(struct mtd_info *mtd, int section,+
struct mtd_oob_region *oobregion)+{+ if (section)+
return -ERANGE;++ oobregion-&length = 62;+ oobregion-&offset = 2;++ return 0;+}++static const struct mtd_ooblayout_ops micron_ooblayout_128_ops = {+ .ecc = micron_ooblayout_ecc_128,+ .free = micron_ooblayout_free_128,+};++static void mt29f_get_ecc_status(struct spinand_device *chip,+
unsigned int status,+
unsigned int *corrected,+
unsigned int *ecc_error)+{+ unsigned int ecc_status = status & SPI_NAND_MT29F_ECC_MASK;++ *ecc_error = (ecc_status == SPI_NAND_MT29F_ECC_UNCORR);+ switch (ecc_status) {+ case SPI_NAND_MT29F_ECC_0_BIT:+
*corrected = 0;+
+ case SPI_NAND_MT29F_ECC_1_3_BIT:+
*corrected = 3;+
+ case SPI_NAND_MT29F_ECC_4_6_BIT:+
*corrected = 6;+
+ case SPI_NAND_MT29F_ECC_7_8_BIT:+
*corrected = 8;+
+ }+}++static void mt29f_build_column_addr(struct spinand_device *chip,+
struct spinand_op *op,+
u32 page, u32 column)+{+ struct nand_device *nand = &chip-&++ op-&n_addr = 2;+ op-&addr[0] = (u8)(column && 8);+ op-&addr[0] |= (u8)((nand_page_to_eraseblock(nand, page)+
& 0x1) && 4);+ op-&addr[1] = (u8)+}++static int micron_spinand_get_dummy(struct spinand_device *chip,+
struct spinand_op *op)+{+ u8 opcode = op-&++ switch (opcode) {+ case SPINAND_CMD_READ_FROM_CACHE:+ case SPINAND_CMD_READ_FROM_CACHE_FAST:+ case SPINAND_CMD_READ_FROM_CACHE_X2:+ case SPINAND_CMD_READ_FROM_CACHE_DUAL_IO:+ case SPINAND_CMD_READ_FROM_CACHE_X4:+ case SPINAND_CMD_READ_ID:+
return 1;+ case SPINAND_CMD_READ_FROM_CACHE_QUAD_IO:+
return 2;+ default:+
return 0;+ }+}++static struct spinand_ecc_engine_ops generic_spi_ecc_engine_ops = {+ .get_ecc_status = mt29f_get_ecc_status,+};++static int micron_spinand_init(struct spinand_device *chip)+{+ struct mtd_info *mtd = spinand_to_mtd(chip);+ struct nand_device *nand = mtd_to_nand(mtd);++ chip-&ecc_engine.ops = &generic_spi_ecc_engine_+ if (nand_per_page_oobsize(nand) == 128)+
mtd_set_ooblayout(mtd, &micron_ooblayout_128_ops);++ return 0;+}++const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {+ .init = micron_spinand_init,+ .build_column_addr = mt29f_build_column_addr,+ .get_dummy = micron_spinand_get_dummy,+};--1.9.1
Raw Message
On Wed, 1 Mar :09 +0800This commit is to add support for Micron MT29F2G01ABAGDspi nand chip.---drivers/mtd/nand/spi/Makefile
1 +drivers/mtd/nand/spi/spinand_ids.c
5 ++drivers/mtd/nand/spi/spinand_micron.c | 133 ++++++++++++++++++++++++++++++++++micron.c should be enough.
Raw Message
Hi Boris,On Wed, Mar 8, 2017 at 4:32 PM, Boris BrezillonOn Wed, 1 Mar :09 +0800This commit is to add support for Micron MT29F2G01ABAGDspi nand chip.---drivers/mtd/nand/spi/Makefile
1 +drivers/mtd/nand/spi/spinand_ids.c
5 ++drivers/mtd/nand/spi/spinand_micron.c | 133 ++++++++++++++++++++++++++++++++++micron.c should be enough.Noted. Fix this in v3ThanksPeter Pan
Raw Message
This is the first commit for spi nand framkework.This commit is to add spi nand initialization andrelease functions.Signed-off-by: Peter Pan &***@&---drivers/mtd/nand/Kconfig
1 +drivers/mtd/nand/Makefile
1 +drivers/mtd/nand/spi/Kconfig
5 +drivers/mtd/nand/spi/Makefile
2 +drivers/mtd/nand/spi/spinand_base.c | 469 ++++++++++++++++++++++++++++++++++++drivers/mtd/nand/spi/spinand_ids.c
29 +++include/linux/mtd/spinand.h
| 315 ++++++++++++++++++++++++7 files changed, 822 insertions(+)create mode 100644 drivers/mtd/nand/spi/Kconfigcreate mode 100644 drivers/mtd/nand/spi/Makefilecreate mode 100644 drivers/mtd/nand/spi/spinand_base.ccreate mode 100644 drivers/mtd/nand/spi/spinand_ids.ccreate mode 100644 include/linux/mtd/spinand.hdiff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfigindex 1c1a1f4..644--- a/drivers/mtd/nand/Kconfig+++ b/drivers/mtd/nand/Kconfig@@ -2,3 +2,4 @@ config MTD_NAND_COREtristatesource "drivers/mtd/nand/raw/Kconfig"+source "drivers/mtd/nand/spi/Kconfig"diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefileindex fe430d9..644--- a/drivers/mtd/nand/Makefile+++ b/drivers/mtd/nand/Makefile@@ -3,3 +3,4 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.onandcore-objs :=
bbt.oobj-y += raw/+obj-$(CONFIG_MTD_SPI_NAND) += spi/diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfignew file mode 100644index a7b71--- /dev/null+++ b/drivers/mtd/nand/spi/Kconfig@@ -0,0 +1,5 @@+menuconfig MTD_SPI_NAND+ tristate "SPI-NAND device Support"+ depends on MTD_NAND+ help+
This is the framework for the SPI NAND device drivers.diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefilenew file mode 100644index f0d622--- /dev/null+++ b/drivers/mtd/nand/spi/Makefile@@ -0,0 +1,2 @@+obj-$(CONFIG_MTD_SPI_NAND) += spinand_base.o+obj-$(CONFIG_MTD_SPI_NAND) += spinand_ids.odiff --git a/drivers/mtd/nand/spi/spinand_base.c b/drivers/mtd/nand/spi/spinand_base.cnew file mode 100644index d47146--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_base.c@@ -0,0 +1,469 @@+/**+* spi-nand-base.c+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt++#include &linux/kernel.h&+#include &linux/module.h&+#include &linux/sched.h&+#include &linux/delay.h&+#include &linux/jiffies.h&+#include &linux/mtd/spinand.h&+#include &linux/slab.h&+++static u64 spinand_get_chip_size(struct spinand_device *chip)+{+ struct nand_device *nand = &chip-&++ return nand_diesize(nand) * nand_ndies(nand);+}++static inline int spinand_exec_cmd(struct spinand_device *chip,+
struct spinand_op *cmd)+{+ return chip-&controller.ops-&exec_op(chip, cmd);+}++static inline void spinand_op_init(struct spinand_op *op)+{+ memset(op, 0, sizeof(struct spinand_op));+ op-&addr_nbits = 1;+ op-&data_nbits = 1;+}++/**+ * spinand_read_reg - send command 0Fh to read register+ * @chip: SPI-NAND device structure+ * @ register to read+ * @buf: buffer to store value+ */+static int spinand_read_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_GET_FEATURE;+ cmd.n_addr = 1;+ cmd.addr[0] =+ cmd.n_rx = 1;+ cmd.rx_buf =++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0)+
pr_err("err: %d read register %d\n", ret, reg);++ +}++/**+ * spinand_write_reg - send command 1Fh to write register+ * @chip: SPI-NAND device structure+ * @ register to write+ * @buf: buffer stored value+ */+static int spinand_write_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_SET_FEATURE;+ cmd.n_addr = 1;+ cmd.addr[0] =+ cmd.n_tx = 1,+ cmd.tx_buf = buf,++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0)+
pr_err("err: %d write register %d\n", ret, reg);++ +}++/**+ * spinand_read_status - get status register value+ * @chip: SPI-NAND device structure+ * @status: buffer to store value+ * Description:+ *
After read, write, or erase, the Nand device is expected to set the+ *
busy status.+ *
This function is to allow reading the status of the command: read,+ *
write, and erase.+ *
Once the status turns to be ready, the other status bits also are+ *
valid status bits.+ */+static int spinand_read_status(struct spinand_device *chip, uint8_t *status)+{+ return spinand_read_reg(chip, REG_STATUS, status);+}++/**+ * spinand_wait - wait until the command is done+ * @chip: SPI-NAND device structure+ * @s: buffer to store status register(can be NULL)+ */+static int spinand_wait(struct spinand_device *chip, u8 *s)+{+ unsigned long timeo = msecs_to_jiffies(400);+ u8++ do {+
spinand_read_status(chip, &status);+
if ((status & STATUS_OIP_MASK) == STATUS_READY)+
+ } while (time_before(jiffies, timeo));++ /*+
* Extra read, just in case the STATUS_READY bit has changed+
* since out last check+
*/+ spinand_read_status(chip, &status);+out:+ if (s)+
*s =++ return (status & STATUS_OIP_MASK) == STATUS_READY ? 0 : -ETIMEDOUT;;+}++/**+ * spinand_read_id - send 9Fh command to get ID+ * @chip: SPI-NAND device structure+ * @buf: buffer to store id+ */+static int spinand_read_id(struct spinand_device *chip, u8 *buf)+{+ struct spinand_++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_READ_ID;+ if (chip-&manufacturer.ops-&get_dummy)+
cmd.dummy_bytes = chip-&manufacturer.ops-&get_dummy(chip, &cmd);+ cmd.n_rx = 2;+ cmd.rx_buf =++ return spinand_exec_cmd(chip, &cmd);+}++/**+ * spinand_reset - send command FFh to reset chip.+ * @chip: SPI-NAND device structure+ */+static int spinand_reset(struct spinand_device *chip)+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_RESET;++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0) {+
pr_err("spinand reset failed!\n");+
+ }+ ret = spinand_wait(chip, NULL);+out:+ +}++/**+ * spinand_lock_block - write block lock register to+ * lock/unlock device+ * @spi: spi device structure+ * @lock: value to set to block lock register+ * Description:+ *
After power up, all the Nand blocks are locked.
This function allows+ *
one to unlock the blocks, and so it can be written or erased.+ */+static int spinand_lock_block(struct spinand_device *chip, u8 lock)+{+ return spinand_write_reg(chip, REG_BLOCK_LOCK, &lock);+}++/**+ * spinand_scan_id_table - scan chip info in id table+ * @chip: SPI-NAND device structure+ * @id: point to manufacture id and device id+ * Description:+ *
If found in id table, config chip with table information.+ */+static bool spinand_scan_id_table(struct spinand_device *chip, u8 *id)+{+ struct nand_device *nand = &chip-&+ struct spinand_flash *type = spinand_+ struct nand_memory_organization *memorg = &nand-&+ struct spinand_ecc_engine *ecc_engine = &chip-&ecc_++ for (; type-& type++) {+
if (id[0] == type-&mfr_id && id[1] == type-&dev_id) {+
chip-&name = type-&+
memorg-&eraseblocksize = type-&page_size+
* type-&pages_per_+
memorg-&pagesize = type-&page_+
memorg-&oobsize = type-&oob_+
memorg-&diesize =+
memorg-&eraseblocksize * type-&blks_per_+
memorg-&ndies = type-&luns_per_+
ecc_engine-&strength = type-&ecc_+
chip-&rw_mode = type-&rw_++
}+ }++ +}++/**+ * spinand_set_rd_wr_op - Chose the best read write command+ * @chip: SPI-NAND device structure+ * Description:+ *
Chose the fastest r/w command according to spi controller's ability.+ * Note:+ *
If 03h/0Bh follows SPI NAND protocol, there is no difference,+ *
while if follows SPI NOR protocol, 03h command is working under+ *
&=***@3.3V,&=***@1.8V; 0Bh command is working under+ *
***@3.3v, ***@1.8V.+ */+static void spinand_set_rd_wr_op(struct spinand_device *chip)+{+ u32 controller_cap = chip-&controller.+ u32 rw_mode = chip-&rw_++ if ((controller_cap & SPINAND_CAP_RD_QUAD) && (rw_mode & SPINAND_RD_QUAD))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_QUAD_IO;+ else if ((controller_cap & SPINAND_CAP_RD_X4) && (rw_mode & SPINAND_RD_X4))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_X4;+ else if ((controller_cap & SPINAND_CAP_RD_DUAL) && (rw_mode & SPINAND_RD_DUAL))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_DUAL_IO;+ else if ((controller_cap & SPINAND_CAP_RD_X2) && (rw_mode & SPINAND_RD_X2))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_X2;+ else+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_FAST;++ if ((controller_cap & SPINAND_CAP_WR_X4) && (rw_mode & SPINAND_WR_X4))+
chip-&write_cache_op = SPINAND_CMD_PROG_LOAD_X4;+ else+
chip-&write_cache_op = SPINAND_CMD_PROG_LOAD;+}++/*+ * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC+ * compliant and does not have a full-id or legacy-id entry in the nand_ids+ * table.+ */+static bool spinand_manufacturer_detect(struct spinand_device *chip)+{+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&detect)+
return chip-&manufacturer.ops-&detect(chip);+ +}++/*+ * Manufacturer initialization. This function is called for all NANDs including+ * ONFI and JEDEC compliant ones.+ * Manufacturer drivers should put all their specific initialization code in+ * their -&init() hook.+ */+static int spinand_manufacturer_init(struct spinand_device *chip)+{+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&init)+
return chip-&manufacturer.ops-&init(chip);++ return 0;+}++/*+ * Manufacturer cleanup. This function is called for all NANDs including+ * ONFI and JEDEC compliant ones.+ * Manufacturer drivers should put all their specific cleanup code in their+ * -&cleanup() hook.+ */+static void spinand_manufacturer_cleanup(struct spinand_device *chip)+{+ /* Release manufacturer private data */+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&cleanup)+
return chip-&manufacturer.ops-&cleanup(chip);+}++static void spinand_fill_id(struct spinand_device *chip, u8 *id)+{+ memcpy(chip-&id.data, id, SPINAND_MAX_ID_LEN);+ chip-&id.len = SPINAND_MAX_ID_LEN;+}++static u8 spinand_get_mfr_id(struct spinand_device *chip)+{+ return chip-&id.data[SPINAND_MFR_ID];+}++static u8 spinand_get_dev_id(struct spinand_device *chip)+{+ return chip-&id.data[SPINAND_DEV_ID];+}++static void spinand_set_manufacturer_ops(struct spinand_device *chip, u8 mfr_id)+{+ int i = 0;++ for (; spinand_manuf_ids[i].id != 0x0; i++) {+
if (spinand_manuf_ids[i].id == mfr_id)+
+ }+ chip-&manufacturer.ops = spinand_manuf_ids[i].+}++/**+ * spinand_scan_ident - [SPI-NAND Interface] Scan for the SPI-NAND device+ * @chip: SPI-NAND device structure+ * Description:+ *
This is the first phase of the initiazation. It reads the flash ID and+ *
sets up spinand_device fields accordingly.+ */+int spinand_scan_ident(struct spinand_device *chip, u8 expect_mfr_id)+{+ struct nand_device *nand = &chip-&+ u8 id[SPINAND_MAX_ID_LEN] = {0};+ int id_retry = 2;++ spinand_set_manufacturer_ops(chip, expect_mfr_id);+ spinand_reset(chip);+read_id:+ spinand_read_id(chip, id);+ if (spinand_scan_id_table(chip, id))+
goto ident_+ if (id_retry--)+
goto read_+ pr_info("SPI-NAND type mfr_id: %x, dev_id: %x is not in id table.\n",+
id[SPINAND_MFR_ID], id[SPINAND_DEV_ID]);+ if (spinand_manufacturer_detect(chip))+
goto ident_++ return -ENODEV;++ident_done:+ spinand_fill_id(chip, id);++ pr_info("SPI-NAND: %s is found.\n", chip-&name);+ pr_info("Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",+
spinand_get_mfr_id(chip), spinand_get_dev_id(chip));+ pr_info("%d MiB, block size: %d KiB, page size: %d, OOB size: %d\n",+
(int)(spinand_get_chip_size(chip) && 20), nand_eraseblock_size(nand) && 10,+
nand_page_size(nand), nand_per_page_oobsize(nand));+ spinand_set_manufacturer_ops(chip, spinand_get_mfr_id(chip));+ spinand_manufacturer_init(chip);+ spinand_set_rd_wr_op(chip);++ chip-&buf = kzalloc(nand_page_size(nand) + nand_per_page_oobsize(nand), GFP_KERNEL);+ if (!chip-&buf)+
return -ENOMEM;++ chip-&oobbuf = chip-&buf + nand_page_size(nand);+ spinand_lock_block(chip, BL_ALL_UNLOCKED);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_ident);++/**+ * spinand_scan_tail - [SPI-NAND Interface] Scan for the SPI-NAND device+ * @chip: SPI-NAND device structure+ * Description:+ *
This is the second phase of the initiazation. It fills out all the+ *
uninitialized fields of spinand_device and mtd fields.+ */+int spinand_scan_tail(struct spinand_device *chip)+{+ struct mtd_info *mtd = spinand_to_mtd(chip);+ struct nand_device *nand = mtd_to_nand(mtd);+ struct spinand_ecc_engine *ecc_engine = &chip-&ecc_+ ++ mutex_init(&chip-&lock);++ mtd-&name = chip-&+ mtd-&size = spinand_get_chip_size(chip);+ mtd-&erasesize = nand_eraseblock_size(nand);+ mtd-&writesize = nand_page_size(nand);+ mtd-&writebufsize = mtd-&+ mtd-&owner = THIS_MODULE;+ mtd-&type = MTD_NANDFLASH;+ mtd-&flags = MTD_CAP_NANDFLASH;+ if (!mtd-&ecc_strength)+
mtd-&ecc_strength = ecc_engine-&strength ?+
ecc_engine-&strength : 1;++ mtd-&oobsize = nand_per_page_oobsize(nand);+ ret = mtd_ooblayout_count_freebytes(mtd);+ if (ret & 0)+
ret = 0;+ mtd-&oobavail =++ if (!mtd-&bitflip_threshold)+
mtd-&bitflip_threshold = DIV_ROUND_UP(mtd-&ecc_strength * 3, 4);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_tail);++/**+ * spinand_scan_ident_release - [SPI-NAND Interface] Free resources+ * applied by spinand_scan_ident+ * @chip: SPI-NAND device structure+ */+int spinand_scan_ident_release(struct spinand_device *chip)+{+ spinand_manufacturer_cleanup(chip);+ kfree(chip-&buf);+ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_ident_release);++/**+ * spinand_scan_tail_release - [SPI-NAND Interface] Free resources+ * applied by spinand_scan_tail+ * @chip: SPI-NAND device structure+ */+int spinand_scan_tail_release(struct spinand_device *chip)+{+ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_tail_release);++/**+ * spinand_release - [SPI-NAND Interface] Free resources held by the SPI-NAND+ * device+ * @chip: SPI-NAND device structure+ */+int spinand_release(struct spinand_device *chip)+{+ struct mtd_info *mtd = spinand_to_mtd(chip);++ mtd_device_unregister(mtd);+ spinand_manufacturer_cleanup(chip);+ kfree(chip-&buf);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_release);++MODULE_DESCRIPTION("SPI NAND framework");+MODULE_AUTHOR("Peter Pan&***@&");+MODULE_LICENSE("GPL v2");diff --git a/drivers/mtd/nand/spi/spinand_ids.c b/drivers/mtd/nand/spi/spinand_ids.cnew file mode 100644index 06ae3--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_ids.c@@ -0,0 +1,29 @@+/**+* spi-nand-base.c+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#include &linux/module.h&+#include &linux/mtd/spinand.h&++struct spinand_flash spinand_table[] = {+ {.name = NULL},+};+++struct spinand_manufacturer spinand_manuf_ids[] = {+ {0x0, "Unknown"}+};++EXPORT_SYMBOL(spinand_manuf_ids);diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.hnew file mode 100644index 0000000..f3d0351--- /dev/null+++ b/include/linux/mtd/spinand.h@@ -0,0 +1,315 @@+/**+* spinand.h+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/+#ifndef __LINUX_MTD_SPINAND_H+#define __LINUX_MTD_SPINAND_H++#include &linux/wait.h&+#include &linux/spinlock.h&+#include &linux/mtd/mtd.h&+#include &linux/mtd/flashchip.h&+#include &linux/mtd/nand.h&++/*+ * Standard SPI-NAND flash commands+ */+#define SPINAND_CMD_RESET
0xff+#define SPINAND_CMD_GET_FEATURE
0x0f+#define SPINAND_CMD_SET_FEATURE
0x1f+#define SPINAND_CMD_PAGE_READ
0x13+#define SPINAND_CMD_READ_PAGE_CACHE_RDM
0x30+#define SPINAND_CMD_READ_PAGE_CACHE_LAST 0x3f+#define SPINAND_CMD_READ_FROM_CACHE
0x03+#define SPINAND_CMD_READ_FROM_CACHE_FAST 0x0b+#define SPINAND_CMD_READ_FROM_CACHE_X2
0x3b+#define SPINAND_CMD_READ_FROM_CACHE_DUAL_IO 0xbb+#define SPINAND_CMD_READ_FROM_CACHE_X4
0x6b+#define SPINAND_CMD_READ_FROM_CACHE_QUAD_IO 0xeb+#define SPINAND_CMD_BLK_ERASE
0xd8+#define SPINAND_CMD_PROG_EXC
0x10+#define SPINAND_CMD_PROG_LOAD
0x02+#define SPINAND_CMD_PROG_LOAD_RDM_DATA
0x84+#define SPINAND_CMD_PROG_LOAD_X4
0x32+#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4 0x34+#define SPINAND_CMD_READ_ID
0x9f+#define SPINAND_CMD_WR_DISABLE
0x04+#define SPINAND_CMD_WR_ENABLE
0x06+#define SPINAND_CMD_END
0x0+++/* feature registers */+#define REG_BLOCK_LOCK
0xa0+#define REG_CFG
0xb0+#define REG_STATUS
0xc0+#define REG_DIE_SELECT
0xd0++/* status */+#define STATUS_OIP_MASK
0x01+#define STATUS_CRBSY_MASK 0x80+#define STATUS_READY
(0 && 0)+#define STATUS_BUSY
(1 && 0)++#define STATUS_E_FAIL_MASK 0x04+#define STATUS_E_FAIL
(1 && 2)++#define STATUS_P_FAIL_MASK 0x08+#define STATUS_P_FAIL
(1 && 3)+++/*Configuration register defines*/+#define CFG_QE_MASK
0x01+#define CFG_QE_ENABLE
0x01+#define CFG_ECC_MASK
0x10+#define CFG_ECC_ENABLE
0x10+#define CFG_LOT_MASK
0x20+#define CFG_LOT_ENABLE
0x20+#define CFG_OTP_MASK
0xc2+#define CFG_OTP_ENTER
0x40+#define CFG_OTP_EXIT
0x00++/* block lock */+#define BL_ALL_LOCKED
0x7c+#define BL_U_1_1024_LOCKED
0x08+#define BL_U_1_512_LOCKED
0x10+#define BL_U_1_256_LOCKED
0x18+#define BL_U_1_128_LOCKED
0x20+#define BL_U_1_64_LOCKED
0x28+#define BL_U_1_32_LOCKED
0x30+#define BL_U_1_16_LOCKED
0x38+#define BL_U_1_8_LOCKED
0x40+#define BL_U_1_4_LOCKED
0x48+#define BL_U_1_2_LOCKED
0x50+#define BL_L_1_1024_LOCKED
0x0c+#define BL_L_1_512_LOCKED
0x14+#define BL_L_1_256_LOCKED
0x1c+#define BL_L_1_128_LOCKED
0x24+#define BL_L_1_64_LOCKED
0x2c+#define BL_L_1_32_LOCKED
0x34+#define BL_L_1_16_LOCKED
0x3c+#define BL_L_1_8_LOCKED
0x44+#define BL_L_1_4_LOCKED
0x4c+#define BL_L_1_2_LOCKED
0x54+#define BL_ALL_UNLOCKED
0X00++/* die select */+#define DIE_SELECT_MASK
0x40+#define DIE_SELECT_DS0
0x00+#define DIE_SELECT_DS1
0x40+++struct spinand_+struct spinand_++#define SPINAND_MAX_ID_LEN
2+/**+ * struct nand_id - NAND id structure+ * @data: buffer containing the id bytes. Currently 8 bytes large, but can+ *
be extended if required.+ * @len: ID length.+ */+struct spinand_id {+ #define SPINAND_MFR_ID
0+ #define SPINAND_DEV_ID
1+ u8 data[SPINAND_MAX_ID_LEN];+ +};++struct spinand_controller_ops {+ int (*exec_op)(struct spinand_device *chip,+
struct spinand_op *op);+};++struct spinand_manufacturer_ops {+ bool(*detect)(struct spinand_device *chip);+ int (*init)(struct spinand_device *chip);+ void (*cleanup)(struct spinand_device *chip);+ int (*get_dummy)(struct spinand_device *chip, struct spinand_op *op);+};++struct spinand_manufacturer {+ u8+ char *+ struct spinand_manufacturer_ops *+};++extern struct spinand_manufacturer spinand_manuf_ids[];++struct spinand_ecc_engine_ops {+ void (*get_ecc_status)(struct spinand_device *chip, unsigned int status,+
unsigned int *corrected, unsigned int *ecc_errors);+ void (*disable_ecc)(struct spinand_device *chip);+ void (*enable_ecc)(struct spinand_device *chip);+};++typedef enum {+ SPINAND_ECC_ONDIE,+ SPINAND_ECC_HW,+} spinand_ecc_modes_t;+++struct spinand_ecc_engine {+ spinand_ecc_modes_+ u32+ u32+ struct spinand_ecc_engine_ops *+};++/**+ * struct spinand_device - SPI-NAND Private Flash Chip Data+ * @base: NAND device instance+ * @lock: protection lock+ * @name: name of the chip+ * @id: ID structure+ * @read_cache_op: Opcode of read from cache+ * @write_cache_op: Opcode of program load+ * @buf: buffer for read/write data+ * @oobbuf: buffer for read/write oob+ * @rw_mode: read/write mode of SPI NAND chip+ * @controller: SPI NAND controller instance+ * @manufacturer: SPI NAND manufacturer instance, describe+ *
manufacturer related objects+ * @ecc_engine: SPI NAND ECC engine instance+ */+struct spinand_device {+ struct nand_+ + char *+ struct spinand_+ u8 read_cache_+ u8 write_cache_+ u8 *+ u8 *+ u32 rw_+ struct {+
struct spinand_controller_ops *+#define SPINAND_CAP_RD_X1 (1 && 0)+#define SPINAND_CAP_RD_X2 (1 && 1)+#define SPINAND_CAP_RD_X4 (1 && 2)+#define SPINAND_CAP_RD_DUAL (1 && 3)+#define SPINAND_CAP_RD_QUAD (1 && 4)+#define SPINAND_CAP_WR_X1 (1 && 5)+#define SPINAND_CAP_WR_X2 (1 && 6)+#define SPINAND_CAP_WR_X4 (1 && 7)+#define SPINAND_CAP_WR_DUAL (1 && 8)+#define SPINAND_CAP_WR_QUAD (1 && 9)+#define SPINAND_CAP_HW_ECC (1 && 10)+
void *+ }+ struct {+
struct spinand_manufacturer_ops *+
void *+ }+ struct spinand_ecc_engine ecc_+};++static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)+{+ return container_of(mtd_to_nand(mtd), struct spinand_device, base);+}++static inline struct mtd_info *spinand_to_mtd(struct spinand_device *chip)+{+ return nand_to_mtd(&chip-&base);+}++static inline void spinand_set_controller_data(struct spinand_device *chip,+
void *data)+{+ chip-&controller.priv =+}++static inline void *spinand_get_controller_data(struct spinand_device *chip)+{+ return chip-&controller.+}+++struct spinand_flash {+ char *+ u8 mfr_+ u8 dev_+ u32 page_+ u32 oob_+ u32 pages_per_+ u32 blks_per_+ u32 luns_per_+ u32 ecc_+ u32+ u32 rw_+};++extern struct spinand_flash spinand_table[];++#define SPINAND_MAX_ADDR_LEN
4++struct spinand_op {+ u8+ u8 n_+ u8 addr_+ u8 dummy_+ u8 addr[SPINAND_MAX_ADDR_LEN];+ u32 n_+ const u8 *tx_+ u32 n_+ u8 *rx_+ u8 data_+};++struct spinand_op_def {+ u8+ u8 addr_+ u8 addr_+ u8 dummy_+ u8 data_+};++/* SPI NAND supported OP mode */+#define SPINAND_RD_X1
0x+#define SPINAND_RD_X2
0x+#define SPINAND_RD_X4
0x+#define SPINAND_RD_DUAL
0x+#define SPINAND_RD_QUAD
0x+#define SPINAND_WR_X1
0x+#define SPINAND_WR_X2
0x+#define SPINAND_WR_X4
0x+#define SPINAND_WR_DUAL
0x+#define SPINAND_WR_QUAD
0x++#define SPINAND_RD_COMMON SPINAND_RD_X1 | SPINAND_RD_X2 | \+
SPINAND_RD_X4 | SPINAND_RD_DUAL | \+
SPINAND_RD_QUAD+#define SPINAND_WR_COMMON SPINAND_WR_X1 | SPINAND_WR_X4+#define SPINAND_OP_COMMON SPINAND_RD_COMMON | SPINAND_WR_COMMON++#define SPI_NAND_INFO(nm, mid, did, pagesz, oobsz, pg_per_blk,\+ blk_per_lun, lun_per_chip, ecc_stren, rwmode) \+ { .name = (nm), .mfr_id = (mid), .dev_id = (did),\+ .page_size = (pagesz), .oob_size = (oobsz),\+ .pages_per_blk = (pg_per_blk), .blks_per_lun = (blk_per_lun),\+ .luns_per_chip = (lun_per_chip), .ecc_strength = (ecc_stren),\+ .rw_mode = (rwmode) }++/*SPI NAND manufacture ID definition*/+#define SPINAND_MFR_MICRON
0x2C++int spinand_scan_ident(struct spinand_device *chip, u8 expect_mfr_id);+int spinand_scan_tail(struct spinand_device *chip);+int spinand_scan_ident_release(struct spinand_device *chip);+int spinand_scan_tail_release(struct spinand_device *chip);+int spinand_release(struct spinand_device *chip);+int spinand_set_cmd_cfg_table(int mfr);+struct spinand_op_def *spinand_get_cmd_cfg(u8 opcode);+#endif /* __LINUX_MTD_SPINAND_H */--1.9.1
Raw Message
+ArnaudHi Peter,Can you please Cc Arnaud (and in general all reviewers) each time yousend a new version.On Wed, 1 Mar :05 +0800This is the first commit for spi nand framkework.This commit is to add spi nand initialization andrelease functions.Hm, actually you're doing more than that. Just say that you add basicbuilding blocks for the SPI NAND infrastructure.---drivers/mtd/nand/Kconfig
1 +drivers/mtd/nand/Makefile
1 +drivers/mtd/nand/spi/Kconfig
5 +drivers/mtd/nand/spi/Makefile
2 +drivers/mtd/nand/spi/spinand_base.c | 469 ++++++++++++++++++++++++++++++++++++drivers/mtd/nand/spi/spinand_ids.c
29 +++include/linux/mtd/spinand.h
| 315 ++++++++++++++++++++++++If you're okay with that, I'd like you to add an entry in MAINTAINERSfor the spinand sub-sub-sub-system :-). This way you'll be tagged asthe maintainer of this code and will be Cc when a patch is submitted.7 files changed, 822 insertions(+)create mode 100644 drivers/mtd/nand/spi/Kconfigcreate mode 100644 drivers/mtd/nand/spi/Makefilecreate mode 100644 drivers/mtd/nand/spi/spinand_base.ccreate mode 100644 drivers/mtd/nand/spi/spinand_ids.ccreate mode 100644 include/linux/mtd/spinand.hdiff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfigindex 1c1a1f4..644--- a/drivers/mtd/nand/Kconfig+++ b/drivers/mtd/nand/Kconfig@@ -2,3 +2,4 @@ config MTD_NAND_COREtristatesource "drivers/mtd/nand/raw/Kconfig"+source "drivers/mtd/nand/spi/Kconfig"diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefileindex fe430d9..644--- a/drivers/mtd/nand/Makefile+++ b/drivers/mtd/nand/Makefile@@ -3,3 +3,4 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.onandcore-objs :=
bbt.oobj-y += raw/+obj-$(CONFIG_MTD_SPI_NAND) += spi/diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfignew file mode 100644index a7b71--- /dev/null+++ b/drivers/mtd/nand/spi/Kconfig@@ -0,0 +1,5 @@+menuconfig MTD_SPI_NAND+ tristate "SPI-NAND device Support"+ depends on MTD_NAND+ help+
This is the framework for the SPI NAND device drivers.diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefilenew file mode 100644index f0d622--- /dev/null+++ b/drivers/mtd/nand/spi/Makefile@@ -0,0 +1,2 @@+obj-$(CONFIG_MTD_SPI_NAND) += spinand_base.o+obj-$(CONFIG_MTD_SPI_NAND) += spinand_ids.odiff --git a/drivers/mtd/nand/spi/spinand_base.c b/drivers/mtd/nand/spi/spinand_base.cnew file mode 100644index d47146--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_base.cHow about renaming this file into core.c?@@ -0,0 +1,469 @@+/**+* spi-nand-base.cPlease do not put the file name in the copyright header. It's not evencorrect, which shows how useless -).+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt++#include &linux/kernel.h&+#include &linux/module.h&+#include &linux/sched.h&+#include &linux/delay.h&+#include &linux/jiffies.h&+#include &linux/mtd/spinand.h&+#include &linux/slab.h&+++static u64 spinand_get_chip_size(struct spinand_device *chip)I would change the parameter name here: s/chip/spinand/. This isapplicable to the whole submission.+{+ struct nand_device *nand = &chip-&++ return nand_diesize(nand) * nand_ndies(nand);+}Probably something that should go in include/linux/mtd/nand.h ordrivers/mtd/nand/core.c.++static inline int spinand_exec_cmd(struct spinand_device *chip,+
struct spinand_op *cmd)+{+ return chip-&controller.ops-&exec_op(chip, cmd);+}++static inline void spinand_op_init(struct spinand_op *op)+{+ memset(op, 0, sizeof(struct spinand_op));+ op-&addr_nbits = 1;+ op-&data_nbits = 1;+}++/**+ * spinand_read_reg - send command 0Fh to read register+ */+static int spinand_read_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)Align parameters on the open parenthesis (run checkpatch.pl --strictand fix everything you can).+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_GET_FEATURE;+ cmd.n_addr = 1;+ cmd.addr[0] =+ cmd.n_rx = 1;+ cmd.rx_buf =++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0)+
pr_err("err: %d read register %d\n", ret, reg);++ +}++/**+ * spinand_write_reg - send command 1Fh to write register+ */+static int spinand_write_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_SET_FEATURE;+ cmd.n_addr = 1;+ cmd.addr[0] =+ cmd.n_tx = 1,+ cmd.tx_buf = buf,++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0)+
pr_err("err: %d write register %d\n", ret, reg);++ +}++/**+ * spinand_read_status - get status register value+ *
After read, write, or erase, the Nand device is expected to set the+ *
busy status.+ *
This function is to allow reading the status of the command: read,+ *
write, and erase.+ *
Once the status turns to be ready, the other status bits also are+ *
valid status bits.+ */+static int spinand_read_status(struct spinand_device *chip, uint8_t *status)+{+ return spinand_read_reg(chip, REG_STATUS, status);+}++/**+ * spinand_wait - wait until the command is done+ */+static int spinand_wait(struct spinand_device *chip, u8 *s)+{+ unsigned long timeo = msecs_to_jiffies(400);+ u8++ do {+
spinand_read_status(chip, &status);+
if ((status & STATUS_OIP_MASK) == STATUS_READY)+
+ } while (time_before(jiffies, timeo));++ /*+
* Extra read, just in case the STATUS_READY bit has changed+
* since out last check^ our last check.+
*/+ spinand_read_status(chip, &status);+ if (s)+
*s =++ return (status & STATUS_OIP_MASK) == STATUS_READY ? 0 : -ETIMEDOUT;;Extra semi-colon at the end of the line.+}++/**+ * spinand_read_id - send 9Fh command to get ID+ */+static int spinand_read_id(struct spinand_device *chip, u8 *buf)+{+ struct spinand_++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_READ_ID;+ if (chip-&manufacturer.ops-&get_dummy)+
cmd.dummy_bytes = chip-&manufacturer.ops-&get_dummy(chip, &cmd);+ cmd.n_rx = 2;+ cmd.rx_buf =++ return spinand_exec_cmd(chip, &cmd);+}++/**+ * spinand_reset - send command FFh to reset chip.+ */+static int spinand_reset(struct spinand_device *chip)+{+ struct spinand_+ ++ spinand_op_init(&cmd);+ cmd.cmd = SPINAND_CMD_RESET;++ ret = spinand_exec_cmd(chip, &cmd);+ if (ret & 0) {+
pr_err("spinand reset failed!\n");+
+ }+ ret = spinand_wait(chip, NULL);Add an empty line here.+ +}++/**+ * spinand_lock_block - write block lock register to+ * lock/unlock device+ *
After power up, all the Nand blocks are locked.
This function allows+ *
one to unlock the blocks, and so it can be written or erased.+ */+static int spinand_lock_block(struct spinand_device *chip, u8 lock)+{+ return spinand_write_reg(chip, REG_BLOCK_LOCK, &lock);+}++/**+ * spinand_scan_id_table - scan chip info in id table+ *
If found in id table, config chip with table information.+ */+static bool spinand_scan_id_table(struct spinand_device *chip, u8 *id)+{+ struct nand_device *nand = &chip-&+ struct spinand_flash *type = spinand_+ struct nand_memory_organization *memorg = &nand-&+ struct spinand_ecc_engine *ecc_engine = &chip-&ecc_++ for (; type-& type++) {+
if (id[0] == type-&mfr_id && id[1] == type-&dev_id) {+
chip-&name = type-&+
memorg-&eraseblocksize = type-&page_size+
* type-&pages_per_+
memorg-&pagesize = type-&page_+
memorg-&oobsize = type-&oob_+
memorg-&diesize =+
memorg-&eraseblocksize * type-&blks_per_+
memorg-&ndies = type-&luns_per_+
ecc_engine-&strength = type-&ecc_+
chip-&rw_mode = type-&rw_++
}+ }++ +}++/**+ * spinand_set_rd_wr_op - Chose the best read write command+ *
Chose the fastest r/w command according to spi controller's ability.+ *
If 03h/0Bh follows SPI NAND protocol, there is no difference,+ *
while if follows SPI NOR protocol, 03h command is working under+ */+static void spinand_set_rd_wr_op(struct spinand_device *chip)+{+ u32 controller_cap = chip-&controller.+ u32 rw_mode = chip-&rw_++ if ((controller_cap & SPINAND_CAP_RD_QUAD) && (rw_mode & SPINAND_RD_QUAD))Try to make checkpatch happy here as well:if ((controller_cap & SPINAND_CAP_RD_QUAD) &&(rw_mode & SPINAND_RD_QUAD))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_QUAD_IO;+ else if ((controller_cap & SPINAND_CAP_RD_X4) && (rw_mode & SPINAND_RD_X4))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_X4;+ else if ((controller_cap & SPINAND_CAP_RD_DUAL) && (rw_mode & SPINAND_RD_DUAL))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_DUAL_IO;+ else if ((controller_cap & SPINAND_CAP_RD_X2) && (rw_mode & SPINAND_RD_X2))+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_X2;+ else+
chip-&read_cache_op = SPINAND_CMD_READ_FROM_CACHE_FAST;++ if ((controller_cap & SPINAND_CAP_WR_X4) && (rw_mode & SPINAND_WR_X4))+
chip-&write_cache_op = SPINAND_CMD_PROG_LOAD_X4;+ else+
chip-&write_cache_op = SPINAND_CMD_PROG_LOAD;+}++/*+ * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC+ * compliant and does not have a full-id or legacy-id entry in the nand_ids+ * table.+ */+static bool spinand_manufacturer_detect(struct spinand_device *chip)+{+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&detect)+
return chip-&manufacturer.ops-&detect(chip);Add an empty line.+ +}++/*+ * Manufacturer initialization. This function is called for all NANDs including+ * ONFI and JEDEC compliant ones.+ * Manufacturer drivers should put all their specific initialization code in+ * their -&init() hook.+ */+static int spinand_manufacturer_init(struct spinand_device *chip)+{+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&init)+
return chip-&manufacturer.ops-&init(chip);++ return 0;+}++/*+ * Manufacturer cleanup. This function is called for all NANDs including+ * ONFI and JEDEC compliant ones.+ * Manufacturer drivers should put all their specific cleanup code in their+ * -&cleanup() hook.+ */+static void spinand_manufacturer_cleanup(struct spinand_device *chip)+{+ /* Release manufacturer private data */+ if (chip-&manufacturer.ops && chip-&manufacturer.ops-&cleanup)+
return chip-&manufacturer.ops-&cleanup(chip);+}++static void spinand_fill_id(struct spinand_device *chip, u8 *id)+{+ memcpy(chip-&id.data, id, SPINAND_MAX_ID_LEN);+ chip-&id.len = SPINAND_MAX_ID_LEN;+}++static u8 spinand_get_mfr_id(struct spinand_device *chip)+{+ return chip-&id.data[SPINAND_MFR_ID];+}++static u8 spinand_get_dev_id(struct spinand_device *chip)+{+ return chip-&id.data[SPINAND_DEV_ID];+}++static void spinand_set_manufacturer_ops(struct spinand_device *chip, u8 mfr_id)+{+ int i = 0;++ for (; spinand_manuf_ids[i].id != 0x0; i++) {+
if (spinand_manuf_ids[i].id == mfr_id)+
+ }Add an empty line here.+ chip-&manufacturer.ops = spinand_manuf_ids[i].+}++/**+ * spinand_scan_ident - [SPI-NAND Interface] Scan for the SPI-NAND device+ *
This is the first phase of the initiazation. It reads the flash ID and+ *
sets up spinand_device fields accordingly.+ */+int spinand_scan_ident(struct spinand_device *chip, u8 expect_mfr_id)+{+ struct nand_device *nand = &chip-&+ u8 id[SPINAND_MAX_ID_LEN] = {0};+ int id_retry = 2;++ spinand_set_manufacturer_ops(chip, expect_mfr_id);+ spinand_reset(chip);+ spinand_read_id(chip, id);+ if (spinand_scan_id_table(chip, id))+
goto ident_+ if (id_retry--)+
goto read_+ pr_info("SPI-NAND type mfr_id: %x, dev_id: %x is not in id table.\n",+
id[SPINAND_MFR_ID], id[SPINAND_DEV_ID]);+ if (spinand_manufacturer_detect(chip))+
goto ident_++ return -ENODEV;+for (i = 0; i & MAX_READID_RETRY; i++) {ret = spinand_read_id(chip, id);if (ret)if (spinand_scan_id_table(chip, id))if (spinand_manufacturer_detect(chip))}if (i == MAX_READID_RETRY) {/* Error message. */return -ENODEV;}BTW, why do we need to retry 2 times? I thought that ifspinand_read_id() returns 0 this means we read the ID correctly, and ifthe NAND detection fails once it will always fail.+ spinand_fill_id(chip, id);++ pr_info("SPI-NAND: %s is found.\n", chip-&name);+ pr_info("Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",+
spinand_get_mfr_id(chip), spinand_get_dev_id(chip));+ pr_info("%d MiB, block size: %d KiB, page size: %d, OOB size: %d\n",+
(int)(spinand_get_chip_size(chip) && 20), nand_eraseblock_size(nand) && 10,+
nand_page_size(nand), nand_per_page_oobsize(nand));+ spinand_set_manufacturer_ops(chip, spinand_get_mfr_id(chip));+ spinand_manufacturer_init(chip);+ spinand_set_rd_wr_op(chip);++ chip-&buf = kzalloc(nand_page_size(nand) + nand_per_page_oobsize(nand), GFP_KERNEL);+ if (!chip-&buf)+
return -ENOMEM;++ chip-&oobbuf = chip-&buf + nand_page_size(nand);+ spinand_lock_block(chip, BL_ALL_UNLOCKED);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_ident);++/**+ * spinand_scan_tail - [SPI-NAND Interface] Scan for the SPI-NAND device+ *
This is the second phase of the initiazation. It fills out all the+ *
uninitialized fields of spinand_device and mtd fields.+ */+int spinand_scan_tail(struct spinand_device *chip)+{+ struct mtd_info *mtd = spinand_to_mtd(chip);+ struct nand_device *nand = mtd_to_nand(mtd);+ struct spinand_ecc_engine *ecc_engine = &chip-&ecc_+ ++ mutex_init(&chip-&lock);++ mtd-&name = chip-&+ mtd-&size = spinand_get_chip_size(chip);+ mtd-&erasesize = nand_eraseblock_size(nand);+ mtd-&writesize = nand_page_size(nand);+ mtd-&writebufsize = mtd-&+ mtd-&owner = THIS_MODULE;+ mtd-&type = MTD_NANDFLASH;+ mtd-&flags = MTD_CAP_NANDFLASH;+ if (!mtd-&ecc_strength)+
mtd-&ecc_strength = ecc_engine-&strength ?+
ecc_engine-&strength : 1;++ mtd-&oobsize = nand_per_page_oobsize(nand);+ ret = mtd_ooblayout_count_freebytes(mtd);+ if (ret & 0)+
ret = 0;+ mtd-&oobavail =++ if (!mtd-&bitflip_threshold)+
mtd-&bitflip_threshold = DIV_ROUND_UP(mtd-&ecc_strength * 3, 4);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_tail);++/**+ * spinand_scan_ident_release - [SPI-NAND Interface] Free resources+ * applied by spinand_scan_ident+ */+int spinand_scan_ident_release(struct spinand_device *chip)+{+ spinand_manufacturer_cleanup(chip);+ kfree(chip-&buf);+ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_ident_release);Drop this function, and only define spinand_release++/**+ * spinand_scan_tail_release - [SPI-NAND Interface] Free resources+ * applied by spinand_scan_tail+ */+int spinand_scan_tail_release(struct spinand_device *chip)+{+ return 0;+}+EXPORT_SYMBOL_GPL(spinand_scan_tail_release);Why is this needed?++/**+ * spinand_release - [SPI-NAND Interface] Free resources held by the SPI-NAND+ * device+ */+int spinand_release(struct spinand_device *chip)I'd call it spinand_cleanup(), because the spinand device has not beenallocated by the core.+{+ struct mtd_info *mtd = spinand_to_mtd(chip);++ mtd_device_unregister(mtd);Please don't do that. I know it's taken directly from the // NANDframework, but it is confusing: the MTD dev registration is left to theSPI NAND controller, so we should let it unregister the MTD device byhimself.+ spinand_manufacturer_cleanup(chip);+ kfree(chip-&buf);++ return 0;+}+EXPORT_SYMBOL_GPL(spinand_release);++MODULE_DESCRIPTION("SPI NAND framework");+MODULE_LICENSE("GPL v2");diff --git a/drivers/mtd/nand/spi/spinand_ids.c b/drivers/mtd/nand/spi/spinand_ids.cnew file mode 100644index 06ae3--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_ids.cRemove the spinand_ prefix in the file name, we know it's spinandrelated thanks to the path (drivers/mtd/nand/spi/):s/spinand_ids.c/ids.c/@@ -0,0 +1,29 @@+/**+* spi-nand-base.c+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#include &linux/module.h&+#include &linux/mtd/spinand.h&++struct spinand_flash spinand_table[] = {+ {.name = NULL},+};+++struct spinand_manufacturer spinand_manuf_ids[] = {+ {0x0, "Unknown"}+};++EXPORT_SYMBOL(spinand_manuf_ids);diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.hnew file mode 100644index 0000000..f3d0351--- /dev/null+++ b/include/linux/mtd/spinand.h@@ -0,0 +1,315 @@+/**+* spinand.h+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/+#ifndef __LINUX_MTD_SPINAND_H+#define __LINUX_MTD_SPINAND_H++#include &linux/wait.h&+#include &linux/spinlock.h&+#include &linux/mtd/mtd.h&+#include &linux/mtd/flashchip.h&+#include &linux/mtd/nand.h&++/*+ * Standard SPI-NAND flash commands+ */+#define SPINAND_CMD_RESET
0xff+#define SPINAND_CMD_GET_FEATURE
0x0f+#define SPINAND_CMD_SET_FEATURE
0x1f+#define SPINAND_CMD_PAGE_READ
0x13+#define SPINAND_CMD_READ_PAGE_CACHE_RDM
0x30+#define SPINAND_CMD_READ_PAGE_CACHE_LAST 0x3f+#define SPINAND_CMD_READ_FROM_CACHE
0x03+#define SPINAND_CMD_READ_FROM_CACHE_FAST 0x0b+#define SPINAND_CMD_READ_FROM_CACHE_X2
0x3b+#define SPINAND_CMD_READ_FROM_CACHE_DUAL_IO 0xbb+#define SPINAND_CMD_READ_FROM_CACHE_X4
0x6b+#define SPINAND_CMD_READ_FROM_CACHE_QUAD_IO 0xeb+#define SPINAND_CMD_BLK_ERASE
0xd8+#define SPINAND_CMD_PROG_EXC
0x10+#define SPINAND_CMD_PROG_LOAD
0x02+#define SPINAND_CMD_PROG_LOAD_RDM_DATA
0x84+#define SPINAND_CMD_PROG_LOAD_X4
0x32+#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4 0x34+#define SPINAND_CMD_READ_ID
0x9f+#define SPINAND_CMD_WR_DISABLE
0x04+#define SPINAND_CMD_WR_ENABLE
0x06+#define SPINAND_CMD_END
0x0+++/* feature registers */+#define REG_BLOCK_LOCK
0xa0+#define REG_CFG
0xb0+#define REG_STATUS
0xc0+#define REG_DIE_SELECT
0xd0++/* status */+#define STATUS_OIP_MASK
0x01+#define STATUS_CRBSY_MASK 0x80+#define STATUS_READY
(0 && 0)+#define STATUS_BUSY
(1 && 0)++#define STATUS_E_FAIL_MASK 0x04+#define STATUS_E_FAIL
(1 && 2)++#define STATUS_P_FAIL_MASK 0x08+#define STATUS_P_FAIL
(1 && 3)+++/*Configuration register defines*/+#define CFG_QE_MASK
0x01+#define CFG_QE_ENABLE
0x01+#define CFG_ECC_MASK
0x10+#define CFG_ECC_ENABLE
0x10+#define CFG_LOT_MASK
0x20+#define CFG_LOT_ENABLE
0x20+#define CFG_OTP_MASK
0xc2+#define CFG_OTP_ENTER
0x40+#define CFG_OTP_EXIT
0x00++/* block lock */+#define BL_ALL_LOCKED
0x7c+#define BL_U_1_1024_LOCKED
0x08+#define BL_U_1_512_LOCKED
0x10+#define BL_U_1_256_LOCKED
0x18+#define BL_U_1_128_LOCKED
0x20+#define BL_U_1_64_LOCKED
0x28+#define BL_U_1_32_LOCKED
0x30+#define BL_U_1_16_LOCKED
0x38+#define BL_U_1_8_LOCKED
0x40+#define BL_U_1_4_LOCKED
0x48+#define BL_U_1_2_LOCKED
0x50+#define BL_L_1_1024_LOCKED
0x0c+#define BL_L_1_512_LOCKED
0x14+#define BL_L_1_256_LOCKED
0x1c+#define BL_L_1_128_LOCKED
0x24+#define BL_L_1_64_LOCKED
0x2c+#define BL_L_1_32_LOCKED
0x34+#define BL_L_1_16_LOCKED
0x3c+#define BL_L_1_8_LOCKED
0x44+#define BL_L_1_4_LOCKED
0x4c+#define BL_L_1_2_LOCKED
0x54+#define BL_ALL_UNLOCKED
0X00++/* die select */+#define DIE_SELECT_MASK
0x40+#define DIE_SELECT_DS0
0x00+#define DIE_SELECT_DS1
0x40+++struct spinand_+struct spinand_++#define SPINAND_MAX_ID_LEN
2+/**+ * struct nand_id - NAND id structure+ *
be extended if required.+ */+struct spinand_id {+ #define SPINAND_MFR_ID
0+ #define SPINAND_DEV_ID
1Please move these defines just below the SPINAND_MAX_ID_LEN definition.+ u8 data[SPINAND_MAX_ID_LEN];+ +};++struct spinand_controller_ops {+ int (*exec_op)(struct spinand_device *chip,+
struct spinand_op *op);+};++struct spinand_manufacturer_ops {+ bool(*detect)(struct spinand_device *chip);+ int (*init)(struct spinand_device *chip);+ void (*cleanup)(struct spinand_device *chip);+ int (*get_dummy)(struct spinand_device *chip, struct spinand_op *op);+};++struct spinand_manufacturer {+ u8+ char *+ struct spinand_manufacturer_ops *+};++extern struct spinand_manufacturer spinand_manuf_ids[];++struct spinand_ecc_engine_ops {+ void (*get_ecc_status)(struct spinand_device *chip, unsigned int status,+
unsigned int *corrected, unsigned int *ecc_errors);+ void (*disable_ecc)(struct spinand_device *chip);+ void (*enable_ecc)(struct spinand_device *chip);+};At some point we should find a way to make the ECC handling generic(there's nothing SPINAND specific here), but let's keep that for later.++typedef enum {+ SPINAND_ECC_ONDIE,+ SPINAND_ECC_HW,+} spinand_ecc_modes_t;No typedefs, justenum spinand_ecc_mode {SPINAND_ECC_ONDIE,...};+++struct spinand_ecc_engine {+ spinand_ecc_modes_+ u32+ u32+ struct spinand_ecc_engine_ops *+};++/**+ * struct spinand_device - SPI-NAND Private Flash Chip Data+ *
manufacturer related objects+ */+struct spinand_device {+ struct nand_+ + char *+ struct spinand_+ u8 read_cache_+ u8 write_cache_+ u8 *+ u8 *+ u32 rw_+ struct {+
struct spinand_controller_ops *+#define SPINAND_CAP_RD_X1 (1 && 0)+#define SPINAND_CAP_RD_X2 (1 && 1)+#define SPINAND_CAP_RD_X4 (1 && 2)+#define SPINAND_CAP_RD_DUAL (1 && 3)+#define SPINAND_CAP_RD_QUAD (1 && 4)+#define SPINAND_CAP_WR_X1 (1 && 5)+#define SPINAND_CAP_WR_X2 (1 && 6)+#define SPINAND_CAP_WR_X4 (1 && 7)+#define SPINAND_CAP_WR_DUAL (1 && 8)+#define SPINAND_CAP_WR_QUAD (1 && 9)+#define SPINAND_CAP_HW_ECC (1 && 10)Again, I don't like when struct definitions and macros are intermixed.Please move that before the struct def.+
void *+ }Hm, shouldn't we point to a spinand_controller object? I mean, maybethere are some situations where you have a single spinand_controllerwhich interacts with several spinand devices.struct spinand_controller {struct spinand_controller_ops *u32};and then in spinand_device:struct spinand_device {struct {struct spinand_controller *void *}}+ struct {+
struct spinand_manufacturer_ops *Should be const, and let's store the spinand_manufacturer pointerdirectly, this way we have the manufacture name directly accessible.+
void *+ }+ struct spinand_ecc_engine ecc_Same here, the ECC engine should allocated separately, andspinand_device should point to it.struct {struct spinand_ecc_engine *void *}+};++static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)+{+ return container_of(mtd_to_nand(mtd), struct spinand_device, base);+}++static inline struct mtd_info *spinand_to_mtd(struct spinand_device *chip)+{+ return nand_to_mtd(&chip-&base);+}++static inline void spinand_set_controller_data(struct spinand_device *chip,+
void *data)+{+ chip-&controller.priv =+}++static inline void *spinand_get_controller_data(struct spinand_device *chip)+{+ return chip-&controller.+}+++struct spinand_flash {s/spinand_flash/spinand_desc/ or s/spinand_flash/spinand_info/ ?+ char *+ u8 mfr_+ u8 dev_We'd better use an array of u8 here, just in case manufacturers decideto put more 2-).+ u32 page_+ u32 oob_+ u32 pages_per_+ u32 blks_per_+ u32 luns_per_+ u32 ecc_+ u32+ u32 rw_+};++extern struct spinand_flash spinand_table[];++#define SPINAND_MAX_ADDR_LEN
4++struct spinand_op {+ u8+ u8 n_+ u8 addr_+ u8 dummy_+ u8 addr[SPINAND_MAX_ADDR_LEN];+ u32 n_+ const u8 *tx_+ u32 n_+ u8 *rx_+ u8 data_+};++struct spinand_op_def {+ u8+ u8 addr_+ u8 addr_+ u8 dummy_+ u8 data_+};++/* SPI NAND supported OP mode */+#define SPINAND_RD_X1
0x+#define SPINAND_RD_X2
0x+#define SPINAND_RD_X4
0x+#define SPINAND_RD_DUAL
0x+#define SPINAND_RD_QUAD
0x+#define SPINAND_WR_X1
0x+#define SPINAND_WR_X2
0x+#define SPINAND_WR_X4
0x+#define SPINAND_WR_DUAL
0x+#define SPINAND_WR_QUAD
0x++#define SPINAND_RD_COMMON SPINAND_RD_X1 | SPINAND_RD_X2 | \+
SPINAND_RD_X4 | SPINAND_RD_DUAL | \+
SPINAND_RD_QUAD+#define SPINAND_WR_COMMON SPINAND_WR_X1 | SPINAND_WR_X4+#define SPINAND_OP_COMMON SPINAND_RD_COMMON | SPINAND_WR_COMMON++#define SPI_NAND_INFO(nm, mid, did, pagesz, oobsz, pg_per_blk,\+ blk_per_lun, lun_per_chip, ecc_stren, rwmode) \+ { .name = (nm), .mfr_id = (mid), .dev_id = (did),\+ .page_size = (pagesz), .oob_size = (oobsz),\+ .pages_per_blk = (pg_per_blk), .blks_per_lun = (blk_per_lun),\+ .luns_per_chip = (lun_per_chip), .ecc_strength = (ecc_stren),\+ .rw_mode = (rwmode) }Please make this more readable.#define SPI_NAND_INFO(nm, mid, did, pagesz, oobsz, pg_per_blk, \blk_per_lun, lun_per_chip, ecc_stren, \rwmode)
\.name = (nm), .mfr_id = (mid), .dev_id = (did), \....
\}Also, I'm wondering, is this ID table still useful if we haveper-manufacturer init functions? If it's not, maybe we should get ridof it.That does not mean manufacture drivers can't have their own table, butif there's nothing to share between manufacturers (IOW, if the dev_idfield is not standardized), then there's no need to expose a huge idtable in the core.++/*SPI NAND manufacture ID definition*/+#define SPINAND_MFR_MICRON
0x2CShould not be exposed here (keep it in your vendor source file.++int spinand_scan_ident(struct spinand_device *chip, u8 expect_mfr_id);+int spinand_scan_tail(struct spinand_device *chip);+int spinand_scan_ident_release(struct spinand_device *chip);+int spinand_scan_tail_release(struct spinand_device *chip);+int spinand_release(struct spinand_device *chip);How about clarifying a bit the interface:- s/spinand_scan_ident/spinand_detect/- s/spinand_scan_tail/spinand_init/- s/spinand_release/spinand_cleanup/+int spinand_set_cmd_cfg_table(int mfr);+struct spinand_op_def *spinand_get_cmd_cfg(u8 opcode);+#endif /* __LINUX_MTD_SPINAND_H */Regards,Boris
Raw Message
Hi Boris,Thanks again for your comments.Hi Arnaud,I'm so sorry for missing you in my list. And thanks for your commentsin v1 also.On Wed, Mar 1, 2017 at 5:58 PM, Boris Brezillon+ArnaudHi Peter,Can you please Cc Arnaud (and in general all reviewers) each time yousend a new version.I will add all reviewers in the next versions.On Wed, 1 Mar :05 +0800This is the first commit for spi nand framkework.This commit is to add spi nand initialization andrelease functions.Hm, actually you're doing more than that. Just say that you add basicbuilding blocks for the SPI NAND infrastructure.Fix in v3---drivers/mtd/nand/Kconfig
1 +drivers/mtd/nand/Makefile
1 +drivers/mtd/nand/spi/Kconfig
5 +drivers/mtd/nand/spi/Makefile
2 +drivers/mtd/nand/spi/spinand_base.c | 469 ++++++++++++++++++++++++++++++++++++drivers/mtd/nand/spi/spinand_ids.c
29 +++include/linux/mtd/spinand.h
| 315 ++++++++++++++++++++++++If you're okay with that, I'd like you to add an entry in MAINTAINERSfor the spinand sub-sub-sub-system :-). This way you'll be tagged asthe maintainer of this code and will be Cc when a patch is submitted.If you are OK with this. I'm glad to update the MAINTAINERS file. :)Besides, is there a rule to add this info?7 files changed, 822 insertions(+)create mode 100644 drivers/mtd/nand/spi/Kconfigcreate mode 100644 drivers/mtd/nand/spi/Makefilecreate mode 100644 drivers/mtd/nand/spi/spinand_base.ccreate mode 100644 drivers/mtd/nand/spi/spinand_ids.ccreate mode 100644 include/linux/mtd/spinand.hdiff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfigindex 1c1a1f4..644--- a/drivers/mtd/nand/Kconfig+++ b/drivers/mtd/nand/Kconfig@@ -2,3 +2,4 @@ config MTD_NAND_COREtristatesource "drivers/mtd/nand/raw/Kconfig"+source "drivers/mtd/nand/spi/Kconfig"diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefileindex fe430d9..644--- a/drivers/mtd/nand/Makefile+++ b/drivers/mtd/nand/Makefile@@ -3,3 +3,4 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.onandcore-objs :=
bbt.oobj-y
+= raw/+obj-$(CONFIG_MTD_SPI_NAND)
+= spi/diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfignew file mode 100644index a7b71--- /dev/null+++ b/drivers/mtd/nand/spi/Kconfig@@ -0,0 +1,5 @@+menuconfig MTD_SPI_NAND+
tristate "SPI-NAND device Support"+
depends on MTD_NAND+
This is the framework for the SPI NAND device drivers.diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefilenew file mode 100644index f0d622--- /dev/null+++ b/drivers/mtd/nand/spi/Makefile@@ -0,0 +1,2 @@+obj-$(CONFIG_MTD_SPI_NAND) += spinand_base.o+obj-$(CONFIG_MTD_SPI_NAND) += spinand_ids.odiff --git a/drivers/mtd/nand/spi/spinand_base.c b/drivers/mtd/nand/spi/spinand_base.cnew file mode 100644index d47146--- /dev/null+++ b/drivers/mtd/nand/spi/spinand_base.cHow about renaming this file into core.c?core.c is much more clear while spinand_base.c matches rawnand_base.cShould we rename them at the same time or rename spinand_base.c first?@@ -0,0 +1,469 @@+/**+* spi-nand-base.cPlease do not put the file name in the copyright header. It's not evencorrect, which shows how useless -).Fix this in v3+*+* Copyright (c)
Micron Technology, Inc.+*+* This prog you can redistribute it and/or+* modify it under the terms of the GNU General Public License+* as published by the Free Software F either version 2+* of the License, or (at your option) any later version.+*+* This program is distributed in the hope that it will be useful,+* but WITHOUT ANY WARRANTY; without even the implied warranty of+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the+* GNU General Public License for more details.+*/++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt++#include &linux/kernel.h&+#include &linux/module.h&+#include &linux/sched.h&+#include &linux/delay.h&+#include &linux/jiffies.h&+#include &linux/mtd/spinand.h&+#include &linux/slab.h&+++static u64 spinand_get_chip_size(struct spinand_device *chip)I would change the parameter name here: s/chip/spinand/. This isapplicable to the whole submission.Fix this in v3.+{+
struct nand_device *nand = &chip-&++
return nand_diesize(nand) * nand_ndies(nand);+}Probably something that should go in include/linux/mtd/nand.h ordrivers/mtd/nand/core.c.Yes. I will add an interface in include/linux/mtd/nand.h.nand_chip_size() or nand_device_size(), which one is better?++static inline int spinand_exec_cmd(struct spinand_device *chip,+
struct spinand_op *cmd)+{+
return chip-&controller.ops-&exec_op(chip, cmd);+}++static inline void spinand_op_init(struct spinand_op *op)+{+
memset(op, 0, sizeof(struct spinand_op));+
op-&addr_nbits = 1;+
op-&data_nbits = 1;+}++/**+ * spinand_read_reg - send command 0Fh to read register+ */+static int spinand_read_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)Align parameters on the open parenthesis (run checkpatch.pl --strictand fix everything you can).Fix this in v3+{+
struct spinand_+++
spinand_op_init(&cmd);+
cmd.cmd = SPINAND_CMD_GET_FEATURE;+
cmd.n_addr = 1;+
cmd.addr[0] =+
cmd.n_rx = 1;+
cmd.rx_buf =++
ret = spinand_exec_cmd(chip, &cmd);+
if (ret & 0)+
pr_err("err: %d read register %d\n", ret, reg);+++}++/**+ * spinand_write_reg - send command 1Fh to write register+ */+static int spinand_write_reg(struct spinand_device *chip,+
uint8_t reg, uint8_t *buf)+{+
struct spinand_+++
spinand_op_init(&cmd);+
cmd.cmd = SPINAND_CMD_SET_FEATURE;+
cmd.n_addr = 1;+
cmd.addr[0] =+
cmd.n_tx = 1,+
cmd.tx_buf = buf,++
ret = spinand_exec_cmd(chip, &cmd);+
if (ret & 0)+
pr_err("err: %d write register %d\n", ret, reg);+++}++/**+ * spinand_read_status - get status register value+ *
After read, write, or erase, the Nand device is expected to set the+ *
busy status.+ *
This function is to allow reading the status of the command: read,+ *
write, and erase.+ *
Once the status turns to be ready, the other status bits also are+ *
valid status bits.+ */+static int spinand_read_status(struct spinand_device *chip, uint8_t *status)+{+
return spinand_read_reg(chip, REG_STATUS, status);+}++/**+ * spinand_wait - wait until the command is done+ */+static int spinand_wait(struct spinand_device *chip, u8 *s)+{+
unsigned long timeo = msecs_to_jiffies(400);+
spinand_read_status(chip, &status);+
if ((status & STATUS_OIP_MASK) == STATUS_READY)+
} while (time_before(jiffies, timeo));++
* Extra read, just in case the STATUS_READY bit has changed+
* since out last check^ our last check.Fix this in v3+
spinand_read_status(chip, &status);+
return (status & STATUS_OIP_MASK) == STATUS_READY ? 0 : -ETIMEDOUT;;Extra semi-colon at the end of the line.Fix this in v3+}++/**+ * spinand_read_id - send 9Fh command to get ID+ */+static int spinand_read_id(struct spinand_device *chip, u8 *buf)+{+
struct spinand_++
spinand_op_init(&cmd);+
cmd.cmd = SPINAND_CMD_READ_ID;+
if (chip-&manufacturer.ops-&get_dummy)+
cmd.dummy_bytes = chip-&manufacturer.ops-&get_dummy(chip, &cmd);+
cmd.n_rx = 2;+
cmd.rx_buf =++
return spinand_exec_cmd(chip, &cmd);+}++/**+ * spinand_reset - sen}

我要回帖

更多关于 v4l2 subdev ops 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信