Skip to contentSkip to conversation

mtd: Qualcomm NAND controller driver

PATCH Superseded Archit Taneja 8 participants 127 messages Jan 16, 2015 – Mar 22, 2016 Page 2 of 2

Subsystems (6)
lore
Share & tools
lore
#61 lore raw

Re: [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver

In reply to Boris Brezillon

Hi Boris,

Quoted 4 lines · Boris Brezillon

Hi Archit,

Again, sorry for the late review. It's probably not exhaustive but points a few things that should be fixed.

Thanks for the thorough review! Some comments below.

Quoted 360 lines
Quoted 355 lines · On Wed, 19 Aug 2015 10:19:03 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. For this reason, we use the newly created flag NAND_BBT_ACCESS_BBM_RAW to read the factory provided bad block markers.

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

---
  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 1910 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 1918 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 5b2806a..6085b8a 100644
@@ -538,4 +538,11 @@ config MTD_NAND_HISI504
  	help
  	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
  endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 1f897ec..87b6a1d 100644
@@ -53,5 +53,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
  obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
  obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
  obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
  nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +250 -0
new file mode 100644
index 0000000..2337731
@@ -0,0 +1,1910 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/delay.h>
+
+/* NANDc reg offsets */
+#define NAND_FLASH_CMD			0x00
+#define NAND_ADDR0			0x04
+#define NAND_ADDR1			0x08
+#define NAND_FLASH_CHIP_SELECT		0x0c
+#define NAND_EXEC_CMD			0x10
+#define NAND_FLASH_STATUS		0x14
+#define NAND_BUFFER_STATUS		0x18
+#define NAND_DEV0_CFG0			0x20
+#define NAND_DEV0_CFG1			0x24
+#define NAND_DEV0_ECC_CFG		0x28
+#define NAND_DEV1_ECC_CFG		0x2c
+#define NAND_DEV1_CFG0			0x30
+#define NAND_DEV1_CFG1			0x34
+#define NAND_READ_ID			0x40
+#define NAND_READ_STATUS		0x44
+#define NAND_DEV_CMD0			0xa0
+#define NAND_DEV_CMD1			0xa4
+#define NAND_DEV_CMD2			0xa8
+#define NAND_DEV_CMD_VLD		0xac
+#define SFLASHC_BURST_CFG		0xe0
+#define NAND_ERASED_CW_DETECT_CFG	0xe8
+#define NAND_ERASED_CW_DETECT_STATUS	0xec
+#define NAND_EBI2_ECC_BUF_CFG		0xf0
+#define FLASH_BUF_ACC			0x100
+
+#define NAND_CTRL			0xf00
+#define NAND_VERSION			0xf08
+#define NAND_READ_LOCATION_0		0xf20
+#define NAND_READ_LOCATION_1		0xf24
+
+/* dummy register offsets, used by write_reg_dma */
+#define NAND_DEV_CMD1_RESTORE		0xdead
+#define NAND_DEV_CMD_VLD_RESTORE	0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define PAGE_ACC			BIT(4)
+#define LAST_PAGE			BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define NAND_DEV_SEL			0
+#define DM_EN				BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define FS_OP_ERR			BIT(4)
+#define FS_READY_BSY_N			BIT(5)
+#define FS_MPU_ERR			BIT(8)
+#define FS_DEVICE_STS_ERR		BIT(16)
+#define FS_DEVICE_WP			BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define BS_UNCORRECTABLE_BIT		BIT(8)
+#define BS_CORRECTABLE_ERR_MSK		0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define DISABLE_STATUS_AFTER_WRITE	4
+#define CW_PER_PAGE			6
+#define UD_SIZE_BYTES			9
+#define ECC_PARITY_SIZE_BYTES_RS	19
+#define SPARE_SIZE_BYTES		23
+#define NUM_ADDR_CYCLES			27
+#define STATUS_BFR_READ			30
+#define SET_RD_MODE_AFTER_STATUS	31
+
+/* NAND_DEVn_CFG0 bits */
+#define DEV0_CFG1_ECC_DISABLE		0
+#define WIDE_FLASH			1
+#define NAND_RECOVERY_CYCLES		2
+#define CS_ACTIVE_BSY			5
+#define BAD_BLOCK_BYTE_NUM		6
+#define BAD_BLOCK_IN_SPARE_AREA		16
+#define WR_RD_BSY_GAP			17
+#define ENABLE_BCH_ECC			27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define ECC_CFG_ECC_DISABLE		0
+#define ECC_SW_RESET			1
+#define ECC_MODE			4
+#define ECC_PARITY_SIZE_BYTES_BCH	8
+#define ECC_NUM_DATA_BYTES		16
+#define ECC_FORCE_CLK_OPEN		30
+
+/* NAND_DEV_CMD1 bits */
+#define READ_ADDR			0
+
+/* NAND_DEV_CMD_VLD bits */
+#define READ_START_VLD			0
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define NUM_STEPS			0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define ERASED_CW_ECC_MASK		1
+#define AUTO_DETECT_RES			0
+#define MASK_ECC			(1 << ERASED_CW_ECC_MASK)
+#define RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
+#define ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
+#define CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
+#define SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define PAGE_ALL_ERASED			BIT(7)
+#define CODEWORD_ALL_ERASED		BIT(6)
+#define PAGE_ERASED			BIT(5)
+#define CODEWORD_ERASED			BIT(4)
+#define ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
+#define ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* Version Mask */
+#define NAND_VERSION_MAJOR_MASK		0xf0000000
+#define NAND_VERSION_MAJOR_SHIFT	28
+#define NAND_VERSION_MINOR_MASK		0x0fff0000
+#define NAND_VERSION_MINOR_SHIFT	16
+
+/* NAND OP_CMDs */
+#define PAGE_READ			0x2
+#define PAGE_READ_WITH_ECC		0x3
+#define PAGE_READ_WITH_ECC_SPARE	0x4
+#define PROGRAM_PAGE			0x6
+#define PAGE_PROGRAM_WITH_ECC		0x7
+#define PROGRAM_PAGE_SPARE		0x9
+#define BLOCK_ERASE			0xa
+#define FETCH_ID			0xb
+#define RESET_DEVICE			0xd
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define NANDC_STEP_SIZE			512
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
+
+/* we read at most 3 registers per codeword scan */
+#define MAX_REG_RD			(3 * MAX_NUM_STEPS)
+
+/* ECC modes */
+#define ECC_NONE	BIT(0)
+#define ECC_RS_4BIT	BIT(1)
+#define	ECC_BCH_4BIT	BIT(2)
+#define	ECC_BCH_8BIT	BIT(3)
+
+struct desc_info {
+	struct list_head list;
+
+	enum dma_data_direction dir;
+	struct scatterlist sgl;
+	struct dma_async_tx_descriptor *dma_desc;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+	__le32 cmd;
+	__le32 addr0;
+	__le32 addr1;
+	__le32 chip_sel;
+	__le32 exec;
+
+	__le32 cfg0;
+	__le32 cfg1;
+	__le32 ecc_bch_cfg;
+
+	__le32 clrflashstatus;
+	__le32 clrreadstatus;
+
+	__le32 cmd1;
+	__le32 vld;
+
+	__le32 orig_cmd1;
+	__le32 orig_vld;
+
+	__le32 ecc_buf_cfg;
+};
+
+/*
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @list:			DMA descriptor list (list of desc_infos)
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		buffer for reading register data via DMA
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
+ *				ecc/non-ecc mode for the current nand flash
+ *				device
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes
+ * @ecc_strength:		4 bit or 8 bit ecc, received via DT
+ * @bus_width:			8 bit or 16 bit NAND bus width, received via DT
+ * @ecc_modes:			supported ECC modes by the current controller,
+ *				initialized via DT match data
+ * @cw_size:			the number of bytes in a single step/codeword
+ *				of a page, consisting of all data, ecc, spare
+ *				and reserved bytes
+ * @cw_data:			the number of bytes within a codeword protected
+ *				by ECC
+ * @bch_enabled:		flag to tell whether BCH or RS ECC mode is used
+ * @status:			value to be returned if NAND_CMD_STATUS command
+ *				is executed
+ */
+struct qcom_nandc_data {
+	struct platform_device *pdev;
+	struct device *dev;
+
+	void __iomem *base;
+	struct resource *res;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;
+
+	/* DMA stuff */
+	struct dma_chan *chan;
+	struct dma_slave_config	slave_conf;
+	unsigned int cmd_crci;
+	unsigned int data_crci;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 255

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+	struct list_head list;
+
+	/* MTD stuff */
+	struct nand_chip chip;
+	struct mtd_info mtd;

You can drop this field, since nand_chip now embeds its own mtd_info instance (accessible through the nand_to_mtd() helper).

Ah, alright. I'd posted this patchset during the 4.3-rc cycle, this must have been in discussion then. I'll update accordingly.

Quoted 23 lines
Quoted 23 lines
drivers/mtd/nand/qcom_nandc.c new file +22 -0
+
+	/* local data buffer and markers */
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;
+
+	/* local buffer to read back registers */
+	__le32 *reg_read_buf;
+	int reg_read_pos;
+
+	/* required configs */
+	u32 cfg0, cfg1;
+	u32 cfg0_raw, cfg1_raw;
+	u32 ecc_buf_cfg;
+	u32 ecc_bch_cfg;
+	u32 clrflashstatus;
+	u32 clrreadstatus;
+	u32 sflashc_burst_cfg;
+	u32 cmd1, vld;
+
+	/* register state */
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 282

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+	struct nandc_regs *regs;
+
+	/* things we get from DT */
+	int ecc_strength;
+	int bus_width;

Do you really need these fields? You can directly change the ->chip.ecc.strength and ->chip.options field instead.

Yes, these aren't required. I was forcibly reading these via custom DT properties. I will replace this such that these are populated via nand_dt_init().

Quoted 29 lines

drivers/mtd/nand/qcom_nandc.c line 293

Quoted 12 lines
drivers/mtd/nand/qcom_nandc.c new file +11 -0
+
+	u32 ecc_modes;
+
+	/* misc params */
+	int cw_size;
+	int cw_data;
+	bool use_ecc;
+	bool bch_enabled;
+	u8 status;
+	int last_command;
+};

You're mixing controller and chip stuff in this structure. As said in my answer to your DT bindings proposal, I think it would be clearer to separate the controller and chip specific fields.

Note that a NAND chip can be attached to a NAND controller through its ->controller field.

So here is how it would look like:

struct qcom_nandc_data {
	struct nand_hw_control controller;

	struct list_head chips;
	/* controller specific fields */
};
Quoted 6 lines
struct qcom_nand_data {
	struct list_head node;
	struct nand_chip chip;

	/* chip specific fields */
}

Thanks for the explanation. I wasn't aware of this sort of structure split. I was probably referring to the sinlge chip nand controller drivers when I wrote it.

Quoted 328 lines

[...]

drivers/mtd/nand/qcom_nandc.c line 810

Quoted 11 lines
drivers/mtd/nand/qcom_nandc.c new file +11 -0
+
+/*
+ * Implements chip->cmdfunc. It's  only used for a limited set of commands.
+ * The rest of the commands wouldn't be called by upper layers. For example,
+ * NAND_CMD_READOOB would never be called because we have our own versions
+ * of read_oob ops for nand_ecc_ctrl.
+ */
+static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+			 int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd_to_nand(mtd);
Quoted 70 lines
drivers/mtd/nand/qcom_nandc.c new file +70 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nandc_data *this = chip->priv;
+	bool wait = false;
+	int r = 0;
+
+	pre_command(this, command);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		r = reset(this);
+		wait = true;
+		break;
+
+	case NAND_CMD_READID:
+		this->buf_count = 4;
+		r = read_id(this, column);
+		wait = true;
+		break;
+
+	case NAND_CMD_PARAM:
+		r = nandc_param(this);
+		wait = true;
+		break;
+
+	case NAND_CMD_ERASE1:
+		r = erase_block(this, page_addr);
+		wait = true;
+		break;
+
+	case NAND_CMD_READ0:
+		/* we read the entire page for now */
+		WARN_ON(column != 0);
+
+		this->use_ecc = true;
+		set_address(this, 0, page_addr);
+		update_rw_regs(this, ecc->steps, true);
+		break;
+
+	case NAND_CMD_SEQIN:
+		WARN_ON(column != 0);
+		set_address(this, 0, page_addr);
+		break;
+
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_NONE:
+	default:
+		break;
+	}
+
+	if (r) {
+		dev_err(this->dev, "failure executing command %d\n",
+			command);
+		free_descs(this);
+		return;
+	}
+
+	if (wait) {
+		r = submit_descs(this);
+		if (r)
+			dev_err(this->dev,
+				"failure submitting descs for command %d\n",
+				command);
+	}
+
+	free_descs(this);
+
+	post_command(this, command);
+}
+

drivers/mtd/nand/qcom_nandc.c line 890

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nandc_data *this, u8 *data_buf)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 63 lines
drivers/mtd/nand/qcom_nandc.c new file +63 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage = ecc->steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (this->bch_enabled || !this->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(this->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * this->cw_data];
+		empty2 = &data_buf[175 + i * this->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * this->cw_data] = orig1[j];
+		data_buf[175 + j * this->cw_data] = orig2[j];
+	}
+
+	return false;
+}
+
+struct read_stats {
+	__le32 flash;
+	__le32 buffer;
+	__le32 erased_cw;

drivers/mtd/nand/qcom_nandc.c line 963

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+};
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nandc_data *this, bool erased_page)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 40 lines
drivers/mtd/nand/qcom_nandc.c new file +40 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage = ecc->steps;
+	unsigned int max_bitflips = 0;
+	int i;
+	struct read_stats *buf;
+
+	buf = (struct read_stats *)this->reg_read_buf;
+	for (i = 0; i < cwperpage; i++, buf++) {
+		unsigned int stat;
+		u32 flash, buffer, erased_cw;
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+
+			/* ignore erased codeword errors */
+			if (this->bch_enabled) {
+				if ((erased_cw & ERASED_CW) == ERASED_CW)
+					continue;
+			} else if (erased_page) {
+				continue;
+			}
+
+			if (buffer & BS_UNCORRECTABLE_BIT) {
+				mtd->ecc_stats.failed++;
+				continue;
+			}
+		}
+
+		stat = buffer & BS_CORRECTABLE_ERR_MSK;
+		mtd->ecc_stats.corrected += stat;
+
+		max_bitflips = max(max_bitflips, stat);
+	}
+
+	return max_bitflips;
+}
+

[...]

drivers/mtd/nand/qcom_nandc.c line 1350

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+/*
+ * the three functions below implement chip->read_byte(), chip->read_buf()
+ * and chip->write_buf() respectively. these aren't used for
+ * reading/writing page data, they are used for smaller data like reading
+ * id, status etc
+ */
+static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd_to_nand(mtd);
Quoted 11 lines
drivers/mtd/nand/qcom_nandc.c new file +11 -0
+	struct qcom_nandc_data *this = chip->priv;
+	uint8_t *buf = this->data_buffer;
+	uint8_t ret = 0x0;
+
+	if (this->last_command == NAND_CMD_STATUS) {
+		ret = this->status;
+
+		this->status = NAND_STATUS_READY | NAND_STATUS_WP;
+
+		return ret;
+	}

drivers/mtd/nand/qcom_nandc.c line 1371

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+	if (this->buf_start < this->buf_count)
+		ret = buf[this->buf_start++];
+
+	return ret;
+}
+
+static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd_to_nand(mtd);

drivers/mtd/nand/qcom_nandc.c line 1382

Quoted 11 lines
drivers/mtd/nand/qcom_nandc.c new file +11 -0
+	struct qcom_nandc_data *this = chip->priv;
+	int real_len = min_t(size_t, len, this->buf_count - this->buf_start);
+
+	memcpy(buf, this->data_buffer + this->buf_start, real_len);
+	this->buf_start += real_len;
+}
+
+static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+		int len)
+{
+	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd_to_nand(mtd);

drivers/mtd/nand/qcom_nandc.c line 1394

Quoted 12 lines
drivers/mtd/nand/qcom_nandc.c new file +12 -0
+	struct qcom_nandc_data *this = chip->priv;
+	int real_len = min_t(size_t, len, this->buf_count - this->buf_start);
+
+	memcpy(this->data_buffer + this->buf_start, buf, real_len);
+
+	this->buf_start += real_len;
+}
+
+/* we support only one external chip for now */
+static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd_to_nand(mtd);
Quoted 18 lines
drivers/mtd/nand/qcom_nandc.c new file +18 -0
+	struct qcom_nandc_data *this = chip->priv;
+
+	if (chipnr <= 0)
+		return;
+
+	dev_warn(this->dev, "invalid chip select\n");
+}
+
+/*
+ * NAND controller page layout info
+ *
+ * |-----------------------|	  |---------------------------------|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |	DATA	xx..ECC..xx|	  |	DATA	**SPARE**xx..ECC..xx|
+ * |   (516)	xx.......xx|	  |  (516-n*4)	**(n*4)**xx.......xx|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |-----------------------|	  |---------------------------------|
+ *     codeword 1,2..n-1			codeword n

drivers/mtd/nand/qcom_nandc.c line 1422

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+ *  <---(528/532 Bytes)---->	   <-------(528/532 Bytes)---------->
+ *
+ * n = number of codewords in the page
+ * . = ECC bytes
+ * * = spare bytes
+ * x = unused/reserved bytes
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes

Is there a reason not to use the following layout?

(
n x (
data = 512 bytes
protected OOB data = 4 bytes
ECC bytes = 12 or 16
)

+

Quoted 8 lines

remaining unprotected OOB bytes
)

This way the ECC layout definition would be easier to define, and you'll have something that is closer to what a NAND chip expect (ECC block/step size of 512 or 1024).

I know this is also dependent on the bootloader, hence my question.

I tried to figure this out looking at documentation and the downstream drivers. What I understood was that all the OOB was intentionally kept in the last step, so that things are faster when we only want to access OOB. In that case, the controller will need to write to only one step/codeword.

The bootloaders also use the same layout.

Quoted 16 lines
Quoted 15 lines

+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * the layout described above is used by the controller when the ECC block is
+ * enabled. When we read a page with ECC enabled, the unused/reserved bytes are
+ * skipped and not copied to our internal buffer. therefore, the nand_ecclayout
+ * layouts defined below doesn't consider the positions occupied by the reserved
+ * bytes

Quoted 2 lines

You could just read this portion with the ECC engine disabled when you're asked for OOB data.

Yes, but there are ecc ops (like ecc->read_page/ecc->write_page) that have an argument called 'oob_required'. We need to have ECC enabled when running these ops.

In order to read this additional portion, I'll need to read/write each step again with ECC disabled, which would really slow things down.

Quoted 8 lines
Quoted 5 lines

+ *
+ * when the ECC block is disabled, one unused byte (or two for 16 bit bus width)
+ * in the last codeword is the position of bad block marker. the bad block
+ * marker cannot be accessed when ECC is enabled.

So, you're switching the BBM with the data at the BBM position (possibly some in-band data), right?

Yes. When ECC isn't enabled, the BBM byte lies within the in-band data of the last step. In fact, there are dummy BBM bytes in the previous steps at the same offset.

With ECC enabled, the controller just skips that position (and the dummy BBM bytes in previous steps) altogether.

Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1447

Quoted 8 lines

+ *
+ */

drivers/mtd/nand/qcom_nandc.c new file +5 -0
+
+/*
+ * Layouts for different page sizes and ecc modes. We skip the eccpos field
+ * since it isn't needed for this driver
+ */

If you know where they are stored, please specify them, even if they are not used by the upper layers (this helps analyzing raw nand dumps).

Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1455

Quoted 8 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+
+/* 2K page, 4 bit ECC */
+static struct nand_ecclayout layout_oob_64 = {
+	.eccbytes	= 40,
+	.oobfree	= {
+				{ 30, 16 },
+			  },
+};

According to your description it should either be eccbytes = 48 (if you're considering reserved bytes as ECC bytes) or 32 (if you're not counting reserved bytes).

Each step is 528 bytes in total. The first 3 steps contain 516 bytes of data, 10 bytes of ECC and 2 bytes of resrved data. The last step contains 500 bytes of data, 16 bytes of OOB, 10 bytes of ECC and 2 reserved bytes.

If I don't count the reserved bytes as part of ECC, I get 40. If I do count it as part of ECC, I get 48. In the way I described layouts, I ignored the ECC parts. How did you get 32?

Quoted 2 lines

BTW, is the oobfree portion really starting at offset 30?

I thought the offsets mentioned here also had to incorporate positions taken by ECC bytes? If I strip all the the in-band data (real data) from each step, we get:

ECC(10 bytes).ECC(10 bytes).ECC(10 bytes).OOB(16 bytes).ECC(10 bytes)

Wouldn't this result in the offset as 30?

We are still only taking into account 56 bytes out of the 64 bytes in the chip's OOB. This is because I'm discaring the 2 bytes from each step (summing up to 8) which aren't accessible when ECC is enabled.

Quoted 2 lines

I'd say that in the 2K page, 4 bit ECC you don't have any oobfree bytes (528 * 4 == 2048 + 64).

528 contains both oob and in-band data. If you ignore the weird layout and assume we have at an average 512 bytes for each step, we get:

512 * 4 == 2048 bytes of data, and 64 bytes of OOB (16 bytes free, 40 ECC, and 8 reserved/unused).

Quoted 29 lines
Quoted 29 lines
drivers/mtd/nand/qcom_nandc.c new file +28 -0
+
+/* 4K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_128 = {
+	.eccbytes	= 80,
+	.oobfree	= {
+				{ 70, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 8 bit bus width */
+static struct nand_ecclayout layout_oob_224_x8 = {
+	.eccbytes	= 104,
+	.oobfree	= {
+				{ 91, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 16 bit bus width */
+static struct nand_ecclayout layout_oob_224_x16 = {
+	.eccbytes	= 112,
+	.oobfree	= {
+				{ 98, 32 },
+			  },
+};
+
+/* 8K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_256 = {
+	.eccbytes	= 160,
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1487

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	.oobfree	= {
+				{ 151, 64 },
+			  },
+};

Those ECC layout definitions could probably be dynamically created based on the detected ECC strength, bus-width and page size, instead of defining a new one for each new combination.

That's true. I can try that out.

Quoted 40 lines
Quoted 16 lines
drivers/mtd/nand/qcom_nandc.c new file +15 -0
+
+/*
+ * this is called before scan_ident, we do some minimal configurations so
+ * that reading ID and ONFI params work
+ */
+static void qcom_nandc_pre_init(struct qcom_nandc_data *this)
+{
+	/* kill onenand */
+	nandc_write(this, SFLASHC_BURST_CFG, 0);
+
+	/* enable ADM DMA */
+	nandc_write(this, NAND_FLASH_CHIP_SELECT, DM_EN);
+
+	/* save the original values of these registers */
+	this->cmd1 = nandc_read(this, NAND_DEV_CMD1);

drivers/mtd/nand/qcom_nandc.c line 1512

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	this->vld = nandc_read(this, NAND_DEV_CMD_VLD);
+
+	/* initial status value */
+	this->status = NAND_STATUS_READY | NAND_STATUS_WP;
+}
+
+static int qcom_nandc_ecc_init(struct qcom_nandc_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage;
+	bool wide_bus;
+
+	/* the nand controller fetches codewords/chunks of 512 bytes */
+	cwperpage = mtd->writesize >> 9;
+
+	ecc->strength = this->ecc_strength;
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1526

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		ecc->bytes = wide_bus ? 14 : 13;

Maybe you'd better consider that reserved bytes (after the ECC bytes) are actually ECC bytes. So, according to your description you would always have 16 here.

The thing is that if I consider the reserved bytes as a part of the ECC bytes, and if I use this bigger value when configuring the controller and dma, I will get bad results; becase the hardware doesn't touch these when ECC is enabled.

I could set the ecc->bytes to '16' and still use the actual values when configuring the controller. Do you think that will help in any way?

Quoted 212 lines

drivers/mtd/nand/qcom_nandc.c line 1534

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (this->ecc_modes & ECC_BCH_4BIT)
+			ecc->bytes = wide_bus ? 8 : 7;

Ditto, except it's 12 here.

Quoted 44 lines
drivers/mtd/nand/qcom_nandc.c new file +44 -0
+		else
+			ecc->bytes = 10;
+	}
+
+	/* each step consists of 512 bytes of data */
+	ecc->size = NANDC_STEP_SIZE;
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	/*
+	 * the bad block marker is readable only when we read the page with ECC
+	 * disabled. all the ops above run with ECC enabled. We need raw read
+	 * and write function for oob in order to access bad block marker.
+	 */
+	ecc->read_oob_raw	= qcom_nandc_read_oob_raw;
+	ecc->write_oob_raw	= qcom_nandc_write_oob_raw;
+
+	switch (mtd->oobsize) {
+	case 64:
+		ecc->layout = &layout_oob_64;
+		break;
+	case 128:
+		ecc->layout = &layout_oob_128;
+		break;
+	case 224:
+		if (wide_bus)
+			ecc->layout = &layout_oob_224_x16;
+		else
+			ecc->layout = &layout_oob_224_x8;
+		break;
+	case 256:
+		ecc->layout = &layout_oob_256;
+		break;
+	default:
+		dev_err(this->dev, "unsupported NAND device, oobsize %d\n",
+			mtd->oobsize);
+		return -ENODEV;
+	}
+
+	ecc->mode = NAND_ECC_HW;
+

drivers/mtd/nand/qcom_nandc.c line 1588

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	/* enable ecc by default */
+	this->use_ecc = true;
+
+	return 0;
+}
+
+static void qcom_nandc_hw_post_init(struct qcom_nandc_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 128 lines
drivers/mtd/nand/qcom_nandc.c new file +128 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage = mtd->writesize / ecc->size;
+	int spare_bytes, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 0;
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		this->cw_size = 532;
+
+		spare_bytes = wide_bus ? 0 : 2;
+
+		this->bch_enabled = true;
+		ecc_mode = 1;
+	} else {
+		this->cw_size = 528;
+
+		if (this->ecc_modes & ECC_BCH_4BIT) {
+			spare_bytes = wide_bus ? 2 : 4;
+
+			this->bch_enabled = true;
+			ecc_mode = 0;
+		} else {
+			spare_bytes = wide_bus ? 0 : 1;
+		}
+	}
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	this->cw_data = 516;
+
+	bad_block_byte = mtd->writesize - this->cw_size * (cwperpage - 1) + 1;
+
+	this->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| this->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| ecc->bytes << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| spare_bytes << SPARE_SIZE_BYTES;
+
+	this->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| this->bch_enabled << ENABLE_BCH_ECC;
+
+	this->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| this->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	this->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	this->ecc_bch_cfg = this->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| this->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| ecc->bytes << ECC_PARITY_SIZE_BYTES_BCH;
+
+	this->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	this->clrflashstatus = FS_READY_BSY_N;
+	this->clrreadstatus = 0xc0;
+
+	dev_dbg(this->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		this->cfg0, this->cfg1, this->ecc_buf_cfg,
+		this->ecc_bch_cfg, this->cw_size, this->cw_data,
+		ecc->strength, ecc->bytes, cwperpage);
+}
+
+static int qcom_nandc_alloc(struct qcom_nandc_data *this)
+{
+	int r;
+
+	r = dma_set_coherent_mask(this->dev, DMA_BIT_MASK(32));
+	if (r) {
+		dev_err(this->dev, "failed to set DMA mask\n");
+		return r;
+	}
+
+	/*
+	 * we use the internal buffer for reading ONFI params, reading small
+	 * data like ID and status, and preforming read-copy-write operations
+	 * when writing to a codeword partially. 532 is the maximum possible
+	 * size of a codeword for our nand controller
+	 */
+	this->buf_size = 532;
+
+	this->data_buffer = devm_kzalloc(this->dev, this->buf_size, GFP_KERNEL);
+	if (!this->data_buffer)
+		return -ENOMEM;
+
+	this->regs = devm_kzalloc(this->dev, sizeof(*this->regs), GFP_KERNEL);
+	if (!this->regs)
+		return -ENOMEM;
+
+	this->reg_read_buf = devm_kzalloc(this->dev,
+				MAX_REG_RD * sizeof(*this->reg_read_buf),
+				GFP_KERNEL);
+	if (!this->reg_read_buf)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&this->list);
+
+	this->chan = dma_request_slave_channel(this->dev, "rxtx");
+	if (!this->chan) {
+		dev_err(this->dev, "failed to request slave channel\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}

drivers/mtd/nand/qcom_nandc.c line 1726

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+static void qcom_nandc_unalloc(struct qcom_nandc_data *this)
+{
+	dma_release_channel(this->chan);
+}
+
+static int qcom_nandc_init(struct qcom_nandc_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 6 lines

drivers/mtd/nand/qcom_nandc.c line 1728

Quoted 2 lines
drivers/mtd/nand/qcom_nandc.c new file +2 -0
+	struct device_node *np = this->dev->of_node;
+	struct mtd_part_parser_data ppdata = { .of_node = np };

You don't need it anymore, because it's automatically extracted from the ->flash_node field.
Just call, nand_set_flash_node() before calling nand_scan_ident().

That's convinient. I'll remove this.

Quoted 17 lines
Quoted 17 lines
drivers/mtd/nand/qcom_nandc.c new file +16 -0
+	int r;
+
+	mtd->priv = chip;
+	mtd->name = "qcom-nandc";
+	mtd->owner = THIS_MODULE;
+
+	chip->priv = this;
+
+	chip->cmdfunc		= qcom_nandc_command;
+	chip->select_chip	= qcom_nandc_select_chip;
+	chip->read_byte		= qcom_nandc_read_byte;
+	chip->read_buf		= qcom_nandc_read_buf;
+	chip->write_buf		= qcom_nandc_write_buf;
+
+	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
+	if (this->bus_width == 16)
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1749

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+		chip->options |= NAND_BUSWIDTH_16;
+
+	chip->bbt_options = NAND_BBT_ACCESS_BBM_RAW;
+	if (of_get_nand_on_flash_bbt(np))
+		chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;

Ditto: rely on the work done by nand_dt_init() which is called by nand_scan_ident().

Yes, I'll remove this.

Quoted 13 lines
Quoted 13 lines
drivers/mtd/nand/qcom_nandc.c new file +12 -0
+
+	qcom_nandc_pre_init(this);
+
+	r = nand_scan_ident(mtd, 1, NULL);
+	if (r)
+		return r;
+
+	r = qcom_nandc_ecc_init(this);
+	if (r)
+		return r;
+
+	qcom_nandc_hw_post_init(this);
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 6 lines
drivers/mtd/nand/qcom_nandc.c new file +6 -0
+
+	r = nand_scan_tail(mtd);
+	if (r)
+		return r;
+
+	return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
	return mtd_device_parse_register(mtd, NULL, NULL, NULL 0);

Will fix.

Quoted 16 lines
Quoted 16 lines
drivers/mtd/nand/qcom_nandc.c new file +15 -0
+}
+
+static int qcom_nandc_parse_dt(struct platform_device *pdev)
+{
+	struct qcom_nandc_data *this = platform_get_drvdata(pdev);
+	struct device_node *np = this->dev->of_node;
+	int r;
+
+	this->ecc_strength = of_get_nand_ecc_strength(np);
+	if (this->ecc_strength < 0) {
+		dev_warn(this->dev,
+			"incorrect ecc strength, setting to 4 bits/step\n");
+		this->ecc_strength = 4;
+	}
+
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1787

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+	this->bus_width = of_get_nand_bus_width(np);
+	if (this->bus_width < 0) {
+		dev_warn(this->dev, "incorrect bus width, setting to 8\n");
+		this->bus_width = 8;
+	}

Those two properties are extracted when calling nand_scan_ident() if you've called nand_set_flash_node() before that.

Yeah, I'll remove these.

Quoted 85 lines
Quoted 85 lines
drivers/mtd/nand/qcom_nandc.c new file +84 -0
+
+	r = of_property_read_u32(np, "qcom,cmd-crci", &this->cmd_crci);
+	if (r) {
+		dev_err(this->dev, "command CRCI unspecified\n");
+		return r;
+	}
+
+	r = of_property_read_u32(np, "qcom,data-crci", &this->data_crci);
+	if (r) {
+		dev_err(this->dev, "data CRCI unspecified\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nandc_data *this;
+	const void *dev_data;
+	int r;
+
+	this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
+	if (!this)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, this);
+
+	this->pdev = pdev;
+	this->dev  = &pdev->dev;
+
+	dev_data = of_device_get_match_data(&pdev->dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	this->ecc_modes = (unsigned long)dev_data;
+
+	this->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	this->base = devm_ioremap_resource(&pdev->dev, this->res);
+	if (IS_ERR(this->base))
+		return PTR_ERR(this->base);
+
+	this->core_clk = devm_clk_get(&pdev->dev, "core");
+	if (IS_ERR(this->core_clk))
+		return PTR_ERR(this->core_clk);
+
+	this->aon_clk = devm_clk_get(&pdev->dev, "aon");
+	if (IS_ERR(this->aon_clk))
+		return PTR_ERR(this->aon_clk);
+
+	r = qcom_nandc_parse_dt(pdev);
+	if (r)
+		return r;
+
+	r = qcom_nandc_alloc(this);
+	if (r)
+		return r;
+
+	r = clk_prepare_enable(this->core_clk);
+	if (r)
+		goto err_core_clk;
+
+	r = clk_prepare_enable(this->aon_clk);
+	if (r)
+		goto err_aon_clk;
+
+	r = qcom_nandc_init(this);
+	if (r)
+		goto err_init;
+
+	return 0;
+
+err_init:
+	clk_disable_unprepare(this->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(this->core_clk);
+err_core_clk:
+	qcom_nandc_unalloc(this);
+
+	return r;
+}
+
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1875

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+static int qcom_nandc_remove(struct platform_device *pdev)
+{
+	struct qcom_nandc_data *this = platform_get_drvdata(pdev);
+

You miss a call to nand_release() here, otherwise your device is still registered to the MTD/NAND layer, even though you've released all the resources attached to it.

I'll fix this.

Quoted 2 lines

That's all I got for now.

Thanks again for taking the time for the review. Really appreciate it.

Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#62 lore raw

Re: [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver

Quoted 39 lines · On Wed, 16 Dec 2015 17:27:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 39 lines
Quoted 9 lines

+/*
+ * NAND controller page layout info
+ *

+ * |-----------------------|	  |---------------------------------|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |	DATA	xx..ECC..xx|	  |	DATA	**SPARE**xx..ECC..xx|
+ * |   (516)	xx.......xx|	  |  (516-n*4)	**(n*4)**xx.......xx|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |-----------------------|	  |---------------------------------|
Quoted 11 lines

+ * codeword 1,2..n-1 codeword n
+ * <---(528/532 Bytes)----> <-------(528/532 Bytes)---------->
+ *
+ * n = number of codewords in the page
+ * . = ECC bytes
+ * * = spare bytes
+ * x = unused/reserved bytes
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes

Is there a reason not to use the following layout?

(
n x (
data = 512 bytes
protected OOB data = 4 bytes
ECC bytes = 12 or 16
)

+

remaining unprotected OOB bytes
)

This way the ECC layout definition would be easier to define, and you'll have something that is closer to what a NAND chip expect (ECC block/step size of 512 or 1024).

Quoted 7 lines
Quoted 1 line

I know this is also dependent on the bootloader, hence my question.

I tried to figure this out looking at documentation and the downstream drivers. What I understood was that all the OOB was intentionally kept in the last step, so that things are faster when we only want to access OOB. In that case, the controller will need to write to only one step/codeword.

Well, I don't think sending a column change command is that costly compared to a page retrieval command or ECC calculation.

Quoted 2 lines

The bootloaders also use the same layout.

Ok, then I guess we'll have to live with that (but it complicates a lot the driver logic :-/)

Quoted 20 lines
Quoted 17 lines
Quoted 16 lines

+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * the layout described above is used by the controller when the ECC block is
+ * enabled. When we read a page with ECC enabled, the unused/reserved bytes are
+ * skipped and not copied to our internal buffer. therefore, the nand_ecclayout
+ * layouts defined below doesn't consider the positions occupied by the reserved
+ * bytes

Quoted 2 lines

You could just read this portion with the ECC engine disabled when you're asked for OOB data.

Quoted 6 lines

Yes, but there are ecc ops (like ecc->read_page/ecc->write_page) that have an argument called 'oob_required'. We need to have ECC enabled when running these ops.

In order to read this additional portion, I'll need to read/write each step again with ECC disabled, which would really slow things down.

Nowadays, MTD FS are not using the OOB area, and oob_required is only passed if the MTD user asked for OOB data, so that can be an acceptable penalty. Anyway, that's not really important if we loose a few OOB bytes.

Quoted 10 lines
Quoted 9 lines
Quoted 6 lines

+ *
+ * when the ECC block is disabled, one unused byte (or two for 16 bit bus width)
+ * in the last codeword is the position of bad block marker. the bad block
+ * marker cannot be accessed when ECC is enabled.

So, you're switching the BBM with the data at the BBM position (possibly some in-band data), right?

Quoted 6 lines

Yes. When ECC isn't enabled, the BBM byte lies within the in-band data of the last step. In fact, there are dummy BBM bytes in the previous steps at the same offset.

With ECC enabled, the controller just skips that position (and the dummy BBM bytes in previous steps) altogether.

Okay.

Quoted 31 lines
Quoted 13 lines

drivers/mtd/nand/qcom_nandc.c line 1447

Quoted 9 lines

+ *
+ */

drivers/mtd/nand/qcom_nandc.c new file +5 -0
+
+/*
+ * Layouts for different page sizes and ecc modes. We skip the eccpos field
+ * since it isn't needed for this driver
+ */

If you know where they are stored, please specify them, even if they are not used by the upper layers (this helps analyzing raw nand dumps).

Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1455

Quoted 8 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+
+/* 2K page, 4 bit ECC */
+static struct nand_ecclayout layout_oob_64 = {
+	.eccbytes	= 40,
+	.oobfree	= {
+				{ 30, 16 },
+			  },
+};

According to your description it should either be eccbytes = 48 (if you're considering reserved bytes as ECC bytes) or 32 (if you're not counting reserved bytes).

Each step is 528 bytes in total. The first 3 steps contain 516 bytes of data, 10 bytes of ECC and 2 bytes of resrved data. The last step contains 500 bytes of data, 16 bytes of OOB, 10 bytes of ECC and 2 reserved bytes.

Quoted 5 lines

If I don't count the reserved bytes as part of ECC, I get 40. If I do count it as part of ECC, I get 48. In the way I described layouts, I ignored the ECC parts. How did you get 32?

From the ecc.bytes value you're filling in qcom_nandc_pre_init(). Just

multiplied it by 4 (the number of ECC steps).

And here is where weird things happen: you're setting ecc.size to 512 and ecc.strength to 4. But in reality, what you have is 4bits/516bytes for the first 3 blocks, and 4bits/500bytes for the last one. You're not only fooling the MTD user when faking a 4bits/512byte strength, you're also sightly modifying the logic supposed to detect the maximum number of bitflips found in a page.

This being said, I understand your constraints, just trying to explain why we're trying to use the symmetric ECC block size.

Quoted 11 lines
Quoted 3 lines

BTW, is the oobfree portion really starting at offset 30?

I thought the offsets mentioned here also had to incorporate positions taken by ECC bytes? If I strip all the the in-band data (real data) from each step, we get:

ECC(10 bytes).ECC(10 bytes).ECC(10 bytes).OOB(16 bytes).ECC(10 bytes)

Wouldn't this result in the offset as 30?

Yep, as I said I thought it was 32 because of what you put in ecc.size. And, you're putting OOB bytes before the last chunk of ECC bytes, because they are protected, right?

Note that you could put the oobfree area at the end of the OOB area, since this 10-10-10-16-10 representation is already a virtual representation of the OOB area (ECC bytes are actually interleaved with in-band data on the flash).

Quoted 5 lines

We are still only taking into account 56 bytes out of the 64 bytes in the chip's OOB. This is because I'm discaring the 2 bytes from each step (summing up to 8) which aren't accessible when ECC is enabled.

Okay. As said above, those two bytes could be exposed without two much overhead for most operations, but that's your call to make.

Quoted 10 lines
Quoted 4 lines

I'd say that in the 2K page, 4 bit ECC you don't have any oobfree bytes (528 * 4 == 2048 + 64).

528 contains both oob and in-band data. If you ignore the weird layout and assume we have at an average 512 bytes for each step, we get:

512 * 4 == 2048 bytes of data, and 64 bytes of OOB (16 bytes free, 40 ECC, and 8 reserved/unused).

Okay. Still think the ECC block asymmetry is not a good idea, but I get your point ;-).

Quoted 39 lines
Quoted 30 lines
Quoted 30 lines
drivers/mtd/nand/qcom_nandc.c new file +28 -0
+
+/* 4K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_128 = {
+	.eccbytes	= 80,
+	.oobfree	= {
+				{ 70, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 8 bit bus width */
+static struct nand_ecclayout layout_oob_224_x8 = {
+	.eccbytes	= 104,
+	.oobfree	= {
+				{ 91, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 16 bit bus width */
+static struct nand_ecclayout layout_oob_224_x16 = {
+	.eccbytes	= 112,
+	.oobfree	= {
+				{ 98, 32 },
+			  },
+};
+
+/* 8K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_256 = {
+	.eccbytes	= 160,
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1487

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	.oobfree	= {
+				{ 151, 64 },
+			  },
+};

Those ECC layout definitions could probably be dynamically created based on the detected ECC strength, bus-width and page size, instead of defining a new one for each new combination.

Quoted 1 line

That's true. I can try that out.

Cool.

Quoted 50 lines
Quoted 41 lines
Quoted 17 lines
drivers/mtd/nand/qcom_nandc.c new file +15 -0
+
+/*
+ * this is called before scan_ident, we do some minimal configurations so
+ * that reading ID and ONFI params work
+ */
+static void qcom_nandc_pre_init(struct qcom_nandc_data *this)
+{
+	/* kill onenand */
+	nandc_write(this, SFLASHC_BURST_CFG, 0);
+
+	/* enable ADM DMA */
+	nandc_write(this, NAND_FLASH_CHIP_SELECT, DM_EN);
+
+	/* save the original values of these registers */
+	this->cmd1 = nandc_read(this, NAND_DEV_CMD1);

drivers/mtd/nand/qcom_nandc.c line 1512

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	this->vld = nandc_read(this, NAND_DEV_CMD_VLD);
+
+	/* initial status value */
+	this->status = NAND_STATUS_READY | NAND_STATUS_WP;
+}
+
+static int qcom_nandc_ecc_init(struct qcom_nandc_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage;
+	bool wide_bus;
+
+	/* the nand controller fetches codewords/chunks of 512 bytes */
+	cwperpage = mtd->writesize >> 9;
+
+	ecc->strength = this->ecc_strength;
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1526

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		ecc->bytes = wide_bus ? 14 : 13;

Maybe you'd better consider that reserved bytes (after the ECC bytes) are actually ECC bytes. So, according to your description you would always have 16 here.

Quoted 4 lines

The thing is that if I consider the reserved bytes as a part of the ECC bytes, and if I use this bigger value when configuring the controller and dma, I will get bad results; becase the hardware doesn't touch these when ECC is enabled.

You should at least be consistent with what you put in your ECC layout. Choose one solution and stick to it. Since reserved bytes are not accessible I would suggest to count them in the number of ECC bytes.

Quoted 3 lines

I could set the ecc->bytes to '16' and still use the actual values when configuring the controller. Do you think that will help in any way?

You can have you own private field(s) to store you controller config, if that helps, or create a function which would convert ecc.bytes into something appropriate.

Quoted 5 lines
Quoted 3 lines

That's all I got for now.

Thanks again for taking the time for the review. Really appreciate it.

No problem.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#63 lore raw

Re: [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver

Quoted 44 lines · Boris Brezillon
Quoted 41 lines · On Wed, 16 Dec 2015 17:27:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 40 lines
Quoted 9 lines

+/*
+ * NAND controller page layout info
+ *

+ * |-----------------------|	  |---------------------------------|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |	DATA	xx..ECC..xx|	  |	DATA	**SPARE**xx..ECC..xx|
+ * |   (516)	xx.......xx|	  |  (516-n*4)	**(n*4)**xx.......xx|
+ * |		xx.......xx|	  |		*********xx.......xx|
+ * |-----------------------|	  |---------------------------------|
Quoted 11 lines

+ * codeword 1,2..n-1 codeword n
+ * <---(528/532 Bytes)----> <-------(528/532 Bytes)---------->
+ *
+ * n = number of codewords in the page
+ * . = ECC bytes
+ * * = spare bytes
+ * x = unused/reserved bytes
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes

Is there a reason not to use the following layout?

(
n x (
data = 512 bytes
protected OOB data = 4 bytes
ECC bytes = 12 or 16
)

+

remaining unprotected OOB bytes
)

This way the ECC layout definition would be easier to define, and you'll have something that is closer to what a NAND chip expect (ECC block/step size of 512 or 1024).

I know this is also dependent on the bootloader, hence my question.

Quoted 8 lines
Quoted 5 lines

I tried to figure this out looking at documentation and the downstream drivers. What I understood was that all the OOB was intentionally kept in the last step, so that things are faster when we only want to access OOB. In that case, the controller will need to write to only one step/codeword.

Well, I don't think sending a column change command is that costly compared to a page retrieval command or ECC calculation.

Yeah, that's probably true. Although, for this controller, we have
a fixed behavior: if you read a step within a page, the controller
reads the entire 516 bytes into its internal buffer. In other words, the controller would need to read the entire page for just 16 bytes of free OOB if we have the standard ECC layout.

Quoted 6 lines
Quoted 3 lines

The bootloaders also use the same layout.

Ok, then I guess we'll have to live with that (but it complicates a lot the driver logic :-/)

Yeah, it does :/

The controller does support a mode (where free OOB isn't protected by ECC). In that case, the flash layout is similar to the one you mentioned. But again, if the bootloaders use the weird layout, then
we don't have much choice.

Quoted 25 lines
Quoted 25 lines
Quoted 18 lines
Quoted 17 lines

+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * the layout described above is used by the controller when the ECC block is
+ * enabled. When we read a page with ECC enabled, the unused/reserved bytes are
+ * skipped and not copied to our internal buffer. therefore, the nand_ecclayout
+ * layouts defined below doesn't consider the positions occupied by the reserved
+ * bytes

Quoted 2 lines

You could just read this portion with the ECC engine disabled when you're asked for OOB data.

Yes, but there are ecc ops (like ecc->read_page/ecc->write_page) that have an argument called 'oob_required'. We need to have ECC enabled when running these ops.

Quoted 7 lines
Quoted 2 lines

In order to read this additional portion, I'll need to read/write each step again with ECC disabled, which would really slow things down.

Nowadays, MTD FS are not using the OOB area, and oob_required is only passed if the MTD user asked for OOB data, so that can be an acceptable penalty. Anyway, that's not really important if we loose a few OOB bytes.

Ah, okay.

Quoted 51 lines
Quoted 11 lines
Quoted 10 lines
Quoted 7 lines

+ *
+ * when the ECC block is disabled, one unused byte (or two for 16 bit bus width)
+ * in the last codeword is the position of bad block marker. the bad block
+ * marker cannot be accessed when ECC is enabled.

So, you're switching the BBM with the data at the BBM position (possibly some in-band data), right?

Quoted 6 lines

Yes. When ECC isn't enabled, the BBM byte lies within the in-band data of the last step. In fact, there are dummy BBM bytes in the previous steps at the same offset.

With ECC enabled, the controller just skips that position (and the dummy BBM bytes in previous steps) altogether.

Okay.

Quoted 31 lines
Quoted 13 lines

drivers/mtd/nand/qcom_nandc.c line 1447

Quoted 9 lines

+ *
+ */

drivers/mtd/nand/qcom_nandc.c new file +5 -0
+
+/*
+ * Layouts for different page sizes and ecc modes. We skip the eccpos field
+ * since it isn't needed for this driver
+ */

If you know where they are stored, please specify them, even if they are not used by the upper layers (this helps analyzing raw nand dumps).

Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1455

Quoted 8 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+
+/* 2K page, 4 bit ECC */
+static struct nand_ecclayout layout_oob_64 = {
+	.eccbytes	= 40,
+	.oobfree	= {
+				{ 30, 16 },
+			  },
+};

According to your description it should either be eccbytes = 48 (if you're considering reserved bytes as ECC bytes) or 32 (if you're not counting reserved bytes).

Each step is 528 bytes in total. The first 3 steps contain 516 bytes of data, 10 bytes of ECC and 2 bytes of resrved data. The last step contains 500 bytes of data, 16 bytes of OOB, 10 bytes of ECC and 2 reserved bytes.

Quoted 6 lines
Quoted 3 lines

If I don't count the reserved bytes as part of ECC, I get 40. If I do count it as part of ECC, I get 48. In the way I described layouts, I ignored the ECC parts. How did you get 32?

From the ecc.bytes value you're filling in qcom_nandc_pre_init(). Just
multiplied it by 4 (the number of ECC steps).

Oh, sorry, I didn't point that earlier, but this controller only supports Reed Solomon for 4 bit ECC. That requires 10 bytes per step.

Quoted 10 lines

And here is where weird things happen: you're setting ecc.size to 512 and ecc.strength to 4. But in reality, what you have is 4bits/516bytes for the first 3 blocks, and 4bits/500bytes for the last one. You're not only fooling the MTD user when faking a 4bits/512byte strength, you're also sightly modifying the logic supposed to detect the maximum number of bitflips found in a page.

This being said, I understand your constraints, just trying to explain why we're trying to use the symmetric ECC block size.

You're right. The lack of symmetry does cause complications. I can try to report this for the future, so that the people deciding the layouts keep this in mind.

Quoted 9 lines
Quoted 9 lines
Quoted 4 lines

BTW, is the oobfree portion really starting at offset 30?

I thought the offsets mentioned here also had to incorporate positions taken by ECC bytes? If I strip all the the in-band data (real data) from each step, we get:

Quoted 7 lines
Quoted 3 lines

ECC(10 bytes).ECC(10 bytes).ECC(10 bytes).OOB(16 bytes).ECC(10 bytes)

Wouldn't this result in the offset as 30?

Yep, as I said I thought it was 32 because of what you put in ecc.size. And, you're putting OOB bytes before the last chunk of ECC bytes, because they are protected, right?

Yes.

Quoted 5 lines

Note that you could put the oobfree area at the end of the OOB area, since this 10-10-10-16-10 representation is already a virtual representation of the OOB area (ECC bytes are actually interleaved with in-band data on the flash).

But, when I read from the controller's internal buffer via DMA, I first
get the oobfree area, and only then the last step's ECC bytes. So, the content in chip->oob_poi is in the same order as mentioned above (10-10-10-16-10).

If the upper layers uses MTD_OPS_AUTO_OOB, and if I have a different layout as what it is in the oob_poi buffer, then it'll end up reading/writing the wrong bytes in nand_transfer_oob/nand_fill_oob.

Are you suggesting that I modify the contents of oob_poi by hand such that it has a cleaner 10-10-10-10-16 representation?

Quoted 9 lines
Quoted 6 lines

We are still only taking into account 56 bytes out of the 64 bytes in the chip's OOB. This is because I'm discaring the 2 bytes from each step (summing up to 8) which aren't accessible when ECC is enabled.

Okay. As said above, those two bytes could be exposed without two much overhead for most operations, but that's your call to make.

When I read the oob regions into a buffer via DMA, I get a total of 56
bytes. For the extra 8 bytes, I will have to insert 2 dummy bytes manually for each step by hand. If I don't, then I'll end up messing what I read/write to oob.

Are you suggesting I do that? It will make the code slightly more messy, but as you said, at least give a more clearer description of the layout.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

I'd say that in the 2K page, 4 bit ECC you don't have any oobfree bytes (528 * 4 == 2048 + 64).

Quoted 8 lines
Quoted 5 lines

528 contains both oob and in-band data. If you ignore the weird layout and assume we have at an average 512 bytes for each step, we get:

512 * 4 == 2048 bytes of data, and 64 bytes of OOB (16 bytes free, 40 ECC, and 8 reserved/unused).

Okay. Still think the ECC block asymmetry is not a good idea, but I get your point ;-).

haha yeah, I don't think it's a good idea either :p. Sadly, we're stuck with it.

Quoted 104 lines
Quoted 40 lines
Quoted 31 lines
Quoted 31 lines
drivers/mtd/nand/qcom_nandc.c new file +28 -0
+
+/* 4K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_128 = {
+	.eccbytes	= 80,
+	.oobfree	= {
+				{ 70, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 8 bit bus width */
+static struct nand_ecclayout layout_oob_224_x8 = {
+	.eccbytes	= 104,
+	.oobfree	= {
+				{ 91, 32 },
+			  },
+};
+
+/* 4K page, 8 bit ECC, 16 bit bus width */
+static struct nand_ecclayout layout_oob_224_x16 = {
+	.eccbytes	= 112,
+	.oobfree	= {
+				{ 98, 32 },
+			  },
+};
+
+/* 8K page, 4 bit ECC, 8/16 bit bus width */
+static struct nand_ecclayout layout_oob_256 = {
+	.eccbytes	= 160,
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1487

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	.oobfree	= {
+				{ 151, 64 },
+			  },
+};

Those ECC layout definitions could probably be dynamically created based on the detected ECC strength, bus-width and page size, instead of defining a new one for each new combination.

Quoted 1 line

That's true. I can try that out.

Cool.

Quoted 50 lines
Quoted 41 lines
Quoted 17 lines
drivers/mtd/nand/qcom_nandc.c new file +15 -0
+
+/*
+ * this is called before scan_ident, we do some minimal configurations so
+ * that reading ID and ONFI params work
+ */
+static void qcom_nandc_pre_init(struct qcom_nandc_data *this)
+{
+	/* kill onenand */
+	nandc_write(this, SFLASHC_BURST_CFG, 0);
+
+	/* enable ADM DMA */
+	nandc_write(this, NAND_FLASH_CHIP_SELECT, DM_EN);
+
+	/* save the original values of these registers */
+	this->cmd1 = nandc_read(this, NAND_DEV_CMD1);

drivers/mtd/nand/qcom_nandc.c line 1512

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	this->vld = nandc_read(this, NAND_DEV_CMD_VLD);
+
+	/* initial status value */
+	this->status = NAND_STATUS_READY | NAND_STATUS_WP;
+}
+
+static int qcom_nandc_ecc_init(struct qcom_nandc_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = &this->chip;
	struct nand_chip *chip = &this->chip;
	struct mtd_info *mtd = nand_to_mtd(chip);
Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int cwperpage;
+	bool wide_bus;
+
+	/* the nand controller fetches codewords/chunks of 512 bytes */
+	cwperpage = mtd->writesize >> 9;
+
+	ecc->strength = this->ecc_strength;
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1526

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		ecc->bytes = wide_bus ? 14 : 13;

Maybe you'd better consider that reserved bytes (after the ECC bytes) are actually ECC bytes. So, according to your description you would always have 16 here.

Quoted 4 lines

The thing is that if I consider the reserved bytes as a part of the ECC bytes, and if I use this bigger value when configuring the controller and dma, I will get bad results; becase the hardware doesn't touch these when ECC is enabled.

You should at least be consistent with what you put in your ECC layout. Choose one solution and stick to it. Since reserved bytes are not accessible I would suggest to count them in the number of ECC bytes.

Quoted 1 line
Quoted 6 lines
Quoted 2 lines

I could set the ecc->bytes to '16' and still use the actual values when configuring the controller. Do you think that will help in any way?

You can have you own private field(s) to store you controller config, if that helps, or create a function which would convert ecc.bytes into something appropriate.

Right. Got it.

Thanks,
Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#64 lore raw

Re: [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver

Hi Archit,

Quoted 12 lines · On Thu, 17 Dec 2015 15:18:46 +0530 Archit Taneja <[email protected]> wrote:
Quoted 6 lines

Note that you could put the oobfree area at the end of the OOB area, since this 10-10-10-16-10 representation is already a virtual representation of the OOB area (ECC bytes are actually interleaved with in-band data on the flash).

But, when I read from the controller's internal buffer via DMA, I first get the oobfree area, and only then the last step's ECC bytes. So, the content in chip->oob_poi is in the same order as mentioned above (10-10-10-16-10).

Quoted 6 lines

If the upper layers uses MTD_OPS_AUTO_OOB, and if I have a different layout as what it is in the oob_poi buffer, then it'll end up reading/writing the wrong bytes in nand_transfer_oob/nand_fill_oob.

Are you suggesting that I modify the contents of oob_poi by hand such that it has a cleaner 10-10-10-10-16 representation?

Hm, I thought you could just place the free oob bytes wherever you want since there's only one oobfree region. AFAICS, it's just a matter of passing ->oob_poi + 40 instead of passing ->oob_poi + 30 when preparing the DMA descriptor (30 and 40 are just numbers for this specific use case).
Anyway, I won't complain if you address all comments but this one.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#65 lore raw

Re: [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja
Quoted 9 lines · Archit Taneja
Quoted 6 lines · Boris Brezillon

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 1 line · On Wed, 19 Aug 2015 10:19:03 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +1 -0
+	return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
	return mtd_device_parse_register(mtd, NULL, NULL, NULL 0);

Will fix.

Or just:

	return mtd_device_register(mtd, NULL, 0);
#66 lore raw

PATCH v4 3/5 dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

v4:
- No changes

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

---
 .../devicetree/bindings/mtd/qcom_nandc.txt         | 49 ++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +49 -0
new file mode 100644
index 0000000..1de4643
@@ -0,0 +1,49 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits. If not present, 4 is chosen as default
+- nand-on-flash-bbt:	Create/use on-flash bad block table
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	partition@0 {
+	...
+	};
+};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#67 lore raw

Re: [PATCH v4 3/5] dt/bindings: qcom_nandc: Add DT bindings

Hi Archit,

Sorry for the late review, but there are a few things I think should be addressed.

Quoted 63 lines · On Wed, 19 Aug 2015 10:19:04 +0530 Archit Taneja <[email protected]> wrote:

Add DT bindings document for the Qualcomm NAND controller driver.

v4:
- No changes

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

---
 .../devicetree/bindings/mtd/qcom_nandc.txt         | 49 ++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +39 -0
new file mode 100644
index 0000000..1de4643
@@ -0,0 +1,49 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits. If not present, 4 is chosen as default
+- nand-on-flash-bbt:	Create/use on-flash bad block table
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 49

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	partition@0 {
+	...
+	};
+};

According to the registers layout defined in your driver, your NAND controller can address multiple chips (NAND_DEV_SEL register). Since DT bindings are supposed to be as stable as possible, I would recommend separating the NAND controller and NAND chip declaration (as done here
[1] and here [2]).

Best Regards,

Boris

[1]http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt [2]http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/mtd/sunxi-nand.txt

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#68 lore raw

Re: [PATCH v4 3/5] dt/bindings: qcom_nandc: Add DT bindings

Hi Boris,

Quoted 80 lines · Boris Brezillon

Hi Archit,

Sorry for the late review, but there are a few things I think should be addressed.

Quoted 72 lines · On Wed, 19 Aug 2015 10:19:04 +0530 Archit Taneja <[email protected]> wrote:

Add DT bindings document for the Qualcomm NAND controller driver.

v4:
- No changes

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

---
  .../devicetree/bindings/mtd/qcom_nandc.txt         | 49 ++++++++++++++++++++++
  1 file changed, 49 insertions(+)

create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt

Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +48 -0
new file mode 100644
index 0000000..1de4643
@@ -0,0 +1,49 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits. If not present, 4 is chosen as default
+- nand-on-flash-bbt:	Create/use on-flash bad block table
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	partition@0 {
+	...
+	};
Quoted 8 lines

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 49

Quoted 1 line
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +1 -0
+};

According to the registers layout defined in your driver, your NAND controller can address multiple chips (NAND_DEV_SEL register). Since DT bindings are supposed to be as stable as possible, I would recommend separating the NAND controller and NAND chip declaration (as done here
[1] and here [2]).

Yes, the controller does support multiple chips, but the driver only supports one chip for now.

I'll make changes such that the driver works in accordance to the DT bindings format you shared.

Thanks for the review.

Archit

Quoted 9 lines

Best Regards,

Boris

[1]http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt [2]http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/mtd/sunxi-nand.txt

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#69 lore raw

PATCH v4 4/5 arm: qcom: dts: Add NAND controller node for ipq806x

In reply to Archit Taneja

The nand controller in IPQ806x is of the 'EBI2 type'. Use the corresponding compatible string.

---
 arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/arm/boot/dts/qcom-ipq8064.dtsi +15 -0
index 1e1b3f0..a7f0ee5 100644
@@ -350,5 +350,20 @@
 			status = "disabled";
 		};
 
+		nand@1ac00000 {
+			compatible = "qcom,ebi2-nandc";
+			reg = <0x1ac00000 0x800>;
+
+			clocks = <&gcc EBI2_CLK>,
+				 <&gcc EBI2_AON_CLK>;
+			clock-names = "core", "aon";
+
+			dmas = <&adm_dma 3>;
+			dma-names = "rxtx";
+			qcom,cmd-crci = <15>;
+			qcom,data-crci = <3>;
+
+			status = "disabled";
+		};
 	};
 };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#70 lore raw

PATCH v4 5/5 arm: qcom: dts: Enable NAND node on IPQ8064 AP148 platform

In reply to Archit Taneja

Enable the NAND controller node on the AP148 platform. Provide pinmux information.

v4:
- Move bias-disable out of mux and create a separate group for it.
- Place the dma node inside soc node and give the full path with address.

v3, v2, v1:
- No changes

---
 arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 40 ++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
arch/arm/boot/dts/qcom-ipq8064-ap148.dts +40 -0
index 7f9ea50..648994c 100644
@@ -30,6 +30,32 @@
 					bias-none;
 				};
 			};
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+				};
+				disable {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38";
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
 		};
 
 		gsbi@16300000 {
@@ -93,5 +119,19 @@
 		sata@29000000 {
 			status = "ok";
 		};
+
+		dma@18300000 {
+			status = "ok";
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			nand-ecc-strength = <4>;
+			nand-bus-width = <8>;
+		};
 	};
 };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#71 lore raw

v5 cover mtd: Qualcomm NAND controller driver

In reply to Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

The first patch in the series contains a nand_base clean up which the driver will utilize.

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

v5:
- Skip creation of BBT as in v1. Will bring this back after BBMs are read/written in raw mode (using badblockbits support).
- Incorporated misc fixes/suggestions by Boris.
- Dropped the DT patches for now, since ADM DMA support isn't merged yet.

v4:
- Some more fixes. Mentioned in individual patch

v3:
- Various fixes and clean ups suggested by Stephen Boyd.

v2:
- Added a new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

v1:
- original series:
https://lkml.org/lkml/2015/1/16/317

Archit Taneja (3):
mtd: nand: don't select chip in nand_chip's block_bad op
mtd: nand: Qualcomm NAND controller driver dt/bindings: qcom_nandc: Add DT bindings

 .../devicetree/bindings/mtd/qcom_nandc.txt         |   84 +
 drivers/mtd/nand/Kconfig                           |    7 +
 drivers/mtd/nand/Makefile                          |    1 +
 drivers/mtd/nand/nand_base.c                       |   41 +-
 drivers/mtd/nand/qcom_nandc.c                      | 1981 ++++++++++++++++++++
 include/linux/mtd/nand.h                           |    2 +-
 6 files changed, 2097 insertions(+), 19 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#72 lore raw

PATCH v5 1/3 mtd: nand: don't select chip in nand_chip's block_bad op

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and move the chip selection to nand_block_checkbad (the only user of chip->block_bad). Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

---
 drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++++++------------------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 24 insertions(+), 19 deletions(-)
drivers/mtd/nand/nand_base.c +23 -18
index 928081b..42aa441 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-	int page, chipnr, res = 0, i = 0;
+	int page, res = 0, i = 0;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	u16 bad;
 
@@ -328,15 +328,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
-
 	do {
 		if (chip->options & NAND_BUSWIDTH_16) {
 			chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +352,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 		i++;
 	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-	if (getchip) {
-		chip->select_chip(mtd, -1);
-		nand_release_device(mtd);
-	}
-
 	return res;
 }
 
@@ -514,8 +500,27 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+	if (!chip->bbt) {
+		int ret;
+
+		if (getchip) {
+			int chipnr = (int)(ofs >> chip->chip_shift);
+
+			nand_get_device(mtd, FL_READING);
+
+			/* Select the NAND device */
+			chip->select_chip(mtd, chipnr);
+		}
+
+		ret = chip->block_bad(mtd, ofs);
+
+		if (getchip) {
+			chip->select_chip(mtd, -1);
+			nand_release_device(mtd);
+		}
+
+		return ret;
+	}
 
 	/* Return info from the table */
 	return nand_isbad_bbt(mtd, ofs, allowbbt);
include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#73 lore raw

Re: [PATCH v5 1/3] mtd: nand: don't select chip in nand_chip's block_bad op

Quoted 4 lines · On Tue, 5 Jan 2016 10:54:59 +0530 Archit Taneja <[email protected]> wrote:

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

Quoted 8 lines

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and move the chip selection to nand_block_checkbad (the only user of chip->block_bad). Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

I would go even further and move the chip selection into nand_block_isbad(), who is the only caller that requires this chip selection.

Quoted 94 lines
---
 drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++++++------------------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 24 insertions(+), 19 deletions(-)
drivers/mtd/nand/nand_base.c +23 -18
index 928081b..42aa441 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-	int page, chipnr, res = 0, i = 0;
+	int page, res = 0, i = 0;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	u16 bad;
 
@@ -328,15 +328,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
-
 	do {
 		if (chip->options & NAND_BUSWIDTH_16) {
 			chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +352,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 		i++;
 	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-	if (getchip) {
-		chip->select_chip(mtd, -1);
-		nand_release_device(mtd);
-	}
-
 	return res;
 }
 
@@ -514,8 +500,27 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+	if (!chip->bbt) {
+		int ret;
+
+		if (getchip) {
+			int chipnr = (int)(ofs >> chip->chip_shift);
+
+			nand_get_device(mtd, FL_READING);
+
+			/* Select the NAND device */
+			chip->select_chip(mtd, chipnr);
+		}
+
+		ret = chip->block_bad(mtd, ofs);
+
+		if (getchip) {
+			chip->select_chip(mtd, -1);
+			nand_release_device(mtd);
+		}
+
+		return ret;
+	}
 
 	/* Return info from the table */
 	return nand_isbad_bbt(mtd, ofs, allowbbt);
include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#74 lore raw

Re: [PATCH v5 1/3] mtd: nand: don't select chip in nand_chip's block_bad op

Quoted 11 lines · Boris Brezillon
Quoted 8 lines · On Tue, 5 Jan 2016 10:54:59 +0530 Archit Taneja <[email protected]> wrote:

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Quoted 8 lines
Quoted 4 lines

Remove the getchip argument from the block_bad op and move the chip selection to nand_block_checkbad (the only user of chip->block_bad). Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

I would go even further and move the chip selection into nand_block_isbad(), who is the only caller that requires this chip selection.

You're right. The only other place where nand_block_checkbad is used is nand_erase_nand, and that already selects the chip before.

I'll update the patch.

Thanks,
Archit

Quoted 98 lines
Quoted 95 lines
---
  drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++++++------------------
  include/linux/mtd/nand.h     |  2 +-
  2 files changed, 24 insertions(+), 19 deletions(-)
drivers/mtd/nand/nand_base.c +23 -18
index 928081b..42aa441 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
   *
   * Check, if the block is bad.
   */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
  {
-	int page, chipnr, res = 0, i = 0;
+	int page, res = 0, i = 0;
  	struct nand_chip *chip = mtd_to_nand(mtd);
  	u16 bad;
 
@@ -328,15 +328,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
  	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
-
  	do {
  		if (chip->options & NAND_BUSWIDTH_16) {
  			chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +352,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
  		i++;
  	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-	if (getchip) {
-		chip->select_chip(mtd, -1);
-		nand_release_device(mtd);
-	}
-
  	return res;
  }
 
@@ -514,8 +500,27 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
  {
  	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+	if (!chip->bbt) {
+		int ret;
+
+		if (getchip) {
+			int chipnr = (int)(ofs >> chip->chip_shift);
+
+			nand_get_device(mtd, FL_READING);
+
+			/* Select the NAND device */
+			chip->select_chip(mtd, chipnr);
+		}
+
+		ret = chip->block_bad(mtd, ofs);
+
+		if (getchip) {
+			chip->select_chip(mtd, -1);
+			nand_release_device(mtd);
+		}
+
+		return ret;
+	}
 
  	/* Return info from the table */
  	return nand_isbad_bbt(mtd, ofs, allowbbt);
include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
  	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
  	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
  	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
  	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
  	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
  	int (*dev_ready)(struct mtd_info *mtd);
Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#75 lore raw

PATCH v5 2/3 mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1989 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +1981 -0

1,981 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#76 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Hi Archit,

Quoted 263 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1989 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +146 -0
new file mode 100644
index 0000000..a4dd922
@@ -0,0 +1,1981 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/delay.h>
+
+/* NANDc reg offsets */
+#define NAND_FLASH_CMD			0x00
+#define NAND_ADDR0			0x04
+#define NAND_ADDR1			0x08
+#define NAND_FLASH_CHIP_SELECT		0x0c
+#define NAND_EXEC_CMD			0x10
+#define NAND_FLASH_STATUS		0x14
+#define NAND_BUFFER_STATUS		0x18
+#define NAND_DEV0_CFG0			0x20
+#define NAND_DEV0_CFG1			0x24
+#define NAND_DEV0_ECC_CFG		0x28
+#define NAND_DEV1_ECC_CFG		0x2c
+#define NAND_DEV1_CFG0			0x30
+#define NAND_DEV1_CFG1			0x34
+#define NAND_READ_ID			0x40
+#define NAND_READ_STATUS		0x44
+#define NAND_DEV_CMD0			0xa0
+#define NAND_DEV_CMD1			0xa4
+#define NAND_DEV_CMD2			0xa8
+#define NAND_DEV_CMD_VLD		0xac
+#define SFLASHC_BURST_CFG		0xe0
+#define NAND_ERASED_CW_DETECT_CFG	0xe8
+#define NAND_ERASED_CW_DETECT_STATUS	0xec
+#define NAND_EBI2_ECC_BUF_CFG		0xf0
+#define FLASH_BUF_ACC			0x100
+
+#define NAND_CTRL			0xf00
+#define NAND_VERSION			0xf08
+#define NAND_READ_LOCATION_0		0xf20
+#define NAND_READ_LOCATION_1		0xf24
+
+/* dummy register offsets, used by write_reg_dma */
+#define NAND_DEV_CMD1_RESTORE		0xdead
+#define NAND_DEV_CMD_VLD_RESTORE	0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define PAGE_ACC			BIT(4)
+#define LAST_PAGE			BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define NAND_DEV_SEL			0
+#define DM_EN				BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define FS_OP_ERR			BIT(4)
+#define FS_READY_BSY_N			BIT(5)
+#define FS_MPU_ERR			BIT(8)
+#define FS_DEVICE_STS_ERR		BIT(16)
+#define FS_DEVICE_WP			BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define BS_UNCORRECTABLE_BIT		BIT(8)
+#define BS_CORRECTABLE_ERR_MSK		0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define DISABLE_STATUS_AFTER_WRITE	4
+#define CW_PER_PAGE			6
+#define UD_SIZE_BYTES			9
+#define ECC_PARITY_SIZE_BYTES_RS	19
+#define SPARE_SIZE_BYTES		23
+#define NUM_ADDR_CYCLES			27
+#define STATUS_BFR_READ			30
+#define SET_RD_MODE_AFTER_STATUS	31
+
+/* NAND_DEVn_CFG0 bits */
+#define DEV0_CFG1_ECC_DISABLE		0
+#define WIDE_FLASH			1
+#define NAND_RECOVERY_CYCLES		2
+#define CS_ACTIVE_BSY			5
+#define BAD_BLOCK_BYTE_NUM		6
+#define BAD_BLOCK_IN_SPARE_AREA		16
+#define WR_RD_BSY_GAP			17
+#define ENABLE_BCH_ECC			27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define ECC_CFG_ECC_DISABLE		0
+#define ECC_SW_RESET			1
+#define ECC_MODE			4
+#define ECC_PARITY_SIZE_BYTES_BCH	8
+#define ECC_NUM_DATA_BYTES		16
+#define ECC_FORCE_CLK_OPEN		30
+
+/* NAND_DEV_CMD1 bits */
+#define READ_ADDR			0
+
+/* NAND_DEV_CMD_VLD bits */
+#define READ_START_VLD			0
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define NUM_STEPS			0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define ERASED_CW_ECC_MASK		1
+#define AUTO_DETECT_RES			0
+#define MASK_ECC			(1 << ERASED_CW_ECC_MASK)
+#define RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
+#define ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
+#define CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
+#define SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define PAGE_ALL_ERASED			BIT(7)
+#define CODEWORD_ALL_ERASED		BIT(6)
+#define PAGE_ERASED			BIT(5)
+#define CODEWORD_ERASED			BIT(4)
+#define ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
+#define ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* Version Mask */
+#define NAND_VERSION_MAJOR_MASK		0xf0000000
+#define NAND_VERSION_MAJOR_SHIFT	28
+#define NAND_VERSION_MINOR_MASK		0x0fff0000
+#define NAND_VERSION_MINOR_SHIFT	16
+
+/* NAND OP_CMDs */
+#define PAGE_READ			0x2
+#define PAGE_READ_WITH_ECC		0x3
+#define PAGE_READ_WITH_ECC_SPARE	0x4
+#define PROGRAM_PAGE			0x6
+#define PAGE_PROGRAM_WITH_ECC		0x7

drivers/mtd/nand/qcom_nandc.c line 156

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+#define PROGRAM_PAGE_SPARE		0x9
+#define BLOCK_ERASE			0xa
+#define FETCH_ID			0xb
+#define RESET_DEVICE			0xd
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define NANDC_STEP_SIZE			512

Sometimes you're using spaces...

drivers/mtd/nand/qcom_nandc.c line 162

Quoted 6 lines
drivers/mtd/nand/qcom_nandc.c new file +6 -0
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)

... and other times tabs between #define and the MACRO name. I'd suggest choosing one solution and sticking to it.

drivers/mtd/nand/qcom_nandc.c line 171

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+
+/* we read at most 3 registers per codeword scan */
+#define MAX_REG_RD			(3 * MAX_NUM_STEPS)
+
+/* ECC modes supported by the controller */
+#define ECC_NONE	BIT(0)
+#define ECC_RS_4BIT	BIT(1)
+#define	ECC_BCH_4BIT	BIT(2)
+#define	ECC_BCH_8BIT	BIT(3)

Ditto.

Quoted 80 lines
drivers/mtd/nand/qcom_nandc.c new file +80 -0
+
+struct desc_info {
+	struct list_head node;
+
+	enum dma_data_direction dir;
+	struct scatterlist sgl;
+	struct dma_async_tx_descriptor *dma_desc;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+	__le32 cmd;
+	__le32 addr0;
+	__le32 addr1;
+	__le32 chip_sel;
+	__le32 exec;
+
+	__le32 cfg0;
+	__le32 cfg1;
+	__le32 ecc_bch_cfg;
+
+	__le32 clrflashstatus;
+	__le32 clrreadstatus;
+
+	__le32 cmd1;
+	__le32 vld;
+
+	__le32 orig_cmd1;
+	__le32 orig_vld;
+
+	__le32 ecc_buf_cfg;
+};
+
+/*
+ * NAND controller data struct
+ *
+ * @controller:			base controller structure
+ * @host_list:			list containing all the chips attached to the
+ *				controller
+ * @dev:			parent device
+ * @res:			resource pointer for platform device (used to
+ *				retrieve the physical addresses of registers
+ *				for DMA)
+ * @base:			MMIO base
+ * @core_clk:			controller clock
+ * @aon_clk:			another controller clock
+ *
+ * @chan:			dma channel
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @desc_list:			DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		local buffer for reading back registers via DMA
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ *
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes. contains the register values to be
+ *				written to controller
+ * @cmd1/vld:			some fixed controller register values
+ * @ecc_modes:			supported ECC modes by the current controller,
+ *				initialized via DT match data
+ */
+struct qcom_nand_controller {
+	struct nand_hw_control controller;
+	struct list_head host_list;
+
+	struct device *dev;
+
+	struct resource *res;
+	void __iomem *base;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;

drivers/mtd/nand/qcom_nandc.c line 261

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+	struct dma_chan *chan;
+	unsigned int cmd_crci;
+	unsigned int data_crci;
+	struct list_head desc_list;
+
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;

Same remark as for the macro definitions.

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+	__le32 *reg_read_buf;
+	int reg_read_pos;
+
+	struct nandc_regs *regs;
+
+	u32 cmd1, vld;
+	u32 ecc_modes;
+};
+

[...]

Quoted 59 lines
drivers/mtd/nand/qcom_nandc.c new file +59 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;

drivers/mtd/nand/qcom_nandc.c line 1006

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

[...]

Quoted 67 lines
drivers/mtd/nand/qcom_nandc.c new file +67 -0
+
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage, spare_bytes, bbm_size, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			spare_bytes = 0;
+			bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			spare_bytes = 2;
+			bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				spare_bytes = 2;
+				bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				spare_bytes = 4;
+				bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				spare_bytes = 0;
+				bbm_size = 2;
+			} else {
+				spare_bytes = 1;
+				bbm_size = 1;
+			}

drivers/mtd/nand/qcom_nandc.c line 1609

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + spare_bytes + bbm_size;

You should add the following check:

	if (ecc->bytes * (mtd->writesize / ecc->size) < mtd->oobsize) {
		dev_err(nandc->dev, "ecc data do not fit in OOB
	area\n");
		return -EINVAL;
	}
Quoted 79 lines
drivers/mtd/nand/qcom_nandc.c new file +79 -0
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	ecc->mode = NAND_ECC_HW;
+
+	ecc->layout = qcom_nand_create_layout(host);
+	if (!ecc->layout)
+		return -ENOMEM;
+
+	cwperpage = mtd->writesize / ecc->size;
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	host->cw_data = 516;
+
+	/*
+	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+	 * for 8 bit ECC
+	 */
+	host->cw_size = host->cw_data + ecc->bytes;
+
+	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| spare_bytes << SPARE_SIZE_BYTES;
+
+	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| host->bch_enabled << ENABLE_BCH_ECC;
+
+	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| host->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	host->clrflashstatus = FS_READY_BSY_N;
+	host->clrreadstatus = 0xc0;
+
+	dev_dbg(nandc->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+		cwperpage);
+
+	return 0;
+}

[...]

Quoted 77 lines
drivers/mtd/nand/qcom_nandc.c new file +77 -0
+
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc;
+	const void *dev_data;
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	int ret;
+
+	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+	if (!nandc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, nandc);
+	nandc->dev = dev;
+
+	dev_data = of_device_get_match_data(dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	nandc->ecc_modes = (unsigned long) dev_data;
+
+	nandc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nandc->base = devm_ioremap_resource(dev, nandc->res);
+	if (IS_ERR(nandc->base))
+		return PTR_ERR(nandc->base);
+
+	nandc->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(nandc->core_clk))
+		return PTR_ERR(nandc->core_clk);
+
+	nandc->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(nandc->aon_clk))
+		return PTR_ERR(nandc->aon_clk);
+
+	ret = qcom_nandc_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(nandc->core_clk);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->aon_clk);
+	if (ret)
+		goto err_aon_clk;
+
+	ret = qcom_nandc_setup(nandc);
+	if (ret)
+		goto err_setup;
+
+	for_each_available_child_of_node(dn, child) {
+		if (of_device_is_compatible(child, "qcom,nandcs")) {
+			struct qcom_nand_host *host;
+
+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+			if (!host) {
+				of_node_put(child);
+				ret = -ENOMEM;
+				goto err_setup;
+			}
+
+			host->nandc = nandc;
+			ret = qcom_nand_host_init(host, child);
+			if (ret) {
+				devm_kfree(dev, host);
+				continue;
+			}
+
+			list_add_tail(&host->node, &nandc->host_list);
+		}

drivers/mtd/nand/qcom_nandc.c line 1929

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	}
+
+	if (list_empty(&nandc->host_list)) {
+		ret = -ENODEV;
+		goto err_setup;
+	}
+
+	return 0;
+
+err_setup:

You should also release the nand devices that may have been registered in the above loop.

Quoted 42 lines
drivers/mtd/nand/qcom_nandc.c new file +42 -0
+	clk_disable_unprepare(nandc->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(nandc->core_clk);
+err_core_clk:
+	qcom_nandc_unalloc(nandc);
+
+	return ret;
+}
+
+static int qcom_nandc_remove(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+	struct qcom_nand_host *host;
+
+	list_for_each_entry(host, &nandc->host_list, node)
+		nand_release(nand_to_mtd(&host->chip));
+
+	qcom_nandc_unalloc(nandc);
+
+	clk_disable_unprepare(nandc->aon_clk);
+	clk_disable_unprepare(nandc->core_clk);
+
+	return 0;
+}
+
+#define EBI2_NANDC_ECC_MODES	(ECC_RS_4BIT | ECC_BCH_8BIT)
+
+/*
+ * data will hold a struct pointer containing more differences once we support
+ * more controller variants
+ */
+static const struct of_device_id qcom_nandc_of_match[] = {
+	{	.compatible = "qcom,ebi2-nandc",
+		.data = (void *) EBI2_NANDC_ECC_MODES,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
+
+static struct platform_driver qcom_nandc_driver = {
+	.driver = {
+		.name = "qcom-nandc",

drivers/mtd/nand/qcom_nandc.c line 1981

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+		.of_match_table = qcom_nandc_of_match,
+	},
+	.probe   = qcom_nandc_probe,
+	.remove  = qcom_nandc_remove,
+};
+module_platform_driver(qcom_nandc_driver);
+
+MODULE_AUTHOR("Archit Taneja <[email protected]>");
+MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
+MODULE_LICENSE("GPL v2");

Thanks for the rework you've done on the other parts of the code.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#77 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Hi,

Quoted 387 lines · Boris Brezillon

Hi Archit,

Quoted 263 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 1989 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
  	help
  	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
  endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
  obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
  obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
  obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
  nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +146 -0
new file mode 100644
index 0000000..a4dd922
@@ -0,0 +1,1981 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/delay.h>
+
+/* NANDc reg offsets */
+#define NAND_FLASH_CMD			0x00
+#define NAND_ADDR0			0x04
+#define NAND_ADDR1			0x08
+#define NAND_FLASH_CHIP_SELECT		0x0c
+#define NAND_EXEC_CMD			0x10
+#define NAND_FLASH_STATUS		0x14
+#define NAND_BUFFER_STATUS		0x18
+#define NAND_DEV0_CFG0			0x20
+#define NAND_DEV0_CFG1			0x24
+#define NAND_DEV0_ECC_CFG		0x28
+#define NAND_DEV1_ECC_CFG		0x2c
+#define NAND_DEV1_CFG0			0x30
+#define NAND_DEV1_CFG1			0x34
+#define NAND_READ_ID			0x40
+#define NAND_READ_STATUS		0x44
+#define NAND_DEV_CMD0			0xa0
+#define NAND_DEV_CMD1			0xa4
+#define NAND_DEV_CMD2			0xa8
+#define NAND_DEV_CMD_VLD		0xac
+#define SFLASHC_BURST_CFG		0xe0
+#define NAND_ERASED_CW_DETECT_CFG	0xe8
+#define NAND_ERASED_CW_DETECT_STATUS	0xec
+#define NAND_EBI2_ECC_BUF_CFG		0xf0
+#define FLASH_BUF_ACC			0x100
+
+#define NAND_CTRL			0xf00
+#define NAND_VERSION			0xf08
+#define NAND_READ_LOCATION_0		0xf20
+#define NAND_READ_LOCATION_1		0xf24
+
+/* dummy register offsets, used by write_reg_dma */
+#define NAND_DEV_CMD1_RESTORE		0xdead
+#define NAND_DEV_CMD_VLD_RESTORE	0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define PAGE_ACC			BIT(4)
+#define LAST_PAGE			BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define NAND_DEV_SEL			0
+#define DM_EN				BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define FS_OP_ERR			BIT(4)
+#define FS_READY_BSY_N			BIT(5)
+#define FS_MPU_ERR			BIT(8)
+#define FS_DEVICE_STS_ERR		BIT(16)
+#define FS_DEVICE_WP			BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define BS_UNCORRECTABLE_BIT		BIT(8)
+#define BS_CORRECTABLE_ERR_MSK		0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define DISABLE_STATUS_AFTER_WRITE	4
+#define CW_PER_PAGE			6
+#define UD_SIZE_BYTES			9
+#define ECC_PARITY_SIZE_BYTES_RS	19
+#define SPARE_SIZE_BYTES		23
+#define NUM_ADDR_CYCLES			27
+#define STATUS_BFR_READ			30
+#define SET_RD_MODE_AFTER_STATUS	31
+
+/* NAND_DEVn_CFG0 bits */
+#define DEV0_CFG1_ECC_DISABLE		0
+#define WIDE_FLASH			1
+#define NAND_RECOVERY_CYCLES		2
+#define CS_ACTIVE_BSY			5
+#define BAD_BLOCK_BYTE_NUM		6
+#define BAD_BLOCK_IN_SPARE_AREA		16
+#define WR_RD_BSY_GAP			17
+#define ENABLE_BCH_ECC			27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define ECC_CFG_ECC_DISABLE		0
+#define ECC_SW_RESET			1
+#define ECC_MODE			4
+#define ECC_PARITY_SIZE_BYTES_BCH	8
+#define ECC_NUM_DATA_BYTES		16
+#define ECC_FORCE_CLK_OPEN		30
+
+/* NAND_DEV_CMD1 bits */
+#define READ_ADDR			0
+
+/* NAND_DEV_CMD_VLD bits */
+#define READ_START_VLD			0
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define NUM_STEPS			0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define ERASED_CW_ECC_MASK		1
+#define AUTO_DETECT_RES			0
+#define MASK_ECC			(1 << ERASED_CW_ECC_MASK)
+#define RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
+#define ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
+#define CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
+#define SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define PAGE_ALL_ERASED			BIT(7)
+#define CODEWORD_ALL_ERASED		BIT(6)
+#define PAGE_ERASED			BIT(5)
+#define CODEWORD_ERASED			BIT(4)
+#define ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
+#define ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* Version Mask */
+#define NAND_VERSION_MAJOR_MASK		0xf0000000
+#define NAND_VERSION_MAJOR_SHIFT	28
+#define NAND_VERSION_MINOR_MASK		0x0fff0000
+#define NAND_VERSION_MINOR_SHIFT	16
+
+/* NAND OP_CMDs */
+#define PAGE_READ			0x2
+#define PAGE_READ_WITH_ECC		0x3
+#define PAGE_READ_WITH_ECC_SPARE	0x4
+#define PROGRAM_PAGE			0x6
+#define PAGE_PROGRAM_WITH_ECC		0x7

drivers/mtd/nand/qcom_nandc.c line 156

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+#define PROGRAM_PAGE_SPARE		0x9
+#define BLOCK_ERASE			0xa
+#define FETCH_ID			0xb
+#define RESET_DEVICE			0xd
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define NANDC_STEP_SIZE			512

Sometimes you're using spaces...

drivers/mtd/nand/qcom_nandc.c line 162

Quoted 6 lines
drivers/mtd/nand/qcom_nandc.c new file +6 -0
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)

... and other times tabs between #define and the MACRO name. I'd suggest choosing one solution and sticking to it.

drivers/mtd/nand/qcom_nandc.c line 171

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+
+/* we read at most 3 registers per codeword scan */
+#define MAX_REG_RD			(3 * MAX_NUM_STEPS)
+
+/* ECC modes supported by the controller */
+#define ECC_NONE	BIT(0)
+#define ECC_RS_4BIT	BIT(1)
+#define	ECC_BCH_4BIT	BIT(2)
+#define	ECC_BCH_8BIT	BIT(3)

Ditto.

Quoted 84 lines
drivers/mtd/nand/qcom_nandc.c new file +84 -0
+
+struct desc_info {
+	struct list_head node;
+
+	enum dma_data_direction dir;
+	struct scatterlist sgl;
+	struct dma_async_tx_descriptor *dma_desc;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+	__le32 cmd;
+	__le32 addr0;
+	__le32 addr1;
+	__le32 chip_sel;
+	__le32 exec;
+
+	__le32 cfg0;
+	__le32 cfg1;
+	__le32 ecc_bch_cfg;
+
+	__le32 clrflashstatus;
+	__le32 clrreadstatus;
+
+	__le32 cmd1;
+	__le32 vld;
+
+	__le32 orig_cmd1;
+	__le32 orig_vld;
+
+	__le32 ecc_buf_cfg;
+};
+
+/*
+ * NAND controller data struct
+ *
+ * @controller:			base controller structure
+ * @host_list:			list containing all the chips attached to the
+ *				controller
+ * @dev:			parent device
+ * @res:			resource pointer for platform device (used to
+ *				retrieve the physical addresses of registers
+ *				for DMA)
+ * @base:			MMIO base
+ * @core_clk:			controller clock
+ * @aon_clk:			another controller clock
+ *
+ * @chan:			dma channel
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @desc_list:			DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		local buffer for reading back registers via DMA
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ *
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes. contains the register values to be
+ *				written to controller
+ * @cmd1/vld:			some fixed controller register values
+ * @ecc_modes:			supported ECC modes by the current controller,
+ *				initialized via DT match data
+ */
+struct qcom_nand_controller {
+	struct nand_hw_control controller;
+	struct list_head host_list;
+
+	struct device *dev;
+
+	struct resource *res;
+	void __iomem *base;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;
+
+	struct dma_chan *chan;
+	unsigned int cmd_crci;
+	unsigned int data_crci;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 261

Quoted 6 lines
drivers/mtd/nand/qcom_nandc.c new file +6 -0
+	struct list_head desc_list;
+
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;

Same remark as for the macro definitions.

Thanks for pointing it out. I'll take care of this.

Quoted 79 lines
Quoted 11 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+
+	__le32 *reg_read_buf;
+	int reg_read_pos;
+
+	struct nandc_regs *regs;
+
+	u32 cmd1, vld;
+	u32 ecc_modes;
+};
+

[...]

Quoted 65 lines
drivers/mtd/nand/qcom_nandc.c new file +65 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 986

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

We wouldn't be able to use nand_check_erased_ecc_chunk directly because there are certain bytes in each chunk that are intentionally not 0xffs.

But I could make it a two step process, where I first override those magic bytes with 0xffs, and then use nand_check_erased_ecc_chunk. That may not reduce tons of code, but would atleast consider possibility of bitflips in erased pages, which the driver currently doesn't do.

Quoted 84 lines

[...]

Quoted 67 lines
drivers/mtd/nand/qcom_nandc.c new file +67 -0
+
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage, spare_bytes, bbm_size, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			spare_bytes = 0;
+			bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			spare_bytes = 2;
+			bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				spare_bytes = 2;
+				bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				spare_bytes = 4;
+				bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				spare_bytes = 0;
+				bbm_size = 2;
+			} else {
+				spare_bytes = 1;
+				bbm_size = 1;
+			}

drivers/mtd/nand/qcom_nandc.c line 1609

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + spare_bytes + bbm_size;

You should add the following check:

Quoted 5 lines
	if (ecc->bytes * (mtd->writesize / ecc->size) < mtd->oobsize) {
		dev_err(nandc->dev, "ecc data do not fit in OOB
	area\n");
		return -EINVAL;
	}

Should that be a '>' in the check?

Quoted 165 lines
Quoted 80 lines
drivers/mtd/nand/qcom_nandc.c new file +79 -0
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	ecc->mode = NAND_ECC_HW;
+
+	ecc->layout = qcom_nand_create_layout(host);
+	if (!ecc->layout)
+		return -ENOMEM;
+
+	cwperpage = mtd->writesize / ecc->size;
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	host->cw_data = 516;
+
+	/*
+	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+	 * for 8 bit ECC
+	 */
+	host->cw_size = host->cw_data + ecc->bytes;
+
+	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| spare_bytes << SPARE_SIZE_BYTES;
+
+	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| host->bch_enabled << ENABLE_BCH_ECC;
+
+	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| host->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	host->clrflashstatus = FS_READY_BSY_N;
+	host->clrreadstatus = 0xc0;
+
+	dev_dbg(nandc->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+		cwperpage);
+
+	return 0;
+}

[...]

Quoted 82 lines
drivers/mtd/nand/qcom_nandc.c new file +82 -0
+
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc;
+	const void *dev_data;
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	int ret;
+
+	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+	if (!nandc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, nandc);
+	nandc->dev = dev;
+
+	dev_data = of_device_get_match_data(dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	nandc->ecc_modes = (unsigned long) dev_data;
+
+	nandc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nandc->base = devm_ioremap_resource(dev, nandc->res);
+	if (IS_ERR(nandc->base))
+		return PTR_ERR(nandc->base);
+
+	nandc->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(nandc->core_clk))
+		return PTR_ERR(nandc->core_clk);
+
+	nandc->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(nandc->aon_clk))
+		return PTR_ERR(nandc->aon_clk);
+
+	ret = qcom_nandc_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(nandc->core_clk);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->aon_clk);
+	if (ret)
+		goto err_aon_clk;
+
+	ret = qcom_nandc_setup(nandc);
+	if (ret)
+		goto err_setup;
+
+	for_each_available_child_of_node(dn, child) {
+		if (of_device_is_compatible(child, "qcom,nandcs")) {
+			struct qcom_nand_host *host;
+
+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+			if (!host) {
+				of_node_put(child);
+				ret = -ENOMEM;
+				goto err_setup;
+			}
+
+			host->nandc = nandc;
+			ret = qcom_nand_host_init(host, child);
+			if (ret) {
+				devm_kfree(dev, host);
+				continue;
+			}
+
+			list_add_tail(&host->node, &nandc->host_list);
+		}
+	}
+
+	if (list_empty(&nandc->host_list)) {
+		ret = -ENODEV;
+		goto err_setup;
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1929

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+	}
+
+	return 0;
+
+err_setup:

You should also release the nand devices that may have been registered in the above loop.

Ah, right. I'll fix this.

Quoted 48 lines
Quoted 48 lines
drivers/mtd/nand/qcom_nandc.c new file +47 -0
+	clk_disable_unprepare(nandc->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(nandc->core_clk);
+err_core_clk:
+	qcom_nandc_unalloc(nandc);
+
+	return ret;
+}
+
+static int qcom_nandc_remove(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+	struct qcom_nand_host *host;
+
+	list_for_each_entry(host, &nandc->host_list, node)
+		nand_release(nand_to_mtd(&host->chip));
+
+	qcom_nandc_unalloc(nandc);
+
+	clk_disable_unprepare(nandc->aon_clk);
+	clk_disable_unprepare(nandc->core_clk);
+
+	return 0;
+}
+
+#define EBI2_NANDC_ECC_MODES	(ECC_RS_4BIT | ECC_BCH_8BIT)
+
+/*
+ * data will hold a struct pointer containing more differences once we support
+ * more controller variants
+ */
+static const struct of_device_id qcom_nandc_of_match[] = {
+	{	.compatible = "qcom,ebi2-nandc",
+		.data = (void *) EBI2_NANDC_ECC_MODES,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
+
+static struct platform_driver qcom_nandc_driver = {
+	.driver = {
+		.name = "qcom-nandc",
+		.of_match_table = qcom_nandc_of_match,
+	},
+	.probe   = qcom_nandc_probe,
+	.remove  = qcom_nandc_remove,
+};
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1981

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+module_platform_driver(qcom_nandc_driver);
+
+MODULE_AUTHOR("Archit Taneja <[email protected]>");
+MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
+MODULE_LICENSE("GPL v2");

Thanks for the rework you've done on the other parts of the code.

Thanks for the follow up review.

Archit

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#78 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 124 lines · On Fri, 8 Jan 2016 12:03:25 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 121 lines · Boris Brezillon

Hi Archit,

Quoted 116 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 1989 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
  	help
  	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
  endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
  obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
  obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
  obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
  nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..a4dd922

[...]

Quoted 75 lines
Quoted 66 lines
Quoted 66 lines
drivers/mtd/nand/qcom_nandc.c new file +65 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 986

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

Quoted 7 lines

We wouldn't be able to use nand_check_erased_ecc_chunk directly because there are certain bytes in each chunk that are intentionally not 0xffs.

But I could make it a two step process, where I first override those magic bytes with 0xffs, and then use nand_check_erased_ecc_chunk. That may not reduce tons of code, but would atleast consider possibility of bitflips in erased pages, which the driver currently doesn't do.

Too bad your ECC engines decides to fix some bits even when it cannot fix all of them. Are you sure there's no flag to disable this behavior? Usually ECC engines just flag the data chunk as uncorrectable and leave its data untouched.

Anyway, are you sure your heuristic to detect erased pages is 100% sure. What if you really have a lot of bitflips but the values @3 and @175 are still 0x54 and 0xff because those are the bitflips the engine decided to fix?

Actually, I don't know if you have any other option but to re-read the page in raw mode and use nand_check_erased_ecc_chunk(). It adds a considerable overhead, but at least you're sure to detect real empty pages without any false positive.

Quoted 85 lines
Quoted 85 lines

[...]

Quoted 67 lines
drivers/mtd/nand/qcom_nandc.c new file +67 -0
+
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage, spare_bytes, bbm_size, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			spare_bytes = 0;
+			bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			spare_bytes = 2;
+			bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				spare_bytes = 2;
+				bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				spare_bytes = 4;
+				bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				spare_bytes = 0;
+				bbm_size = 2;
+			} else {
+				spare_bytes = 1;
+				bbm_size = 1;
+			}

drivers/mtd/nand/qcom_nandc.c line 1609

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + spare_bytes + bbm_size;

You should add the following check:

Quoted 8 lines
Quoted 5 lines
	if (ecc->bytes * (mtd->writesize / ecc->size) < mtd->oobsize) {
		dev_err(nandc->dev, "ecc data do not fit in OOB
	area\n");
		return -EINVAL;
	}

Should that be a '>' in the check?

Absolutely.

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#79 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 213 lines · Boris Brezillon
Quoted 124 lines · On Fri, 8 Jan 2016 12:03:25 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 121 lines · Boris Brezillon

Hi Archit,

Quoted 116 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

   drivers/mtd/nand/Kconfig      |    7 +
   drivers/mtd/nand/Makefile     |    1 +
   drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
   3 files changed, 1989 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
   	help
   	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
   endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
   obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
   obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
   obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
   nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..a4dd922

[...]

Quoted 75 lines
Quoted 66 lines
Quoted 66 lines
drivers/mtd/nand/qcom_nandc.c new file +65 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 986

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

Quoted 7 lines

We wouldn't be able to use nand_check_erased_ecc_chunk directly because there are certain bytes in each chunk that are intentionally not 0xffs.

But I could make it a two step process, where I first override those magic bytes with 0xffs, and then use nand_check_erased_ecc_chunk. That may not reduce tons of code, but would atleast consider possibility of bitflips in erased pages, which the driver currently doesn't do.

Quoted 4 lines

Too bad your ECC engines decides to fix some bits even when it cannot fix all of them. Are you sure there's no flag to disable this behavior? Usually ECC engines just flag the data chunk as uncorrectable and leave its data untouched.

I don't think the engine is actually writing to the chunk at any point when reading an erased chunk.

This whole method adopted by the engine is just a way of flagging to us that it read an erased chunk. Once it reads an erased chunk, it flags an error in one of the controller registers, and replaces offsets at 3 and 175 in its internal buffer.

I am not sure why the HW didn't just provide another bit field which notifies that it it read an erased page. This is what is done in the future version of this controller, and we don't need to any of this stuff.

I don't think this behaviour can be disabled as such.

Quoted 5 lines

Anyway, are you sure your heuristic to detect erased pages is 100% sure. What if you really have a lot of bitflips but the values @3 and @175 are still 0x54 and 0xff because those are the bitflips the engine decided to fix?

As pointed above, I don't think 0x54 and 0xff are explicitly written to the nand flash chip.

Quoted 5 lines

Actually, I don't know if you have any other option but to re-read the page in raw mode and use nand_check_erased_ecc_chunk(). It adds a considerable overhead, but at least you're sure to detect real empty pages without any false positive.

I am not sure why this is needed. The driver code does parse the entire page and reports that it isn't an erased page if all of them (apart from the given offsets) weren't 0xffs.

Thanks,
Archit

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#80 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 229 lines · On Fri, 8 Jan 2016 15:53:43 +0530 Archit Taneja <[email protected]> wrote:
Quoted 213 lines · Boris Brezillon
Quoted 124 lines · On Fri, 8 Jan 2016 12:03:25 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 121 lines · Boris Brezillon

Hi Archit,

Quoted 116 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

   drivers/mtd/nand/Kconfig      |    7 +
   drivers/mtd/nand/Makefile     |    1 +
   drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++
   3 files changed, 1989 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
   	help
   	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
   endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
   obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
   obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
   obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
   nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..a4dd922

[...]

Quoted 75 lines
Quoted 66 lines
Quoted 66 lines
drivers/mtd/nand/qcom_nandc.c new file +65 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 986

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

Quoted 7 lines

We wouldn't be able to use nand_check_erased_ecc_chunk directly because there are certain bytes in each chunk that are intentionally not 0xffs.

But I could make it a two step process, where I first override those magic bytes with 0xffs, and then use nand_check_erased_ecc_chunk. That may not reduce tons of code, but would atleast consider possibility of bitflips in erased pages, which the driver currently doesn't do.

Quoted 4 lines

Too bad your ECC engines decides to fix some bits even when it cannot fix all of them. Are you sure there's no flag to disable this behavior? Usually ECC engines just flag the data chunk as uncorrectable and leave its data untouched.

I don't think the engine is actually writing to the chunk at any point when reading an erased chunk.

This whole method adopted by the engine is just a way of flagging to us that it read an erased chunk. Once it reads an erased chunk, it flags an error in one of the controller registers, and replaces offsets at 3 and 175 in its internal buffer.

Quoted 4 lines

I am not sure why the HW didn't just provide another bit field which notifies that it it read an erased page. This is what is done in the future version of this controller, and we don't need to any of this stuff.

Ok, if that's really the case, and those pattern are just a way to notify the software that it has detected an empty page, then I'm fine with this implementation.
Just add an extra nand_check_erased_ecc_chunk() call (as you suggested) if this function returns false, so that you can handle bitflips in erased pages.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#81 lore raw

Re: [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 237 lines · Boris Brezillon
Quoted 229 lines · On Fri, 8 Jan 2016 15:53:43 +0530 Archit Taneja <[email protected]> wrote:
Quoted 213 lines · Boris Brezillon
Quoted 124 lines · On Fri, 8 Jan 2016 12:03:25 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 121 lines · Boris Brezillon

Hi Archit,

Quoted 116 lines · On Tue, 5 Jan 2016 10:55:00 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/qcom_nandc.c | 1981 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1989 insertions(+)
create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
    	help
    	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
    endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
    obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
    obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
    obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
    nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..a4dd922

[...]

Quoted 75 lines
Quoted 66 lines
Quoted 66 lines
drivers/mtd/nand/qcom_nandc.c new file +65 -0
+
+/*
+ * when using RS ECC, the NAND controller flags an error when reading an
+ * erased page. however, there are special characters at certain offsets when
+ * we read the erased page. we check here if the page is really empty. if so,
+ * we replace the magic characters with 0xffs
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage = chip->ecc.steps;
+	u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
+	int i, j;
+
+	/* if BCH is enabled, HW will take care of detecting erased pages */
+	if (host->bch_enabled || !host->use_ecc)
+		return false;
+
+	for (i = 0; i < cwperpage; i++) {
+		u8 *empty1, *empty2;
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[3 * i]);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, check if
+		 * the page is erased by looking for 0x54s at offsets 3 and 175
+		 * from the beginning of each codeword
+		 */
+		if (!(flash_status & FS_OP_ERR))
+			break;
+
+		empty1 = &data_buf[3 + i * host->cw_data];
+		empty2 = &data_buf[175 + i * host->cw_data];
+
+		/*
+		 * if the error wasn't because of an erased page, bail out and
+		 * and let someone else do the error checking
+		 */
+		if ((*empty1 == 0x54 && *empty2 == 0xff) ||
+				(*empty1 == 0xff && *empty2 == 0x54)) {
+			orig1[i] = *empty1;
+			orig2[i] = *empty2;
+
+			*empty1 = 0xff;
+			*empty2 = 0xff;
+		} else {
+			break;
+		}
+	}
+
+	if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
+		goto not_empty;
+
+	/*
+	 * tell the caller that the page was empty and is fixed up, so that
+	 * parse_read_errors() doesn't think it's an error
+	 */
+	return true;
+
+not_empty:
+	/* restore original values if not empty*/
+	for (j = 0; j < i; j++) {
+		data_buf[3 + j * host->cw_data] = orig1[j];
+		data_buf[175 + j * host->cw_data] = orig2[j];
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 986

Quoted 4 lines
drivers/mtd/nand/qcom_nandc.c new file +4 -0
+	}
+
+	return false;
+}

This empty page detection seems a bit complicated to me. Could you consider using nand_check_erased_ecc_chunk() to check is the chunk is containing 0xff data instead of implementing your own logic?

Quoted 7 lines

We wouldn't be able to use nand_check_erased_ecc_chunk directly because there are certain bytes in each chunk that are intentionally not 0xffs.

But I could make it a two step process, where I first override those magic bytes with 0xffs, and then use nand_check_erased_ecc_chunk. That may not reduce tons of code, but would atleast consider possibility of bitflips in erased pages, which the driver currently doesn't do.

Quoted 4 lines

Too bad your ECC engines decides to fix some bits even when it cannot fix all of them. Are you sure there's no flag to disable this behavior? Usually ECC engines just flag the data chunk as uncorrectable and leave its data untouched.

I don't think the engine is actually writing to the chunk at any point when reading an erased chunk.

This whole method adopted by the engine is just a way of flagging to us that it read an erased chunk. Once it reads an erased chunk, it flags an error in one of the controller registers, and replaces offsets at 3 and 175 in its internal buffer.

Quoted 4 lines

I am not sure why the HW didn't just provide another bit field which notifies that it it read an erased page. This is what is done in the future version of this controller, and we don't need to any of this stuff.

Quoted 6 lines

Ok, if that's really the case, and those pattern are just a way to notify the software that it has detected an empty page, then I'm fine with this implementation.
Just add an extra nand_check_erased_ecc_chunk() call (as you suggested) if this function returns false, so that you can handle bitflips in erased pages.

I just checked the documentation. The engine doesn't try to do ecc correction for erased pages.

About the strange pattern notification thing, there seems to be a feature to auto-check for an erased page rather than using patterns, but I'm hesitant to try that as the downstream drivers don't
use it for this controller, and only use it for future revisions.

I will use the nand helper instead of the rudimentary memchr_inv check

Thanks,
Archit

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#82 lore raw

PATCH v5 3/3 dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +84 -0
new file mode 100644
index 0000000..b2cf2d9
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits.
+- nand-ecc-step-size:	bytes of data per ECC step. Must be 512.
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "boot-nand";
+			reg = <0 0x58a0000>;
+		};
+
+		partition@58a0000 {
+			label = "fs-nand";
+			reg = <0x58a0000 0x4000000>;
+		};
+	};
+};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Reviewed-by on v5 3/3
#83 lore raw

Re: [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings

Hi Archit,

Quoted 54 lines · On Tue, 5 Jan 2016 10:55:01 +0530 Archit Taneja <[email protected]> wrote:

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +30 -0
new file mode 100644
index 0000000..b2cf2d9
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 40

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits.
+- nand-ecc-step-size:	bytes of data per ECC step. Must be 512.
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default

You should probably reference Documentation/devicetree/bindings/mtd/nand.txt which is documenting generic nand-xxx properties.

Quoted 20 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +20 -0
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 70

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+

It's now recommended to define a 'partitions' subnode to store those partition nodes.

Quoted 4 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +4 -0
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 84

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+			label = "boot-nand";
+			reg = <0 0x58a0000>;
+		};
+
+		partition@58a0000 {
+			label = "fs-nand";
+			reg = <0x58a0000 0x4000000>;
+		};
+	};
+};

The rest looks good to me.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
maintainer
#84 lore raw

Re: [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja
Quoted 24 lines · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +0 -0
new file mode 100644
index 0000000..b2cf2d9

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 4

Quoted 4 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +4 -0
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x

More specific name please.

Quoted 29 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +29 -0
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 43

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits.
+- nand-ecc-step-size:	bytes of data per ECC step. Must be 512.
+
+Optional properties:
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.

Can't the partitioning span across chip selects? After all, interleaving is how you get high performance.

Rob

#85 lore raw

Re: [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings

Quoted 66 lines · On Wed, 6 Jan 2016 09:14:44 -0600 Rob Herring <[email protected]> wrote:
Quoted 24 lines · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +0 -0
new file mode 100644
index 0000000..b2cf2d9

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 4

Quoted 4 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +4 -0
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ebi2-nand" for IPQ806x

More specific name please.

Quoted 34 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +34 -0
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	number of bits to correct per ECC step. Must be 4 or 8
+			bits.
+- nand-ecc-step-size:	bytes of data per ECC step. Must be 512.
+
+Optional properties:
Quoted 8 lines

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 43

Quoted 5 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +5 -0
+- nand-bus-width:	bus width. Must be 8 or 16. If not present, 8 is chosen
+			as default
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.

Can't the partitioning span across chip selects? After all, interleaving is how you get high performance.

Hm, defining aggregated mtd devices in the DT is not supported, and since, as I've been told many times ;), DT is supposed to represent the HW not what we want to do with it, I'm not sure that's such a good idea.

Note that the infrastructure to concatenate several MTD devices already exists, but it's not used by the NAND layer.

Also note that some NAND chips embed several dies and expose multiple CS lines. The NAND framework already supports assigning different CS lines to a single NAND device, so you could abuse this feature and expose your different NAND devices as a single one (that will only work for a cluster of identical chips connected to the same controller), but I'd really like to avoid this kind of things.

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
maintainer
#86 lore raw

Re: [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings

Quoted 78 lines · Boris Brezillon
Quoted 66 lines · On Wed, 6 Jan 2016 09:14:44 -0600 Rob Herring <[email protected]> wrote:
Quoted 24 lines · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +0 -0
new file mode 100644
index 0000000..b2cf2d9

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 4

Quoted 4 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +4 -0
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:              should be "qcom,ebi2-nand" for IPQ806x

More specific name please.

Quoted 34 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +34 -0
+- reg:                     MMIO address range
+- clocks:          must contain core clock and always on clock
+- clock-names:             must contain "core" for the core clock and "aon" for the
+                   always on clock
+- dmas:                    DMA specifier, consisting of a phandle to the ADM DMA
+                   controller node and the channel number to be used for
+                   NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:               must be "rxtx"
+- qcom,cmd-crci:   must contain the ADM command type CRCI block instance
+                   number specified for the NAND controller on the given
+                   platform
+- qcom,data-crci:  must contain the ADM data type CRCI block instance
+                   number specified for the NAND controller on the given
+                   platform
+- #address-cells:  <1> - subnodes give the chip-select number
+- #size-cells:             <0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:              should contain "qcom,nandcs"
+- reg:                     a single integer representing the chip-select
+                   number (e.g., 0, 1, 2, etc.)
+- #address-cells:  see partition.txt
+- #size-cells:             see partition.txt
+- nand-ecc-strength:       number of bits to correct per ECC step. Must be 4 or 8
+                   bits.
+- nand-ecc-step-size:      bytes of data per ECC step. Must be 512.
+
+Optional properties:
Quoted 8 lines

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 43

Quoted 5 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +5 -0
+- nand-bus-width:  bus width. Must be 8 or 16. If not present, 8 is chosen
+                   as default
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.

Can't the partitioning span across chip selects? After all, interleaving is how you get high performance.

Quoted 3 lines

Hm, defining aggregated mtd devices in the DT is not supported, and since, as I've been told many times ;), DT is supposed to represent the HW not what we want to do with it, I'm not sure that's such a good idea.

What are partitions then?

Quoted 9 lines

Note that the infrastructure to concatenate several MTD devices already exists, but it's not used by the NAND layer.

Also note that some NAND chips embed several dies and expose multiple CS lines. The NAND framework already supports assigning different CS lines to a single NAND device, so you could abuse this feature and expose your different NAND devices as a single one (that will only work for a cluster of identical chips connected to the same controller), but I'd really like to avoid this kind of things.

What exactly the kernel supports ATM is irrelevant. I'm fully aware that the kernel's NAND support has huge gaps in its ability to support raw NAND at typical SSD speeds. My last employer had delusions about doing that. Fortunately, NAND manufacturers don't really want to sell you raw NAND anyway.

My point here was only that the partitions node may not be under the CS nodes, but at the same level. Or maybe partitions in DT just doesn't make sense at all for interleaved cases.

Rob

#87 lore raw

Re: [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings

Quoted 80 lines · On Wed, 6 Jan 2016 10:13:57 -0600 Rob Herring <[email protected]> wrote:
Quoted 78 lines · Boris Brezillon
Quoted 74 lines · On Wed, 6 Jan 2016 09:14:44 -0600 Rob Herring <[email protected]> wrote:
Quoted 24 lines · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +0 -0
new file mode 100644
index 0000000..b2cf2d9

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 4

Quoted 4 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +4 -0
@@ -0,0 +1,84 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:              should be "qcom,ebi2-nand" for IPQ806x

More specific name please.

Quoted 29 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +29 -0
+- reg:                     MMIO address range
+- clocks:          must contain core clock and always on clock
+- clock-names:             must contain "core" for the core clock and "aon" for the
+                   always on clock
+- dmas:                    DMA specifier, consisting of a phandle to the ADM DMA
+                   controller node and the channel number to be used for
+                   NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:               must be "rxtx"
+- qcom,cmd-crci:   must contain the ADM command type CRCI block instance
+                   number specified for the NAND controller on the given
+                   platform
+- qcom,data-crci:  must contain the ADM data type CRCI block instance
+                   number specified for the NAND controller on the given
+                   platform
+- #address-cells:  <1> - subnodes give the chip-select number
+- #size-cells:             <0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:              should contain "qcom,nandcs"
+- reg:                     a single integer representing the chip-select
+                   number (e.g., 0, 1, 2, etc.)
+- #address-cells:  see partition.txt
+- #size-cells:             see partition.txt

Documentation/devicetree/bindings/mtd/qcom_nandc.txt line 43

Quoted 10 lines
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +10 -0
+- nand-ecc-strength:       number of bits to correct per ECC step. Must be 4 or 8
+                   bits.
+- nand-ecc-step-size:      bytes of data per ECC step. Must be 512.
+
+Optional properties:
+- nand-bus-width:  bus width. Must be 8 or 16. If not present, 8 is chosen
+                   as default
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.

Can't the partitioning span across chip selects? After all, interleaving is how you get high performance.

Quoted 5 lines
Quoted 3 lines

Hm, defining aggregated mtd devices in the DT is not supported, and since, as I've been told many times ;), DT is supposed to represent the HW not what we want to do with it, I'm not sure that's such a good idea.

What are partitions then?

It's definitely not describing the hardware, and I never said describing partitions in the DT was following the number one rule:
"only describe your HW" ;-).
I'm generally not in favor of this kind of restrictions, I'm just pointing the irony of the situation here :p.

Quoted 17 lines
Quoted 10 lines

Note that the infrastructure to concatenate several MTD devices already exists, but it's not used by the NAND layer.

Also note that some NAND chips embed several dies and expose multiple CS lines. The NAND framework already supports assigning different CS lines to a single NAND device, so you could abuse this feature and expose your different NAND devices as a single one (that will only work for a cluster of identical chips connected to the same controller), but I'd really like to avoid this kind of things.

What exactly the kernel supports ATM is irrelevant. I'm fully aware that the kernel's NAND support has huge gaps in its ability to support raw NAND at typical SSD speeds. My last employer had delusions about doing that. Fortunately, NAND manufacturers don't really want to sell you raw NAND anyway.

Quoted 3 lines

My point here was only that the partitions node may not be under the CS nodes, but at the same level. Or maybe partitions in DT just doesn't make sense at all for interleaved cases.

IMHO, if we had to support this aggregation feature, the NAND cluster should be represented using a different node, outside of the nand controller node.
Theoretically, you can perfectly have several NAND chips connected to different NAND controllers, but still want to aggregate those chips into a single entity.

Anyway, that's not the topic here, and since other bindings are already describing partitions under the nand device node and not the nand controller node, I think we can keep doing like this until we find a better solution.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#88 lore raw

v6 cover mtd: Qualcomm NAND controller driver

In reply to Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

The first patch in the series contains a nand_base clean up which the driver will utilize.

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

v6:
- Fix erased page parsing as suggested by Borris.
- Change compatible string to something more legible.
- Whitespace fixes.

v5:
- Skip creation of BBT as in v1. Will bring this back after BBMs are read/written in raw mode (using badblockbits support).
- Incorporated misc fixes/suggestions by Boris.
- Dropped the DT patches for now, since ADM DMA support isn't merged yet.

v4:
- Some more fixes. Mentioned in individual patch

v3:
- Various fixes and clean ups suggested by Stephen Boyd.

v2:
- Added a new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

v1:
- original series:
https://lkml.org/lkml/2015/1/16/317

Archit Taneja (3):
mtd: nand: don't select chip in nand_chip's block_bad op
mtd: nand: Qualcomm NAND controller driver dt/bindings: qcom_nandc: Add DT bindings

 .../devicetree/bindings/mtd/qcom_nandc.txt         |   86 +
 drivers/mtd/nand/Kconfig                           |    7 +
 drivers/mtd/nand/Makefile                          |    1 +
 drivers/mtd/nand/nand_base.c                       |   41 +-
 drivers/mtd/nand/qcom_nandc.c                      | 2013 ++++++++++++++++++++
 include/linux/mtd/nand.h                           |    2 +-
 6 files changed, 2127 insertions(+), 23 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#89 lore raw

PATCH v6 1/3 mtd: nand: don't select chip in nand_chip's block_bad op

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

---
v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

 drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++----------------------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 20 insertions(+), 23 deletions(-)
drivers/mtd/nand/nand_base.c +19 -22
index 928081b..1809c20 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-	int page, chipnr, res = 0, i = 0;
+	int page, res = 0, i = 0;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	u16 bad;
 
@@ -328,15 +328,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
-
 	do {
 		if (chip->options & NAND_BUSWIDTH_16) {
 			chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +352,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 		i++;
 	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-	if (getchip) {
-		chip->select_chip(mtd, -1);
-		nand_release_device(mtd);
-	}
-
 	return res;
 }
 
@@ -503,19 +489,17 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
  * @mtd: MTD device structure
  * @ofs: offset from device start
- * @getchip: 0, if the chip is already selected
  * @allowbbt: 1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
-			       int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
 	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+		return chip->block_bad(mtd, ofs);
 
 	/* Return info from the table */
 	return nand_isbad_bbt(mtd, ofs, allowbbt);
@@ -2918,7 +2902,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 	while (len) {
 		/* Check if we have a bad block, we do not erase bad blocks! */
 		if (nand_block_checkbad(mtd, ((loff_t) page) <<
-					chip->page_shift, 0, allowbbt)) {
+					chip->page_shift, allowbbt)) {
 			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
 				    __func__, page);
 			instr->state = MTD_ERASE_FAILED;
@@ -3005,7 +2989,20 @@ static void nand_sync(struct mtd_info *mtd)
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-	return nand_block_checkbad(mtd, offs, 1, 0);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int chipnr = (int)(offs >> chip->chip_shift);
+	int ret;
+
+	/* Select the NAND device */
+	nand_get_device(mtd, FL_READING);
+	chip->select_chip(mtd, chipnr);
+
+	ret = nand_block_checkbad(mtd, offs, 0);
+
+	chip->select_chip(mtd, -1);
+	nand_release_device(mtd);
+
+	return ret;
 }
 
 /**
include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#90 lore raw

Re: [PATCH v6 1/3] mtd: nand: don't select chip in nand_chip's block_bad op

Hi Archit,

Quoted 29 lines · On Mon, 18 Jan 2016 15:20:32 +0530 Archit Taneja <[email protected]> wrote:

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

---
v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

 drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++----------------------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 20 insertions(+), 23 deletions(-)
drivers/mtd/nand/nand_base.c +0 -0
index 928081b..1809c20 100644

drivers/mtd/nand/nand_base.c static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) · line 320

Quoted 5 lines
drivers/mtd/nand/nand_base.c +1 -1
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)

You also have to update the dummy ->block_bad() implementations in the cafe_nand, diskonchip and docg4 drivers.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#91 lore raw

Re: [PATCH v6 1/3] mtd: nand: don't select chip in nand_chip's block_bad op

Quoted 29 lines · Boris Brezillon

Hi Archit,

Quoted 24 lines · On Mon, 18 Jan 2016 15:20:32 +0530 Archit Taneja <[email protected]> wrote:

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

---
v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

  drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++----------------------
  include/linux/mtd/nand.h     |  2 +-
  2 files changed, 20 insertions(+), 23 deletions(-)
Quoted 13 lines

drivers/mtd/nand/nand_base.c static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) · line 320

Quoted 10 lines
drivers/mtd/nand/nand_base.c +1 -1
index 928081b..1809c20 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
   *
   * Check, if the block is bad.
   */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)

You also have to update the dummy ->block_bad() implementations in the cafe_nand, diskonchip and docg4 drivers.

Ah, I totally missed that. Will update and send.

Thanks,
Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#92 lore raw

PATCH v6 2/3 mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2013 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2021 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +2013 -0

2,013 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#93 lore raw

Re: [PATCH v6 2/3] mtd: nand: Qualcomm NAND controller driver

Hi Archit,

I noticed a few things I didn't report in my previous review (sorry about that), and there's two comments from my previous review you didn't address (maybe you have a good reason :)).

Quoted 121 lines · On Mon, 18 Jan 2016 15:20:33 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2013 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2021 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..cc1e7fa

[...]

Quoted 30 lines
drivers/mtd/nand/qcom_nandc.c new file +30 -0
+/*
+ * NAND controller data struct
+ *
+ * @controller:			base controller structure
+ * @host_list:			list containing all the chips attached to the
+ *				controller
+ * @dev:			parent device
+ * @res:			resource pointer for platform device (used to
+ *				retrieve the physical addresses of registers
+ *				for DMA)
+ * @base:			MMIO base
+ * @core_clk:			controller clock
+ * @aon_clk:			another controller clock
+ *
+ * @chan:			dma channel
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @desc_list:			DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		local buffer for reading back registers via DMA
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ *
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes. contains the register values to be
+ *				written to controller
+ * @cmd1/vld:			some fixed controller register values

drivers/mtd/nand/qcom_nandc.c line 247

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+ * @ecc_modes:			supported ECC modes by the current controller,
+ *				initialized via DT match data
+ */
+struct qcom_nand_controller {
+	struct nand_hw_control controller;
+	struct list_head host_list;
+
+	struct device *dev;
+
+	struct resource *res;

Hm, ->res is only used to get the physical address for your DMA operations, so maybe you should replace it by:

	dma_addr_t base_dma;

and initialize it to phys_to_dma(dev, (phys_addr_t)res->start) in your probe function.

Quoted 45 lines
drivers/mtd/nand/qcom_nandc.c new file +45 -0
+	void __iomem *base;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;
+
+	struct dma_chan *chan;
+	unsigned int cmd_crci;
+	unsigned int data_crci;
+	struct list_head desc_list;
+
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;
+
+	__le32 *reg_read_buf;
+	int reg_read_pos;
+
+	struct nandc_regs *regs;
+
+	u32 cmd1, vld;
+	u32 ecc_modes;
+};
+
+/*
+ * NAND chip structure
+ *
+ * @nandc:			nand controller to which the chip is connected
+ *
+ * @chip:			base NAND chip structure
+ * @node:			list node to add itself to host_list in
+ *				qcom_nand_controller
+ *
+ * @cs:				chip select value for this chip
+ * @cw_size:			the number of bytes in a single step/codeword
+ *				of a page, consisting of all data, ecc, spare
+ *				and reserved bytes
+ * @cw_data:			the number of bytes within a codeword protected
+ *				by ECC
+ * @use_ecc:			request the controller to use ECC for the
+ *				upcoming read/write
+ * @bch_enabled:		flag to tell whether BCH ECC mode is used
+ * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
+ *				chip
+ * @status:			value to be returned if NAND_CMD_STATUS command

drivers/mtd/nand/qcom_nandc.c line 302

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+ *				is executed
+ * @last_command:		keeps track of last command on this chip. used
+ *				for reading correct status
+ *
+ * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
+ *				ecc/non-ecc mode for the current nand flash
+ *				device
+ */
+struct qcom_nand_host {
+	struct qcom_nand_controller *nandc;

You don't need this field, it can be extracted from chip->controller:

struct qcom_nand_controller *
get_qcom_nand_controller(struct nand_chip *chip)

{
	return container_of(chip->controller,
			    struct qcom_nand_controller,
			    controller);
}
Quoted 20 lines
drivers/mtd/nand/qcom_nandc.c new file +20 -0
+
+	struct nand_chip chip;
+	struct list_head node;
+
+	int cs;
+	int cw_size;
+	int cw_data;
+	bool use_ecc;
+	bool bch_enabled;
+	int ecc_bytes_hw;
+	u8 status;
+	int last_command;
+
+	u32 cfg0, cfg1;
+	u32 cfg0_raw, cfg1_raw;
+	u32 ecc_buf_cfg;
+	u32 ecc_bch_cfg;
+	u32 clrflashstatus;
+	u32 clrreadstatus;
+};

[...]

Quoted 66 lines
drivers/mtd/nand/qcom_nandc.c new file +66 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage, spare_bytes, bbm_size, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			spare_bytes = 0;
+			bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			spare_bytes = 2;
+			bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				spare_bytes = 2;
+				bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				spare_bytes = 4;
+				bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				spare_bytes = 0;
+				bbm_size = 2;
+			} else {
+				spare_bytes = 1;
+				bbm_size = 1;
+			}

drivers/mtd/nand/qcom_nandc.c line 1641

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + spare_bytes + bbm_size;

You're still not checking if (ecc->bytes * nsteps) can fit in the OOB area...

Quoted 79 lines
drivers/mtd/nand/qcom_nandc.c new file +79 -0
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	ecc->mode = NAND_ECC_HW;
+
+	ecc->layout = qcom_nand_create_layout(host);
+	if (!ecc->layout)
+		return -ENOMEM;
+
+	cwperpage = mtd->writesize / ecc->size;
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	host->cw_data = 516;
+
+	/*
+	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+	 * for 8 bit ECC
+	 */
+	host->cw_size = host->cw_data + ecc->bytes;
+
+	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| spare_bytes << SPARE_SIZE_BYTES;
+
+	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| host->bch_enabled << ENABLE_BCH_ECC;
+
+	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| host->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	host->clrflashstatus = FS_READY_BSY_N;
+	host->clrreadstatus = 0xc0;
+
+	dev_dbg(nandc->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+		cwperpage);
+
+	return 0;
+}

[...]

Quoted 76 lines
drivers/mtd/nand/qcom_nandc.c new file +76 -0
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc;
+	const void *dev_data;
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	int ret;
+
+	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+	if (!nandc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, nandc);
+	nandc->dev = dev;
+
+	dev_data = of_device_get_match_data(dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	nandc->ecc_modes = (unsigned long) dev_data;
+
+	nandc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nandc->base = devm_ioremap_resource(dev, nandc->res);
+	if (IS_ERR(nandc->base))
+		return PTR_ERR(nandc->base);
+
+	nandc->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(nandc->core_clk))
+		return PTR_ERR(nandc->core_clk);
+
+	nandc->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(nandc->aon_clk))
+		return PTR_ERR(nandc->aon_clk);
+
+	ret = qcom_nandc_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(nandc->core_clk);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->aon_clk);
+	if (ret)
+		goto err_aon_clk;
+
+	ret = qcom_nandc_setup(nandc);
+	if (ret)
+		goto err_setup;
+
+	for_each_available_child_of_node(dn, child) {
+		if (of_device_is_compatible(child, "qcom,nandcs")) {
+			struct qcom_nand_host *host;
+
+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+			if (!host) {
+				of_node_put(child);
+				ret = -ENOMEM;
+				goto err_setup;
+			}
+
+			host->nandc = nandc;
+			ret = qcom_nand_host_init(host, child);
+			if (ret) {
+				devm_kfree(dev, host);
+				continue;
+			}
+
+			list_add_tail(&host->node, &nandc->host_list);
+		}

drivers/mtd/nand/qcom_nandc.c line 1961

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	}
+
+	if (list_empty(&nandc->host_list)) {
+		ret = -ENODEV;
+		goto err_setup;
+	}
+
+	return 0;
+
+err_setup:

... and here, you're not unregistering the NAND devices:

	list_for_each_entry(host, &nandc->host_list, node)
		nand_release(nand_to_mtd(&host->chip));

drivers/mtd/nand/qcom_nandc.c line 1969

Quoted 8 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+	clk_disable_unprepare(nandc->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(nandc->core_clk);
+err_core_clk:
+	qcom_nandc_unalloc(nandc);
+
+	return ret;
+}

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#94 lore raw

Re: [PATCH v6 2/3] mtd: nand: Qualcomm NAND controller driver

Hi Boris,

Quoted 5 lines · Boris Brezillon

Hi Archit,

I noticed a few things I didn't report in my previous review (sorry about that), and there's two comments from my previous review you didn't address (maybe you have a good reason :)).

That's totally okay. Sorry about missing out on some of the comments. I focused on incorporating nand_check_erased_ecc_chunk in the correct way, and forgot about the other comments. I'll address them in v7.

Comments below.

Quoted 172 lines
Quoted 121 lines · On Mon, 18 Jan 2016 15:20:33 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2013 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2021 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
  	help
  	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
  endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
  obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
  obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
  obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
  nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..cc1e7fa

[...]

Quoted 30 lines
drivers/mtd/nand/qcom_nandc.c new file +30 -0
+/*
+ * NAND controller data struct
+ *
+ * @controller:			base controller structure
+ * @host_list:			list containing all the chips attached to the
+ *				controller
+ * @dev:			parent device
+ * @res:			resource pointer for platform device (used to
+ *				retrieve the physical addresses of registers
+ *				for DMA)
+ * @base:			MMIO base
+ * @core_clk:			controller clock
+ * @aon_clk:			another controller clock
+ *
+ * @chan:			dma channel
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @desc_list:			DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		local buffer for reading back registers via DMA
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ *
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes. contains the register values to be
+ *				written to controller
+ * @cmd1/vld:			some fixed controller register values

drivers/mtd/nand/qcom_nandc.c line 247

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+ * @ecc_modes:			supported ECC modes by the current controller,
+ *				initialized via DT match data
+ */
+struct qcom_nand_controller {
+	struct nand_hw_control controller;
+	struct list_head host_list;
+
+	struct device *dev;
+
+	struct resource *res;

Hm, ->res is only used to get the physical address for your DMA operations, so maybe you should replace it by:

Quoted 4 lines
	dma_addr_t base_dma;

and initialize it to phys_to_dma(dev, (phys_addr_t)res->start) in your probe function.

That's a good suggestion, I'll use this.

Quoted 59 lines
Quoted 46 lines
drivers/mtd/nand/qcom_nandc.c new file +45 -0
+	void __iomem *base;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;
+
+	struct dma_chan *chan;
+	unsigned int cmd_crci;
+	unsigned int data_crci;
+	struct list_head desc_list;
+
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;
+
+	__le32 *reg_read_buf;
+	int reg_read_pos;
+
+	struct nandc_regs *regs;
+
+	u32 cmd1, vld;
+	u32 ecc_modes;
+};
+
+/*
+ * NAND chip structure
+ *
+ * @nandc:			nand controller to which the chip is connected
+ *
+ * @chip:			base NAND chip structure
+ * @node:			list node to add itself to host_list in
+ *				qcom_nand_controller
+ *
+ * @cs:				chip select value for this chip
+ * @cw_size:			the number of bytes in a single step/codeword
+ *				of a page, consisting of all data, ecc, spare
+ *				and reserved bytes
+ * @cw_data:			the number of bytes within a codeword protected
+ *				by ECC
+ * @use_ecc:			request the controller to use ECC for the
+ *				upcoming read/write
+ * @bch_enabled:		flag to tell whether BCH ECC mode is used
+ * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
+ *				chip
+ * @status:			value to be returned if NAND_CMD_STATUS command

drivers/mtd/nand/qcom_nandc.c line 302

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+ *				is executed
+ * @last_command:		keeps track of last command on this chip. used
+ *				for reading correct status
+ *
+ * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
+ *				ecc/non-ecc mode for the current nand flash
+ *				device
+ */
+struct qcom_nand_host {
+	struct qcom_nand_controller *nandc;

You don't need this field, it can be extracted from chip->controller:

Quoted 7 lines

struct qcom_nand_controller *
get_qcom_nand_controller(struct nand_chip *chip)

{
	return container_of(chip->controller,
			    struct qcom_nand_controller,
			    controller);
}

Right. I'll use this.

Quoted 95 lines
Quoted 21 lines
drivers/mtd/nand/qcom_nandc.c new file +20 -0
+
+	struct nand_chip chip;
+	struct list_head node;
+
+	int cs;
+	int cw_size;
+	int cw_data;
+	bool use_ecc;
+	bool bch_enabled;
+	int ecc_bytes_hw;
+	u8 status;
+	int last_command;
+
+	u32 cfg0, cfg1;
+	u32 cfg0_raw, cfg1_raw;
+	u32 ecc_buf_cfg;
+	u32 ecc_bch_cfg;
+	u32 clrflashstatus;
+	u32 clrreadstatus;
+};

[...]

Quoted 71 lines
drivers/mtd/nand/qcom_nandc.c new file +71 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct qcom_nand_controller *nandc = host->nandc;
+	struct nand_chip *chip = &host->chip;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int cwperpage, spare_bytes, bbm_size, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			spare_bytes = 0;
+			bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			spare_bytes = 2;
+			bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				spare_bytes = 2;
+				bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				spare_bytes = 4;
+				bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				spare_bytes = 0;
+				bbm_size = 2;
+			} else {
+				spare_bytes = 1;
+				bbm_size = 1;
+			}
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1641

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +5 -0
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + spare_bytes + bbm_size;

You're still not checking if (ecc->bytes * nsteps) can fit in the OOB area...

Sorry about this. Will incorporate in v7.

Quoted 172 lines
Quoted 80 lines
drivers/mtd/nand/qcom_nandc.c new file +79 -0
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	ecc->mode = NAND_ECC_HW;
+
+	ecc->layout = qcom_nand_create_layout(host);
+	if (!ecc->layout)
+		return -ENOMEM;
+
+	cwperpage = mtd->writesize / ecc->size;
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	host->cw_data = 516;
+
+	/*
+	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+	 * for 8 bit ECC
+	 */
+	host->cw_size = host->cw_data + ecc->bytes;
+
+	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| spare_bytes << SPARE_SIZE_BYTES;
+
+	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| host->bch_enabled << ENABLE_BCH_ECC;
+
+	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| host->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	host->clrflashstatus = FS_READY_BSY_N;
+	host->clrreadstatus = 0xc0;
+
+	dev_dbg(nandc->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+		cwperpage);
+
+	return 0;
+}

[...]

Quoted 76 lines
drivers/mtd/nand/qcom_nandc.c new file +76 -0
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc;
+	const void *dev_data;
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	int ret;
+
+	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+	if (!nandc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, nandc);
+	nandc->dev = dev;
+
+	dev_data = of_device_get_match_data(dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	nandc->ecc_modes = (unsigned long) dev_data;
+
+	nandc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nandc->base = devm_ioremap_resource(dev, nandc->res);
+	if (IS_ERR(nandc->base))
+		return PTR_ERR(nandc->base);
+
+	nandc->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(nandc->core_clk))
+		return PTR_ERR(nandc->core_clk);
+
+	nandc->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(nandc->aon_clk))
+		return PTR_ERR(nandc->aon_clk);
+
+	ret = qcom_nandc_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(nandc->core_clk);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->aon_clk);
+	if (ret)
+		goto err_aon_clk;
+
+	ret = qcom_nandc_setup(nandc);
+	if (ret)
+		goto err_setup;
+
+	for_each_available_child_of_node(dn, child) {
+		if (of_device_is_compatible(child, "qcom,nandcs")) {
+			struct qcom_nand_host *host;
+
+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+			if (!host) {
+				of_node_put(child);
+				ret = -ENOMEM;
+				goto err_setup;
+			}
+
+			host->nandc = nandc;
+			ret = qcom_nand_host_init(host, child);
+			if (ret) {
+				devm_kfree(dev, host);
+				continue;
+			}
+
+			list_add_tail(&host->node, &nandc->host_list);
+		}

drivers/mtd/nand/qcom_nandc.c line 1961

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	}
+
+	if (list_empty(&nandc->host_list)) {
+		ret = -ENODEV;
+		goto err_setup;
+	}
+
+	return 0;
+
+err_setup:

... and here, you're not unregistering the NAND devices:

Quoted 2 lines
	list_for_each_entry(host, &nandc->host_list, node)
		nand_release(nand_to_mtd(&host->chip));

This too.

Please let me know if you can see any other issues. I'll try to incorporate them in v7 too.

Thanks again for the review!

Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#95 lore raw

PATCH v6 3/3 dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v6:
- Update compatible tring to something more specific
- Refer to nand.txt for standard properties
- In the example, use 'partitions' node to hold the partition subnodes

v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 86 ++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +86 -0
new file mode 100644
index 0000000..70dd511
@@ -0,0 +1,86 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ipq806x-nand"
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	see nand.txt
+- nand-ecc-step-size:	must be 512. see nand.txt for more details.
+
+Optional properties:
+- nand-bus-width:	see nand.txt
+
+Each nandcs device node may optionally contain a 'partitions' sub-node, which
+further contains sub-nodes describing the flash partition mapping. See
+partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "boot-nand";
+				reg = <0 0x58a0000>;
+			};
+
+			partition@58a0000 {
+				label = "fs-nand";
+				reg = <0x58a0000 0x4000000>;
+			};
+		};
+	};
+};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
maintainer Acked-by on v6 3/3
#96 lore raw

Re: [PATCH v6 3/3] dt/bindings: qcom_nandc: Add DT bindings

Quoted 17 lines · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v6:
- Update compatible tring to something more specific
- Refer to nand.txt for standard properties
- In the example, use 'partitions' node to hold the partition subnodes

v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

Quoted 7 lines

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 86 ++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
#97 lore raw

v7 cover mtd: Qualcomm NAND controller driver

In reply to Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

The first patch in the series contains a nand_base clean up which the driver will utilize.

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

v7:
- Incorporated missed suggestions from Boris.
- Updated cafe_nand, docg4, diskonchip drivers
- Some indentation fixes found by strict checkpatch checking

v6:
- Fix erased page parsing as suggested by Boris.
- Change compatible string to something more legible.
- Whitespace fixes.

v5:
- Skip creation of BBT as in v1. Will bring this back after BBMs are read/written in raw mode (using badblockbits support).
- Incorporated misc fixes/suggestions by Boris.
- Dropped the DT patches for now, since ADM DMA support isn't merged yet.

v4:
- Some more fixes. Mentioned in individual patch

v3:
- Various fixes and clean ups suggested by Stephen Boyd.

v2:
- Added a new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

v1:
- original series:
https://lkml.org/lkml/2015/1/16/317

Archit Taneja (3):
mtd: nand: don't select chip in nand_chip's block_bad op
mtd: nand: Qualcomm NAND controller driver dt/bindings: qcom_nandc: Add DT bindings

 .../devicetree/bindings/mtd/qcom_nandc.txt         |   86 +
 drivers/mtd/nand/Kconfig                           |    7 +
 drivers/mtd/nand/Makefile                          |    1 +
 drivers/mtd/nand/cafe_nand.c                       |    2 +-
 drivers/mtd/nand/diskonchip.c                      |    2 +-
 drivers/mtd/nand/docg4.c                           |    2 +-
 drivers/mtd/nand/nand_base.c                       |   41 +-
 drivers/mtd/nand/qcom_nandc.c                      | 2024 ++++++++++++++++++++
 include/linux/mtd/nand.h                           |    2 +-
 9 files changed, 2141 insertions(+), 26 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#98 lore raw

PATCH v7 1/3 mtd: nand: don't select chip in nand_chip's block_bad op

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

Remove the getchip argument from the bad_block funcs in cafe_nand, diskonchip and docg4 drivers.

---
v7: Updated cafe_nand, diskonchip and docg4 drivers.

v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

 drivers/mtd/nand/cafe_nand.c  |  2 +-
 drivers/mtd/nand/diskonchip.c |  2 +-
 drivers/mtd/nand/docg4.c      |  2 +-
 drivers/mtd/nand/nand_base.c  | 41 +++++++++++++++++++----------------------
 include/linux/mtd/nand.h      |  2 +-
 5 files changed, 23 insertions(+), 26 deletions(-)
drivers/mtd/nand/cafe_nand.c +1 -1
index 00c15e2..68c3048 100644
@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
 	return 0;
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	return 0;
 }
drivers/mtd/nand/diskonchip.c +1 -1
index a5c0466..dfd6cd5 100644
@@ -798,7 +798,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* This is our last resort if we couldn't find or create a BBT.  Just
 	   pretend all blocks are good. */
drivers/mtd/nand/docg4.c +1 -1
index 95cd139..33a1788 100644
@@ -1121,7 +1121,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return ret;
 }
 
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* only called when module_param ignore_badblocks is set */
 	return 0;
drivers/mtd/nand/nand_base.c +19 -22

87 lines not on this page · raw message

include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Reviewed-by on v7 1/3
#99 lore raw

Re: [PATCH v7 1/3] mtd: nand: don't select chip in nand_chip's block_bad op

Quoted 12 lines · On Thu, 21 Jan 2016 12:43:17 +0530 Archit Taneja <[email protected]> wrote:

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Quoted 7 lines

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

Remove the getchip argument from the bad_block funcs in cafe_nand, diskonchip and docg4 drivers.

Looks good to me

Thanks,

Boris

Quoted 162 lines

---
v7: Updated cafe_nand, diskonchip and docg4 drivers.

v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

 drivers/mtd/nand/cafe_nand.c  |  2 +-
 drivers/mtd/nand/diskonchip.c |  2 +-
 drivers/mtd/nand/docg4.c      |  2 +-
 drivers/mtd/nand/nand_base.c  | 41 +++++++++++++++++++----------------------
 include/linux/mtd/nand.h      |  2 +-
 5 files changed, 23 insertions(+), 26 deletions(-)
drivers/mtd/nand/cafe_nand.c +1 -1
index 00c15e2..68c3048 100644
@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
 	return 0;
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	return 0;
 }
drivers/mtd/nand/diskonchip.c +1 -1
index a5c0466..dfd6cd5 100644
@@ -798,7 +798,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* This is our last resort if we couldn't find or create a BBT.  Just
 	   pretend all blocks are good. */
drivers/mtd/nand/docg4.c +1 -1
index 95cd139..33a1788 100644
@@ -1121,7 +1121,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return ret;
 }
 
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* only called when module_param ignore_badblocks is set */
 	return 0;
drivers/mtd/nand/nand_base.c +19 -22
index 928081b..1809c20 100644
@@ -317,9 +317,9 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-	int page, chipnr, res = 0, i = 0;
+	int page, res = 0, i = 0;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	u16 bad;
 
@@ -328,15 +328,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
-
 	do {
 		if (chip->options & NAND_BUSWIDTH_16) {
 			chip->cmdfunc(mtd, NAND_CMD_READOOB,
@@ -361,11 +352,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 		i++;
 	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-	if (getchip) {
-		chip->select_chip(mtd, -1);
-		nand_release_device(mtd);
-	}
-
 	return res;
 }
 
@@ -503,19 +489,17 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
  * @mtd: MTD device structure
  * @ofs: offset from device start
- * @getchip: 0, if the chip is already selected
  * @allowbbt: 1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
-			       int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
 	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+		return chip->block_bad(mtd, ofs);
 
 	/* Return info from the table */
 	return nand_isbad_bbt(mtd, ofs, allowbbt);
@@ -2918,7 +2902,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 	while (len) {
 		/* Check if we have a bad block, we do not erase bad blocks! */
 		if (nand_block_checkbad(mtd, ((loff_t) page) <<
-					chip->page_shift, 0, allowbbt)) {
+					chip->page_shift, allowbbt)) {
 			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
 				    __func__, page);
 			instr->state = MTD_ERASE_FAILED;
@@ -3005,7 +2989,20 @@ static void nand_sync(struct mtd_info *mtd)
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-	return nand_block_checkbad(mtd, offs, 1, 0);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int chipnr = (int)(offs >> chip->chip_shift);
+	int ret;
+
+	/* Select the NAND device */
+	nand_get_device(mtd, FL_READING);
+	chip->select_chip(mtd, chipnr);
+
+	ret = nand_block_checkbad(mtd, offs, 0);
+
+	chip->select_chip(mtd, -1);
+	nand_release_device(mtd);
+
+	return ret;
 }
 
 /**
include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#100 lore raw

PATCH v7 2/3 mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2032 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +2024 -0

2,024 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Reviewed-by on v7 2/3
#101 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Quoted 49 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2032 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+					mtd->ecc_stats.failed++;
+				} else {
+					unsigned int stat;
+
+					stat = buffer & BS_CORRECTABLE_ERR_MSK;
+					mtd->ecc_stats.corrected += stat;
+					max_bitflips = max(max_bitflips, stat);
+				}

drivers/mtd/nand/qcom_nandc.c line 1099

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+			}
+		}
+
+		data_buf += data_len;
+		if (oob_buf)
+			oob_buf += oob_len + ecc->bytes;
+	}
+
+	return max_bitflips;
+}

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#102 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 178 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2032 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 117 lines
drivers/mtd/nand/qcom_nandc.c new file +117 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 3 lines
drivers/mtd/nand/qcom_nandc.c new file +3 -0
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

From what I understood, we still need to parse the chunks to try to fix 'ecc->strength' number of bitflips.

Quoted 13 lines

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Thanks,
Archit

Quoted 24 lines
Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +8 -0
+					mtd->ecc_stats.failed++;
+				} else {
+					unsigned int stat;
+
+					stat = buffer & BS_CORRECTABLE_ERR_MSK;
+					mtd->ecc_stats.corrected += stat;
+					max_bitflips = max(max_bitflips, stat);
+				}

drivers/mtd/nand/qcom_nandc.c line 1099

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+			}
+		}
+
+		data_buf += data_len;
+		if (oob_buf)
+			oob_buf += oob_len + ecc->bytes;
+	}
+
+	return max_bitflips;
+}

Best Regards,

Boris

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#103 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 178 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2032 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 117 lines
drivers/mtd/nand/qcom_nandc.c new file +117 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
Quoted 8 lines

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 3 lines
drivers/mtd/nand/qcom_nandc.c new file +3 -0
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

Quoted 3 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Quoted 15 lines
Quoted 14 lines

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 11 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#104 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 250 lines · Boris Brezillon
Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 186 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

   drivers/mtd/nand/Kconfig      |    7 +
   drivers/mtd/nand/Makefile     |    1 +
   drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
   3 files changed, 2032 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 6 lines
Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

No, the controller reports 0x54s at special offsets, but we still need to parse the entire buffer for 0xffs because the flash user might have intentionally placed 0x54 in that offsets.

The previous revisions of the patchset first the changed the
0x54s to 0xffs at the special offsets, and then checked if the
entire page for 0xffs. If any single byte wasn't 0xff, it reported it
as not empty and replaced the offsets back with 0x54s. For the newer
IPs, we don't need to read the entirepage, we only need to read a bitfield per chunk to be sure.

Quoted 5 lines
Quoted 4 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

Quoted 7 lines

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Okay. I thought that when NAND controllers report an empty page, there can still be bitflips in them once we read it, and that we need to use nand_check_erased_ecc_chunk to set those bits back to 1.

Quoted 25 lines
Quoted 16 lines
Quoted 15 lines

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 12 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Quoted 8 lines

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Okay. I think I understand now :). I thought nand_check_erased_ecc_chunk had to be used for pages that were reported as erased, but it is used for pages that aren't detected as erased because of some bitflips, and we just make sure if it is erased or not.

Should the pseudo code look something like this?

/* ecc->read_page */
int qcom_nand_read_page(...)

{
	/* read the page */
	...

	erased = empty_page_fixup();
	/* we make sure above that the entire page is 0xffs or not */

	return parse_read_errors(host, erased);
}

int parse_read_errors(host, erased)

{
	for each chunk {	
		if (!erased) {
			if (uncorrectable errors) {
				ret = nand_check_erased_ecc_chunk();
				if (ret < 0) {
					/* not an erased page, report */
					stats.failed++
				} else {
					/* 'almost' empty page which
					HW couldn't detect as erased */
					stats.corrected += ret;
				}
			} else {
				stats.corrected += stat;
			}
		}
	}
}

Thanks,
Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#105 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 264 lines · On Thu, 21 Jan 2016 16:30:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 250 lines · Boris Brezillon
Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 186 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

   drivers/mtd/nand/Kconfig      |    7 +
   drivers/mtd/nand/Makefile     |    1 +
   drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++
   3 files changed, 2032 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 6 lines
Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

No, the controller reports 0x54s at special offsets, but we still need to parse the entire buffer for 0xffs because the flash user might have intentionally placed 0x54 in that offsets.

Quoted 6 lines

The previous revisions of the patchset first the changed the 0x54s to 0xffs at the special offsets, and then checked if the entire page for 0xffs. If any single byte wasn't 0xff, it reported it as not empty and replaced the offsets back with 0x54s. For the newer IPs, we don't need to read the entirepage, we only need to read a bitfield per chunk to be sure.

Oh, I thought the FS_OP_ERR + 0X54 pattern @3 and 175 were enough to detect an empty page, but I must have misunderstood your previous explanations. Anyway, adding an extra nand_check_erased_ecc_chunk() here shouldn't hurt, so I'm fine with that one.

Quoted 14 lines
Quoted 6 lines
Quoted 5 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

Quoted 7 lines

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Quoted 3 lines

Okay. I thought that when NAND controllers report an empty page, there can still be bitflips in them once we read it, and that we need to use nand_check_erased_ecc_chunk to set those bits back to 1.

It's really dependent on your NAND controller, so I can't answer that question for your specific case, but usually NAND controller are able to detect pages filled with 0xff, but as soon as you have a single bitflip, the control is passed to the ECC engine which tries to correct errors (and fails to do it in most cases).
Some ECC engines are smarter and you can pass them an 'acceptable' number of bitflips that is used by the "erased page detection" logic. And other ECC engines take care of xoring the ECC bytes so that it generates 0xff bytes for empty pages (this solution is the ideal one, since you're guaranteed to fix bitflips even for the empty/erased page case).

Quoted 66 lines
Quoted 26 lines
Quoted 17 lines
Quoted 4 lines
Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Quoted 8 lines

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Okay. I think I understand now :). I thought nand_check_erased_ecc_chunk had to be used for pages that were reported as erased, but it is used for pages that aren't detected as erased because of some bitflips, and we just make sure if it is erased or not.

Should the pseudo code look something like this?

/* ecc->read_page */
int qcom_nand_read_page(...)

{
	/* read the page */
	...

	erased = empty_page_fixup();
	/* we make sure above that the entire page is 0xffs or not */

	return parse_read_errors(host, erased);
}

int parse_read_errors(host, erased)

{
	for each chunk {	
		if (!erased) {
			if (uncorrectable errors) {
				ret = nand_check_erased_ecc_chunk();
				if (ret < 0) {
					/* not an erased page, report */
					stats.failed++
				} else {
					/* 'almost' empty page which
					HW couldn't detect as erased */
Quoted 8 lines
					stats.corrected += ret;
				}
			} else {
				stats.corrected += stat;
			}
		}
	}
}

Yep, exactly.

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#106 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 274 lines · Boris Brezillon
Quoted 264 lines · On Thu, 21 Jan 2016 16:30:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 250 lines · Boris Brezillon
Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 186 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2032 insertions(+)
create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c line 1072

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 6 lines
Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

No, the controller reports 0x54s at special offsets, but we still need to parse the entire buffer for 0xffs because the flash user might have intentionally placed 0x54 in that offsets.

Quoted 6 lines

The previous revisions of the patchset first the changed the 0x54s to 0xffs at the special offsets, and then checked if the entire page for 0xffs. If any single byte wasn't 0xff, it reported it as not empty and replaced the offsets back with 0x54s. For the newer IPs, we don't need to read the entirepage, we only need to read a bitfield per chunk to be sure.

Quoted 4 lines

Oh, I thought the FS_OP_ERR + 0X54 pattern @3 and 175 were enough to detect an empty page, but I must have misunderstood your previous explanations. Anyway, adding an extra nand_check_erased_ecc_chunk() here shouldn't hurt, so I'm fine with that one.

Yeah, we need to check manually too, sadly. Although, since we are sure that it is always 0xffs, I can put the faster memchr_inv func to check if the page is erased.

Quoted 19 lines
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

Quoted 7 lines

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Quoted 3 lines

Okay. I thought that when NAND controllers report an empty page, there can still be bitflips in them once we read it, and that we need to use nand_check_erased_ecc_chunk to set those bits back to 1.

Quoted 5 lines

It's really dependent on your NAND controller, so I can't answer that question for your specific case, but usually NAND controller are able to detect pages filled with 0xff, but as soon as you have a single bitflip, the control is passed to the ECC engine which tries to correct errors (and fails to do it in most cases).

Yes, that seems to be the case for this controller.

Quoted 2 lines

Some ECC engines are smarter and you can pass them an 'acceptable' number of bitflips that is used by the "erased page detection" logic.

I haven't seen such an 'acceptable' bitfield for this controller.

Quoted 4 lines

And other ECC engines take care of xoring the ECC bytes so that it generates 0xff bytes for empty pages (this solution is the ideal one, since you're guaranteed to fix bitflips even for the empty/erased page case).

Okay, I doubt that the controller does that here, but I'll go through the docs and verify. Thanks for the explanation.

Quoted 76 lines
Quoted 67 lines
Quoted 27 lines
Quoted 18 lines
Quoted 5 lines
Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c line 1081

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Quoted 8 lines

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Okay. I think I understand now :). I thought nand_check_erased_ecc_chunk had to be used for pages that were reported as erased, but it is used for pages that aren't detected as erased because of some bitflips, and we just make sure if it is erased or not.

Should the pseudo code look something like this?

/* ecc->read_page */
int qcom_nand_read_page(...)

{
	/* read the page */
	...

	erased = empty_page_fixup();
	/* we make sure above that the entire page is 0xffs or not */

	return parse_read_errors(host, erased);
}

int parse_read_errors(host, erased)

{
	for each chunk {	
		if (!erased) {
			if (uncorrectable errors) {
				ret = nand_check_erased_ecc_chunk();
				if (ret < 0) {
					/* not an erased page, report */
					stats.failed++
				} else {
					/* 'almost' empty page which
					HW couldn't detect as erased */
Quoted 8 lines
					stats.corrected += ret;
				}
			} else {
				stats.corrected += stat;
			}
		}
	}
}
Quoted 1 line

Yep, exactly.

Thanks. I'll fix this and test it out.

Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#107 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 402 lines · On Thu, 21 Jan 2016 18:38:05 +0530 Archit Taneja <[email protected]> wrote:
Quoted 274 lines · Boris Brezillon
Quoted 264 lines · On Thu, 21 Jan 2016 16:30:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 250 lines · Boris Brezillon
Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 186 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2032 insertions(+)
create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 6 lines
Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

No, the controller reports 0x54s at special offsets, but we still need to parse the entire buffer for 0xffs because the flash user might have intentionally placed 0x54 in that offsets.

Quoted 6 lines

The previous revisions of the patchset first the changed the 0x54s to 0xffs at the special offsets, and then checked if the entire page for 0xffs. If any single byte wasn't 0xff, it reported it as not empty and replaced the offsets back with 0x54s. For the newer IPs, we don't need to read the entirepage, we only need to read a bitfield per chunk to be sure.

Quoted 4 lines

Oh, I thought the FS_OP_ERR + 0X54 pattern @3 and 175 were enough to detect an empty page, but I must have misunderstood your previous explanations. Anyway, adding an extra nand_check_erased_ecc_chunk() here shouldn't hurt, so I'm fine with that one.

Yeah, we need to check manually too, sadly. Although, since we are sure that it is always 0xffs, I can put the faster memchr_inv func to check if the page is erased.

Quoted 19 lines
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

Quoted 7 lines

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Quoted 3 lines

Okay. I thought that when NAND controllers report an empty page, there can still be bitflips in them once we read it, and that we need to use nand_check_erased_ecc_chunk to set those bits back to 1.

Quoted 5 lines

It's really dependent on your NAND controller, so I can't answer that question for your specific case, but usually NAND controller are able to detect pages filled with 0xff, but as soon as you have a single bitflip, the control is passed to the ECC engine which tries to correct errors (and fails to do it in most cases).

Yes, that seems to be the case for this controller.

Quoted 2 lines

Some ECC engines are smarter and you can pass them an 'acceptable' number of bitflips that is used by the "erased page detection" logic.

I haven't seen such an 'acceptable' bitfield for this controller.

Quoted 4 lines

And other ECC engines take care of xoring the ECC bytes so that it generates 0xff bytes for empty pages (this solution is the ideal one, since you're guaranteed to fix bitflips even for the empty/erased page case).

Okay, I doubt that the controller does that here, but I'll go through the docs and verify. Thanks for the explanation.

Quoted 76 lines
Quoted 75 lines
Quoted 27 lines
Quoted 18 lines
Quoted 5 lines
Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Quoted 8 lines

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Okay. I think I understand now :). I thought nand_check_erased_ecc_chunk had to be used for pages that were reported as erased, but it is used for pages that aren't detected as erased because of some bitflips, and we just make sure if it is erased or not.

Should the pseudo code look something like this?

/* ecc->read_page */
int qcom_nand_read_page(...)

{
	/* read the page */
	...

	erased = empty_page_fixup();
	/* we make sure above that the entire page is 0xffs or not */

	return parse_read_errors(host, erased);
}

int parse_read_errors(host, erased)

{
	for each chunk {	
		if (!erased) {
			if (uncorrectable errors) {
				ret = nand_check_erased_ecc_chunk();
				if (ret < 0) {
					/* not an erased page, report */
					stats.failed++
				} else {
					/* 'almost' empty page which
					HW couldn't detect as erased */
					stats.corrected += ret;
				}
			} else {
				stats.corrected += stat;
			}
		}
	}
}
Quoted 3 lines
Quoted 1 line

Yep, exactly.

Thanks. I'll fix this and test it out.

If you want to check that your "bitflips in erased pages" handling is correct, you can try this tool to artificially flip some bits [1].

# flash_erase /dev/mtdX Y 1
# nandflipbits /dev/mtdX 2@<Y>:3@<Y+1>

Best Regards,

Boris

[1]http://lists.infradead.org/pipermail/linux-mtd/2014-November/056634.html

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#108 lore raw

Re: [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 407 lines · Boris Brezillon
Quoted 404 lines · On Thu, 21 Jan 2016 18:38:05 +0530 Archit Taneja <[email protected]> wrote:
Quoted 274 lines · Boris Brezillon
Quoted 264 lines · On Thu, 21 Jan 2016 16:30:48 +0530 Archit Taneja <[email protected]> wrote:
Quoted 250 lines · Boris Brezillon
Quoted 247 lines · On Thu, 21 Jan 2016 15:22:39 +0530 Archit Taneja <[email protected]> wrote:
Quoted 46 lines · Boris Brezillon

Hi Archit,

Quoted 41 lines · On Thu, 21 Jan 2016 12:43:18 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

Quoted 8 lines
Quoted 3 lines

Sorry, I noticed one more thing in your "bitflips in erased pages" handling. Once this is addressed (or explained) you can add my

Thanks! I've given an explanation below.

Quoted 186 lines
Quoted 50 lines

---
v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/qcom_nandc.c | 2024 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2032 insertions(+)
create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 5 lines
drivers/mtd/nand/qcom_nandc.c new file +0 -0
new file mode 100644
index 0000000..269d388

[...]

Quoted 110 lines
drivers/mtd/nand/qcom_nandc.c new file +110 -0
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff
+ */
+static bool empty_page_fixup(struct qcom_nand_host *host, u8 *data_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, erased_cw;
+		u8 empty1, empty2;
+
+		flash = le32_to_cpu(buf->flash);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		/*
+		 * an erased page flags an error in NAND_FLASH_STATUS, if there
+		 * isn't any error, bail out early and report a non-erased
+		 * page
+		 */
+		if (!(flash & FS_OP_ERR))
+			break;
+
+		/*
+		 * if BCH is enabled, HW will take care of detecting erased
+		 * pages
+		 */
+		if (host->bch_enabled) {
+			/* bail out if we didn't detect an erased CW */
+			if ((erased_cw & ERASED_CW) != ERASED_CW)
+				break;
+		} else {
+			/*
+			 * if RS ECC is enabled, check if the CW is erased by
+			 * looking for 0x54s at offsets 3 and 175
+			 */
+			empty1 = data_buf[3 + i * host->cw_data];
+			empty2 = data_buf[175 + i * host->cw_data];
+
+			/* bail out if the CW isn't erased */
+			if (!(empty1 == 0x54 && empty2 == 0xff) &&
+			    !(empty1 == 0xff && empty2 == 0x54))
+				break;
+		}
+	}
+
+	if (i < ecc->steps)
+		return false;
+
+	if (!host->bch_enabled) {
+		/*
+		 * fix up the buffer by replacing the magic offsets with
+		 * 0xff
+		 */
+		for (i = 0; i < ecc->steps; i++) {
+			data_buf[3 + i * host->cw_data] = 0xff;
+			data_buf[175 + i * host->cw_data] = 0xff;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf, bool erased_page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			if (erased_page) {

drivers/mtd/nand/qcom_nandc.c

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);

IIUC, the erased_page info is returned by empty_page_fixup() and is only set if the page is detected as empty (filled with ff). If that's the case, then you don't have to use nand_check_erased_ecc_chunk() to check it again...

Quoted 6 lines
Quoted 3 lines

empty_page_fixup now doesn't parse the entire page for 0xffs, it just checks if the correct flags have been raised by the controller hardware, and replaces the 'special offsets' with 0xffs instead of 0x54s.

But didn't you say that those pattern assignment were guaranteeing that the tested chunk is empty? Or am I missing something else?

No, the controller reports 0x54s at special offsets, but we still need to parse the entire buffer for 0xffs because the flash user might have intentionally placed 0x54 in that offsets.

Quoted 6 lines

The previous revisions of the patchset first the changed the 0x54s to 0xffs at the special offsets, and then checked if the entire page for 0xffs. If any single byte wasn't 0xff, it reported it as not empty and replaced the offsets back with 0x54s. For the newer IPs, we don't need to read the entirepage, we only need to read a bitfield per chunk to be sure.

Quoted 4 lines

Oh, I thought the FS_OP_ERR + 0X54 pattern @3 and 175 were enough to detect an empty page, but I must have misunderstood your previous explanations. Anyway, adding an extra nand_check_erased_ecc_chunk() here shouldn't hurt, so I'm fine with that one.

Yeah, we need to check manually too, sadly. Although, since we are sure that it is always 0xffs, I can put the faster memchr_inv func to check if the page is erased.

Quoted 19 lines
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines

From what I understood, we still need to parse the chunks to try to
fix 'ecc->strength' number of bitflips.

Quoted 7 lines

No, if the controller tests and guarantees that a specific page is empty (filled with ff), then we should trust it.
I suggested to use nand_check_erased_ecc_chunk() in one of my previous review because I thought the 0x54 detection scheme was not sufficient to detect empty pages, but you said it was, so I trust you ;). And if it's really safe, then we don't need to check again with nand_check_erased_ecc_chunk() here.

Quoted 3 lines

Okay. I thought that when NAND controllers report an empty page, there can still be bitflips in them once we read it, and that we need to use nand_check_erased_ecc_chunk to set those bits back to 1.

Quoted 5 lines

It's really dependent on your NAND controller, so I can't answer that question for your specific case, but usually NAND controller are able to detect pages filled with 0xff, but as soon as you have a single bitflip, the control is passed to the ECC engine which tries to correct errors (and fails to do it in most cases).

Yes, that seems to be the case for this controller.

Quoted 2 lines

Some ECC engines are smarter and you can pass them an 'acceptable' number of bitflips that is used by the "erased page detection" logic.

I haven't seen such an 'acceptable' bitfield for this controller.

Quoted 4 lines

And other ECC engines take care of xoring the ECC bytes so that it generates 0xff bytes for empty pages (this solution is the ideal one, since you're guaranteed to fix bitflips even for the empty/erased page case).

Okay, I doubt that the controller does that here, but I'll go through the docs and verify. Thanks for the explanation.

Quoted 77 lines
Quoted 67 lines
Quoted 27 lines
Quoted 18 lines
Quoted 5 lines
Quoted 12 lines

drivers/mtd/nand/qcom_nandc.c

Quoted 9 lines
drivers/mtd/nand/qcom_nandc.c new file +9 -0
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			} else {
+				if (buffer & BS_UNCORRECTABLE_BIT) {

... here is where you should check if what was detected as uncorrectable errors is not in fact some bitflips in an erased page.

Quoted 8 lines

This path will never hit for a page reported as erased by the HW. The 'else' branch happens only for pages that were reported as 'not erased' by empty page fixup.

In other words, the BS_UNCORRECTABLE_BIT register bitfield is never checked for an erased page. In some experiments I performed, I noticed that this bitfield was almost always set for an erased page. There is not point in even checking this field for an erased page.

Quoted 8 lines

No, my point was that, if you have one or several bitflips in an erased page (which can happen), then your NAND controller will first detect that it's not an empty page (because you have some bits set to zero), and then try to correct the errors with its ECC engine (which will probably fail, unless your controller generate 0xff ECC bytes for an empty page). nand_check_erased_ecc_chunk() has been created exactly for this use case: manually check if a page is 'almost' empty when the ECC engine fails to correct errors.

Okay. I think I understand now :). I thought nand_check_erased_ecc_chunk had to be used for pages that were reported as erased, but it is used for pages that aren't detected as erased because of some bitflips, and we just make sure if it is erased or not.

Should the pseudo code look something like this?

/* ecc->read_page */
int qcom_nand_read_page(...)

{
	/* read the page */
	...

	erased = empty_page_fixup();
	/* we make sure above that the entire page is 0xffs or not */

	return parse_read_errors(host, erased);
}

int parse_read_errors(host, erased)

{
	for each chunk {	
		if (!erased) {
			if (uncorrectable errors) {
				ret = nand_check_erased_ecc_chunk();
				if (ret < 0) {
					/* not an erased page, report */
					stats.failed++
				} else {
					/* 'almost' empty page which
					HW couldn't detect as erased */
Quoted 8 lines
					stats.corrected += ret;
				}
			} else {
				stats.corrected += stat;
			}
		}
	}
}

Yep, exactly.

Quoted 9 lines
Quoted 1 line

Thanks. I'll fix this and test it out.

If you want to check that your "bitflips in erased pages" handling is correct, you can try this tool to artificially flip some bits [1].

# flash_erase /dev/mtdX Y 1
# nandflipbits /dev/mtdX 2@<Y>:3@<Y+1>

Thanks for the suggestion. I was thinking of running mtd_torturetest on an eraseblock for a few days and hope for a few bitflips. This seems much easier :)

Archit

Quoted 7 lines

Best Regards,

Boris

[1]http://lists.infradead.org/pipermail/linux-mtd/2014-November/056634.html

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#109 lore raw

PATCH v7 3/3 dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
 .../devicetree/bindings/mtd/qcom_nandc.txt         | 86 ++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +86 -0
new file mode 100644
index 0000000..70dd511
@@ -0,0 +1,86 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ipq806x-nand"
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	see nand.txt
+- nand-ecc-step-size:	must be 512. see nand.txt for more details.
+
+Optional properties:
+- nand-bus-width:	see nand.txt
+
+Each nandcs device node may optionally contain a 'partitions' sub-node, which
+further contains sub-nodes describing the flash partition mapping. See
+partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "boot-nand";
+				reg = <0 0x58a0000>;
+			};
+
+			partition@58a0000 {
+				label = "fs-nand";
+				reg = <0x58a0000 0x4000000>;
+			};
+		};
+	};
+};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#110 lore raw

Re: [PATCH v7 3/3] dt/bindings: qcom_nandc: Add DT bindings

Quoted 1 line · Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

Missed on inserting a "Reviewed-by" from Boris here.

Quoted 101 lines
---
  .../devicetree/bindings/mtd/qcom_nandc.txt         | 86 ++++++++++++++++++++++
  1 file changed, 86 insertions(+)

create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt

Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +86 -0
new file mode 100644
index 0000000..70dd511
@@ -0,0 +1,86 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ipq806x-nand"
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	see nand.txt
+- nand-ecc-step-size:	must be 512. see nand.txt for more details.
+
+Optional properties:
+- nand-bus-width:	see nand.txt
+
+Each nandcs device node may optionally contain a 'partitions' sub-node, which
+further contains sub-nodes describing the flash partition mapping. See
+partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "boot-nand";
+				reg = <0 0x58a0000>;
+			};
+
+			partition@58a0000 {
+				label = "fs-nand";
+				reg = <0x58a0000 0x4000000>;
+			};
+		};
+	};
+};
Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#111 lore raw

v8 cover mtd: Qualcomm NAND controller driver

In reply to Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

The first patch in the series contains a nand_base clean up which the driver will utilize.

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

v8:
- Fixed issues in erased page parsing as pointed by Boris.
- Rewrite the empty page detection func to detect the page at a chunk level. This simplifies the code quite a bit.
- Introduce raw page read/write ops.

v7:
- Incorporated missed suggestions from Boris.
- Updated cafe_nand, docg4, diskonchip drivers
- Some indentation fixes found by strict checkpatch checking

v6:
- Fix erased page parsing as suggested by Boris.
- Change compatible string to something more legible.
- Whitespace fixes.

v5:
- Skip creation of BBT as in v1. Will bring this back after BBMs are read/written in raw mode (using badblockbits support).
- Incorporated misc fixes/suggestions by Boris.
- Dropped the DT patches for now, since ADM DMA support isn't merged yet.

v4:
- Some more fixes. Mentioned in individual patch

v3:
- Various fixes and clean ups suggested by Stephen Boyd.

v2:
- Added a new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

v1:
- original series:
https://lkml.org/lkml/2015/1/16/317

Archit Taneja (3):
mtd: nand: don't select chip in nand_chip's block_bad op
mtd: nand: Qualcomm NAND controller driver dt/bindings: qcom_nandc: Add DT bindings

 .../devicetree/bindings/mtd/qcom_nandc.txt         |   86 +
 drivers/mtd/nand/Kconfig                           |    7 +
 drivers/mtd/nand/Makefile                          |    1 +
 drivers/mtd/nand/cafe_nand.c                       |    2 +-
 drivers/mtd/nand/diskonchip.c                      |    2 +-
 drivers/mtd/nand/docg4.c                           |    2 +-
 drivers/mtd/nand/nand_base.c                       |   41 +-
 drivers/mtd/nand/qcom_nandc.c                      | 2224 ++++++++++++++++++++
 include/linux/mtd/nand.h                           |    2 +-
 9 files changed, 2341 insertions(+), 26 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#112 lore raw

PATCH v8 1/3 mtd: nand: don't select chip in nand_chip's block_bad op

One of the arguments passed to struct nand_chip's block_bad op is 'getchip', which, if true, is supposed to get and select the nand device, and later unselect and release the device.

This op is intended to be replaceable by drivers. The drivers shouldn't be responsible for selecting/unselecting chip. Like other ops, the chip should already be selected before the block_bad op is called.

Remove the getchip argument from the block_bad op and nand_block_checkbad. Move the chip selection to nand_block_isbad, since it is the only caller to nand_block_checkbad which requires chip selection.

Modify nand_block_bad (the default function for the op) such that it doesn't select the chip.

Remove the getchip argument from the bad_block funcs in cafe_nand, diskonchip and docg4 drivers.

---
v7: Updated cafe_nand, diskonchip and docg4 drivers.

v6: As suggested by Boris, remove getchip arg altogether and select the
chip in nand_block_isbad

 drivers/mtd/nand/cafe_nand.c  |  2 +-
 drivers/mtd/nand/diskonchip.c |  2 +-
 drivers/mtd/nand/docg4.c      |  2 +-
 drivers/mtd/nand/nand_base.c  | 41 +++++++++++++++++++----------------------
 include/linux/mtd/nand.h      |  2 +-
 5 files changed, 23 insertions(+), 26 deletions(-)
drivers/mtd/nand/cafe_nand.c +1 -1
index 00c15e2..68c3048 100644
@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
 	return 0;
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	return 0;
 }
drivers/mtd/nand/diskonchip.c +1 -1
index a5c0466..dfd6cd5 100644
@@ -798,7 +798,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* This is our last resort if we couldn't find or create a BBT.  Just
 	   pretend all blocks are good. */
drivers/mtd/nand/docg4.c +1 -1
index 95cd139..33a1788 100644
@@ -1121,7 +1121,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return ret;
 }
 
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* only called when module_param ignore_badblocks is set */
 	return 0;
drivers/mtd/nand/nand_base.c +19 -22

87 lines not on this page · raw message

include/linux/mtd/nand.h +1 -1
index 3e92be1..c15818e 100644
@@ -650,7 +650,7 @@ struct nand_chip {
 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
 	int (*dev_ready)(struct mtd_info *mtd);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#113 lore raw

PATCH v8 2/3 mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v8:
- Use nand_check_erased_ecc_chunk in the right manner as suggested by Boris (place the check when we see uncorrectable errors).
- Rewrite the empty_page_fixup code such that we check for a codeword being erased rather than the entire page. This simplifies the code and we can now place it in parse_read_errors().
- Introduce raw page access functions. This results in making some modifications in the existing ECC page access ops too, since the layout now also considers the real/dummy bad block markers. Explained in comments.

v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2224 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2232 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/Kconfig +7 -0
index 95b8d2b..2fccdfb 100644
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
 	help
 	  Enables support for NAND controller on Hisilicon SoC Hip04.
 
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
 endif # MTD_NAND
drivers/mtd/nand/Makefile +1 -0
index 2c7f014..9450cdc 100644
@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
 obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
drivers/mtd/nand/qcom_nandc.c new file +2224 -0

2,224 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Reviewed-by on v8 2/3
#114 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Hi Archit,

Quoted 105 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v8:
- Use nand_check_erased_ecc_chunk in the right manner as suggested by Boris (place the check when we see uncorrectable errors).
- Rewrite the empty_page_fixup code such that we check for a codeword being erased rather than the entire page. This simplifies the code and we can now place it in parse_read_errors().
- Introduce raw page access functions. This results in making some modifications in the existing ECC page access ops too, since the layout now also considers the real/dummy bad block markers. Explained in comments.

v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

 drivers/mtd/nand/Kconfig      |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/qcom_nandc.c | 2224 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2232 insertions(+)
 create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 73 lines
drivers/mtd/nand/qcom_nandc.c new file +73 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int cwperpage, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			host->spare_bytes = 0;
+			host->bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			host->spare_bytes = 2;
+			host->bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				host->spare_bytes = 2;
+				host->bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				host->spare_bytes = 4;
+				host->bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				host->spare_bytes = 0;
+				host->bbm_size = 2;
+			} else {
+				host->spare_bytes = 1;
+				host->bbm_size = 1;
+			}
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit

drivers/mtd/nand/qcom_nandc.c line 1851

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_page_raw	= qcom_nandc_read_page_raw;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_page_raw	= qcom_nandc_write_page_raw;
+	ecc->write_oob		= qcom_nandc_write_oob;

You should probably also implement ->{read, write}_oob_raw(), otherwise the core set them to ecc->{read, write}_oob(), which is not exactly the same. Anyway, let's keep that as things that as future improvements. The rest looks good to me.

Thanks for your patience, and all the reworks you've done.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#115 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 202 lines · Boris Brezillon

Hi Archit,

Quoted 105 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v8:
- Use nand_check_erased_ecc_chunk in the right manner as suggested by Boris (place the check when we see uncorrectable errors).
- Rewrite the empty_page_fixup code such that we check for a codeword being erased rather than the entire page. This simplifies the code and we can now place it in parse_read_errors().
- Introduce raw page access functions. This results in making some modifications in the existing ECC page access ops too, since the layout now also considers the real/dummy bad block markers. Explained in comments.

v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2224 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2232 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 73 lines
drivers/mtd/nand/qcom_nandc.c new file +73 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int cwperpage, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			host->spare_bytes = 0;
+			host->bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			host->spare_bytes = 2;
+			host->bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				host->spare_bytes = 2;
+				host->bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				host->spare_bytes = 4;
+				host->bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				host->spare_bytes = 0;
+				host->bbm_size = 2;
+			} else {
+				host->spare_bytes = 1;
+				host->bbm_size = 1;
+			}
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit

drivers/mtd/nand/qcom_nandc.c line 1851

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_page_raw	= qcom_nandc_read_page_raw;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_page_raw	= qcom_nandc_write_page_raw;
+	ecc->write_oob		= qcom_nandc_write_oob;

You should probably also implement ->{read, write}_oob_raw(), otherwise the core set them to ecc->{read, write}_oob(), which is not exactly the same. Anyway, let's keep that as things that as future improvements. The rest looks good to me.

Quoted 3 lines

Thanks for your patience, and all the reworks you've done.

Thanks for your patience to review the various revisions :)

Regards,
Archit

Quoted 5 lines

Best Regards,

Boris

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#116 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

In reply to Boris Brezillon

Hi Brian,

Quoted 202 lines · Boris Brezillon

Hi Archit,

Quoted 105 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and 16 bit correction/step) and RS ECC(4 bit correction/step) that covers main and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for each codeword, followed by data descriptors to read or write data from the controller's internal buffer. It uses a single ADM DMA channel that we get via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v8:
- Use nand_check_erased_ecc_chunk in the right manner as suggested by Boris (place the check when we see uncorrectable errors).
- Rewrite the empty_page_fixup code such that we check for a codeword being erased rather than the entire page. This simplifies the code and we can now place it in parse_read_errors().
- Introduce raw page access functions. This results in making some modifications in the existing ECC page access ops too, since the layout now also considers the real/dummy bad block markers. Explained in comments.

v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2224 +++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2232 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 73 lines
drivers/mtd/nand/qcom_nandc.c new file +73 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int cwperpage, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			host->spare_bytes = 0;
+			host->bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			host->spare_bytes = 2;
+			host->bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				host->spare_bytes = 2;
+				host->bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				host->spare_bytes = 4;
+				host->bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				host->spare_bytes = 0;
+				host->bbm_size = 2;
+			} else {
+				host->spare_bytes = 1;
+				host->bbm_size = 1;
+			}
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit

drivers/mtd/nand/qcom_nandc.c line 1851

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_page_raw	= qcom_nandc_read_page_raw;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_page_raw	= qcom_nandc_write_page_raw;
+	ecc->write_oob		= qcom_nandc_write_oob;

You should probably also implement ->{read, write}_oob_raw(), otherwise the core set them to ecc->{read, write}_oob(), which is not exactly the same. Anyway, let's keep that as things that as future improvements. The rest looks good to me.

Quoted 1 line

If the patchset looks okay to you, could you please take this for the 4.6 merge window?

Thanks,
Archit

Quoted 7 lines

Thanks for your patience, and all the reworks you've done.

Best Regards,

Boris

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#117 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 222 lines · Archit Taneja

Hi Brian,

Quoted 219 lines · Boris Brezillon

Hi Archit,

Quoted 117 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:

The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, MDM9x15 series.

It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a broader interface for external slow peripheral devices such as LCD and NAND/NOR flash memory or SRAM like interfaces.

We add support for the NAND controller found within EBI2. For the SoCs of our interest, we only use the NAND controller within EBI2. Therefore, it's safe for us to assume that the NAND controller is a standalone block
within the SoC.

The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND
flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and
16 bit correction/step) and RS ECC(4 bit correction/step) that covers main
and spare data. The controller contains an internal 512 byte page buffer to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA
for register read/write and data transfers. The controller performs page reads and writes at a codeword/step level of 512 bytes. It can support up
to 2 external chips of different configurations.

The driver prepares register read and write configuration descriptors for
each codeword, followed by data descriptors to read or write data from the
controller's internal buffer. It uses a single ADM DMA channel that we get
via dmaengine API. The controller requires 2 ADM CRCIs for command and data flow control. These are passed via DT.

The ecc layout used by the controller is syndrome like, but we can't use the standard syndrome ecc ops because of several reasons. First, the amount
of data bytes covered by ecc isn't same in each step. Second, writing to free oob space requires us writing to the entire step in which the oob lies. This forces us to create our own ecc ops.

One more difference is how the controller accesses the bad block marker. The controller ignores reading the marker when ECC is enabled. ECC needs to be explicity disabled to read or write to the bad block marker. The nand_bbt helpers library hence can't access BBMs for the controller. For now, we skip the creation of BBT and populate chip->block_bad and chip->block_markbad helpers instead.

---
v8:
- Use nand_check_erased_ecc_chunk in the right manner as suggested by Boris (place the check when we see uncorrectable errors).
- Rewrite the empty_page_fixup code such that we check for a codeword being erased rather than the entire page. This simplifies the code and we can now place it in parse_read_errors().
- Introduce raw page access functions. This results in making some modifications in the existing ECC page access ops too, since the layout now also considers the real/dummy bad block markers.
Explained
in comments.

v7:
- Incorporated missing/new comments by Boris
- Cleaned up some strict checkpatch warnings

v6:
- Fix up erased page parsing. Use nand_check_erased_ecc_chunk to return corrected bitflips in an erased page.
- Fix whitespace issues
- Update compatible tring to something more specific

v5:
- split chip/controller structs
- simplify layout by considering reserved bytes as part of ECC
- create ecc layouts automatically
- implement block_bad and block_markbad chip ops instead of
- read_oob_raw/write_oob_raw ecc ops to access BBMs.
- Add NAND_SKIP_BBTSCAN flag until we get badblockbits support.
- misc clean ups

v4:
- Shrink submit_descs
- add desc list node at the end of dma_prep_desc
- Endianness and warning fixes
- Add Stephen's Signed-off since he provided a patch to fix endianness problems

v3:
- Refactor dma functions for maximum reuse
- Use dma_slave_confing on stack
- optimize and clean upempty_page_fixup using memchr_inv
- ensure portability with dma register reads using le32_* funcs
- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
- fix handling of return values of dmaengine funcs
- constify wherever possible
- Remove dependency on ADM DMA in Kconfig
- Misc fixes and clean ups

v2:
- Use new BBT flag that allows us to read BBM in raw mode
- reduce memcpy-s in the driver
- some refactor and clean ups because of above changes

  drivers/mtd/nand/Kconfig      |    7 +
  drivers/mtd/nand/Makefile     |    1 +
  drivers/mtd/nand/qcom_nandc.c | 2224
+++++++++++++++++++++++++++++++++++++++++
  3 files changed, 2232 insertions(+)

create mode 100644 drivers/mtd/nand/qcom_nandc.c

[...]

Quoted 81 lines
drivers/mtd/nand/qcom_nandc.c new file +6 -0
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+    struct nand_chip *chip = &host->chip;
+    struct mtd_info *mtd = nand_to_mtd(chip);
+    struct nand_ecc_ctrl *ecc = &chip->ecc;
+    struct qcom_nand_controller *nandc =

get_qcom_nand_controller(chip);

drivers/mtd/nand/qcom_nandc.c new file +65 -0
+    int cwperpage, bad_block_byte;
+    bool wide_bus;
+    int ecc_mode = 1;
+
+    /*
+     * the controller requires each step consists of 512 bytes of data.
+     * bail out if DT has populated a wrong step size.
+     */
+    if (ecc->size != NANDC_STEP_SIZE) {
+        dev_err(nandc->dev, "invalid ecc size\n");
+        return -EINVAL;
+    }
+
+    wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+    if (ecc->strength >= 8) {
+        /* 8 bit ECC defaults to BCH ECC on all platforms */
+        host->bch_enabled = true;
+        ecc_mode = 1;
+
+        if (wide_bus) {
+            host->ecc_bytes_hw = 14;
+            host->spare_bytes = 0;
+            host->bbm_size = 2;
+        } else {
+            host->ecc_bytes_hw = 13;
+            host->spare_bytes = 2;
+            host->bbm_size = 1;
+        }
+    } else {
+        /*
+         * if the controller supports BCH for 4 bit ECC, the controller
+         * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+         * always 10 bytes
+         */
+        if (nandc->ecc_modes & ECC_BCH_4BIT) {
+            /* BCH */
+            host->bch_enabled = true;
+            ecc_mode = 0;
+
+            if (wide_bus) {
+                host->ecc_bytes_hw = 8;
+                host->spare_bytes = 2;
+                host->bbm_size = 2;
+            } else {
+                host->ecc_bytes_hw = 7;
+                host->spare_bytes = 4;
+                host->bbm_size = 1;
+            }
+        } else {
+            /* RS */
+            host->ecc_bytes_hw = 10;
+
+            if (wide_bus) {
+                host->spare_bytes = 0;
+                host->bbm_size = 2;
+            } else {
+                host->spare_bytes = 1;
+                host->bbm_size = 1;
+            }
+        }
+    }
+
+    /*
+     * we consider ecc->bytes as the sum of all the non-data content

in a
+ * step. It gives us a clean representation of the oob area
(even if
+ * all the bytes aren't used for ECC).It is always 16 bytes for
8 bit

drivers/mtd/nand/qcom_nandc.c new file +3 -0
+     * ECC and 12 bytes for 4 bit ECC
+     */
+    ecc->bytes = host->ecc_bytes_hw + host->spare_bytes +

host->bbm_size;

drivers/mtd/nand/qcom_nandc.c line 1851

Quoted 7 lines
drivers/mtd/nand/qcom_nandc.c new file +7 -0
+
+    ecc->read_page        = qcom_nandc_read_page;
+    ecc->read_page_raw    = qcom_nandc_read_page_raw;
+    ecc->read_oob        = qcom_nandc_read_oob;
+    ecc->write_page        = qcom_nandc_write_page;
+    ecc->write_page_raw    = qcom_nandc_write_page_raw;
+    ecc->write_oob        = qcom_nandc_write_oob;

You should probably also implement ->{read, write}_oob_raw(), otherwise the core set them to ecc->{read, write}_oob(), which is not exactly the same. Anyway, let's keep that as things that as future improvements. The rest looks good to me.

Quoted 4 lines
Quoted 1 line

If the patchset looks okay to you, could you please take this for the 4.6 merge window?

Ping

Archit

Quoted 12 lines

Thanks,
Archit

Quoted 7 lines

Thanks for your patience, and all the reworks you've done.

Best Regards,

Boris

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#118 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

In reply to Archit Taneja

Hi Archit,

Quoted 127 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +127 -0
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout;
+	int i, j, steps, pos = 0, shift = 0;
+
+	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+	if (!layout)
+		return NULL;
+
+	steps = mtd->writesize / ecc->size;
+	layout->eccbytes = steps * ecc->bytes;
+
+	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+	layout->oobfree[0].length = steps << 2;
+	layout->oobavail = steps << 2;
+
+	/*
+	 * the oob bytes in the first n - 1 codewords are all grouped together
+	 * in the format:
+	 * DUMMY_BBM + UNUSED + ECC
+	 */
+	for (i = 0; i < steps - 1; i++) {
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[pos++] = i * ecc->bytes + j;
+	}
+
+	/*
+	 * the oob bytes in the last codeword are grouped in the format:
+	 * BBM + FREE OOB + UNUSED + ECC
+	 */
+
+	/* fill up the bbm positions */
+	for (j = 0; j < host->bbm_size; j++)
+		layout->eccpos[pos++] = i * ecc->bytes + j;
+
+	/*

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * fill up the ecc and reserved positions, their indices are offseted
+	 * by the free oob region
+	 */
+	shift = layout->oobfree[0].length + host->bbm_size;
+
+	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+	return layout;
+}

I'm trying to move this layout definition to the mtd_ooblayout_ops approach, and I wonder why you decided to take such a complicated representation.
AFAIU, in each ECC step you have 512 bytes of data, X ECC+reserved bytes (you decided to consider all of them as ECC bytes, which is fine by me) and 4 usable/free bytes. Am I correct?

If that's the case, then why not exposing the following layout.

eccregion[i] = {
	.offset = i * (ecc->bytes + 4);
	.length = ecc->bytes;
}
oobfreeregion[i] = {
	.offset = (i * (ecc->bytes + 4)) + ecc->bytes;
	.length = 4;
}

Are there any userspace tools relying on the ooblayout you're currently exposing (remember that the exposed OOB layout is not necessarily what you see on the media)?

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#119 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 157 lines · On Fri, 18 Mar 2016 16:49:04 +0100 Boris Brezillon…

Hi Archit,

Quoted 127 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +127 -0
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout;
+	int i, j, steps, pos = 0, shift = 0;
+
+	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+	if (!layout)
+		return NULL;
+
+	steps = mtd->writesize / ecc->size;
+	layout->eccbytes = steps * ecc->bytes;
+
+	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+	layout->oobfree[0].length = steps << 2;
+	layout->oobavail = steps << 2;
+
+	/*
+	 * the oob bytes in the first n - 1 codewords are all grouped together
+	 * in the format:
+	 * DUMMY_BBM + UNUSED + ECC
+	 */
+	for (i = 0; i < steps - 1; i++) {
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[pos++] = i * ecc->bytes + j;
+	}
+
+	/*
+	 * the oob bytes in the last codeword are grouped in the format:
+	 * BBM + FREE OOB + UNUSED + ECC
+	 */
+
+	/* fill up the bbm positions */
+	for (j = 0; j < host->bbm_size; j++)
+		layout->eccpos[pos++] = i * ecc->bytes + j;
+
+	/*

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * fill up the ecc and reserved positions, their indices are offseted
+	 * by the free oob region
+	 */
+	shift = layout->oobfree[0].length + host->bbm_size;
+
+	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+	return layout;
+}

I'm trying to move this layout definition to the mtd_ooblayout_ops approach, and I wonder why you decided to take such a complicated representation.
AFAIU, in each ECC step you have 512 bytes of data, X ECC+reserved bytes (you decided to consider all of them as ECC bytes, which is fine by me) and 4 usable/free bytes. Am I correct?

If that's the case, then why not exposing the following layout.

eccregion[i] = {
	.offset = i * (ecc->bytes + 4);
	.length = ecc->bytes;
}
Quoted 8 lines
oobfreeregion[i] = {
	.offset = (i * (ecc->bytes + 4)) + ecc->bytes;
	.length = 4;
}

Are there any userspace tools relying on the ooblayout you're currently exposing (remember that the exposed OOB layout is not necessarily what you see on the media)?

Okay, I think we already had this discussion :).
I'm still not happy with the exposed layout (it would be much easier to reserve 4 free bytes per chunk, and declare each chunk as containing 512 data bytes + 4 oob bytes + X ECC/reserved bytes), but IIRC, your ROM code (and/or bootloader) is already using this layout :-(.

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#120 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 169 lines · Boris Brezillon
Quoted 157 lines · On Fri, 18 Mar 2016 16:49:04 +0100 Boris Brezillon…

Hi Archit,

Quoted 127 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +127 -0
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout;
+	int i, j, steps, pos = 0, shift = 0;
+
+	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+	if (!layout)
+		return NULL;
+
+	steps = mtd->writesize / ecc->size;
+	layout->eccbytes = steps * ecc->bytes;
+
+	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+	layout->oobfree[0].length = steps << 2;
+	layout->oobavail = steps << 2;
+
+	/*
+	 * the oob bytes in the first n - 1 codewords are all grouped together
+	 * in the format:
+	 * DUMMY_BBM + UNUSED + ECC
+	 */
+	for (i = 0; i < steps - 1; i++) {
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[pos++] = i * ecc->bytes + j;
+	}
+
+	/*
+	 * the oob bytes in the last codeword are grouped in the format:
+	 * BBM + FREE OOB + UNUSED + ECC
+	 */
+
+	/* fill up the bbm positions */
+	for (j = 0; j < host->bbm_size; j++)
+		layout->eccpos[pos++] = i * ecc->bytes + j;
+
+	/*

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * fill up the ecc and reserved positions, their indices are offseted
+	 * by the free oob region
+	 */
+	shift = layout->oobfree[0].length + host->bbm_size;
+
+	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+	return layout;
+}

I'm trying to move this layout definition to the mtd_ooblayout_ops approach, and I wonder why you decided to take such a complicated representation.
AFAIU, in each ECC step you have 512 bytes of data, X ECC+reserved bytes (you decided to consider all of them as ECC bytes, which is fine by me) and 4 usable/free bytes. Am I correct?

If that's the case, then why not exposing the following layout.

eccregion[i] = {
	.offset = i * (ecc->bytes + 4);
	.length = ecc->bytes;
}
Quoted 8 lines
oobfreeregion[i] = {
	.offset = (i * (ecc->bytes + 4)) + ecc->bytes;
	.length = 4;
}

Are there any userspace tools relying on the ooblayout you're currently exposing (remember that the exposed OOB layout is not necessarily what you see on the media)?

Quoted 5 lines

Okay, I think we already had this discussion :).
I'm still not happy with the exposed layout (it would be much easier to reserve 4 free bytes per chunk, and declare each chunk as containing 512 data bytes + 4 oob bytes + X ECC/reserved bytes), but IIRC, your ROM code (and/or bootloader) is already using this layout :-(.

Sadly, yeah. The reason given for this was that if a filesystem only wanted to read the 16 oob bytes off the page, it could just read the last subpage instead of going through all pages. The optimization clearly doesn't seem worth the software overhead.

Is this something that's blocking your mtd_ooblayout_ops work?

Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#121 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 178 lines · On Sat, 19 Mar 2016 15:44:51 +0530 Archit Taneja <[email protected]> wrote:
Quoted 169 lines · Boris Brezillon
Quoted 157 lines · On Fri, 18 Mar 2016 16:49:04 +0100 Boris Brezillon…

Hi Archit,

Quoted 127 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +127 -0
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout;
+	int i, j, steps, pos = 0, shift = 0;
+
+	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+	if (!layout)
+		return NULL;
+
+	steps = mtd->writesize / ecc->size;
+	layout->eccbytes = steps * ecc->bytes;
+
+	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+	layout->oobfree[0].length = steps << 2;
+	layout->oobavail = steps << 2;
+
+	/*
+	 * the oob bytes in the first n - 1 codewords are all grouped together
+	 * in the format:
+	 * DUMMY_BBM + UNUSED + ECC
+	 */
+	for (i = 0; i < steps - 1; i++) {
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[pos++] = i * ecc->bytes + j;
+	}
+
+	/*
+	 * the oob bytes in the last codeword are grouped in the format:
+	 * BBM + FREE OOB + UNUSED + ECC
+	 */
+
+	/* fill up the bbm positions */
+	for (j = 0; j < host->bbm_size; j++)
+		layout->eccpos[pos++] = i * ecc->bytes + j;
+
+	/*

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * fill up the ecc and reserved positions, their indices are offseted
+	 * by the free oob region
+	 */
+	shift = layout->oobfree[0].length + host->bbm_size;
+
+	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+	return layout;
+}

I'm trying to move this layout definition to the mtd_ooblayout_ops approach, and I wonder why you decided to take such a complicated representation.
AFAIU, in each ECC step you have 512 bytes of data, X ECC+reserved bytes (you decided to consider all of them as ECC bytes, which is fine by me) and 4 usable/free bytes. Am I correct?

If that's the case, then why not exposing the following layout.

eccregion[i] = {
	.offset = i * (ecc->bytes + 4);
	.length = ecc->bytes;
}
Quoted 8 lines
oobfreeregion[i] = {
	.offset = (i * (ecc->bytes + 4)) + ecc->bytes;
	.length = 4;
}

Are there any userspace tools relying on the ooblayout you're currently exposing (remember that the exposed OOB layout is not necessarily what you see on the media)?

Quoted 5 lines

Okay, I think we already had this discussion :).
I'm still not happy with the exposed layout (it would be much easier to reserve 4 free bytes per chunk, and declare each chunk as containing 512 data bytes + 4 oob bytes + X ECC/reserved bytes), but IIRC, your ROM code (and/or bootloader) is already using this layout :-(.

Quoted 6 lines

Sadly, yeah. The reason given for this was that if a filesystem only wanted to read the 16 oob bytes off the page, it could just read the last subpage instead of going through all pages. The optimization clearly doesn't seem worth the software overhead.

Is this something that's blocking your mtd_ooblayout_ops work?

Nope, I think I got it right, but maybe you can check/test it. Here is my branch containing the whole rework [1], and here are the qcom relate patches[2][3].

Thanks,

Boris

[1]https://github.com/bbrezillon/linux-0day/commits/nand/ecclayout [2]https://github.com/bbrezillon/linux-0day/commit/85fba29f4177fbbe8e43cabf433848947bd1c311 [3]https://github.com/bbrezillon/linux-0day/commit/2ebab1c79d275e32a049f293aac2d5e918ef37ab

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
author Tested-by
#122 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 186 lines · Boris Brezillon
Quoted 183 lines · On Sat, 19 Mar 2016 15:44:51 +0530 Archit Taneja <[email protected]> wrote:
Quoted 169 lines · Boris Brezillon
Quoted 157 lines · On Fri, 18 Mar 2016 16:49:04 +0100 Boris Brezillon…

Hi Archit,

Quoted 127 lines · On Wed, 3 Feb 2016 14:29:50 +0530 Archit Taneja <[email protected]> wrote:
drivers/mtd/nand/qcom_nandc.c new file +127 -0
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
+ * ecc->bytes is the sum of the three).
+ */
+
+static struct nand_ecclayout *
+qcom_nand_create_layout(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct nand_ecclayout *layout;
+	int i, j, steps, pos = 0, shift = 0;
+
+	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
+	if (!layout)
+		return NULL;
+
+	steps = mtd->writesize / ecc->size;
+	layout->eccbytes = steps * ecc->bytes;
+
+	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
+	layout->oobfree[0].length = steps << 2;
+	layout->oobavail = steps << 2;
+
+	/*
+	 * the oob bytes in the first n - 1 codewords are all grouped together
+	 * in the format:
+	 * DUMMY_BBM + UNUSED + ECC
+	 */
+	for (i = 0; i < steps - 1; i++) {
+		for (j = 0; j < ecc->bytes; j++)
+			layout->eccpos[pos++] = i * ecc->bytes + j;
+	}
+
+	/*
+	 * the oob bytes in the last codeword are grouped in the format:
+	 * BBM + FREE OOB + UNUSED + ECC
+	 */
+
+	/* fill up the bbm positions */
+	for (j = 0; j < host->bbm_size; j++)
+		layout->eccpos[pos++] = i * ecc->bytes + j;
+
+	/*

drivers/mtd/nand/qcom_nandc.c line 1767

Quoted 10 lines
drivers/mtd/nand/qcom_nandc.c new file +10 -0
+	 * fill up the ecc and reserved positions, their indices are offseted
+	 * by the free oob region
+	 */
+	shift = layout->oobfree[0].length + host->bbm_size;
+
+	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
+		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+
+	return layout;
+}

I'm trying to move this layout definition to the mtd_ooblayout_ops approach, and I wonder why you decided to take such a complicated representation.
AFAIU, in each ECC step you have 512 bytes of data, X ECC+reserved bytes (you decided to consider all of them as ECC bytes, which is fine by me) and 4 usable/free bytes. Am I correct?

If that's the case, then why not exposing the following layout.

eccregion[i] = {
	.offset = i * (ecc->bytes + 4);
	.length = ecc->bytes;
}
Quoted 8 lines
oobfreeregion[i] = {
	.offset = (i * (ecc->bytes + 4)) + ecc->bytes;
	.length = 4;
}

Are there any userspace tools relying on the ooblayout you're currently exposing (remember that the exposed OOB layout is not necessarily what you see on the media)?

Quoted 5 lines

Okay, I think we already had this discussion :).
I'm still not happy with the exposed layout (it would be much easier to reserve 4 free bytes per chunk, and declare each chunk as containing 512 data bytes + 4 oob bytes + X ECC/reserved bytes), but IIRC, your ROM code (and/or bootloader) is already using this layout :-(.

Sadly, yeah. The reason given for this was that if a filesystem only wanted to read the 16 oob bytes off the page, it could just read the last subpage instead of going through all pages. The optimization clearly doesn't seem worth the software overhead.

Quoted 5 lines
Quoted 1 line

Is this something that's blocking your mtd_ooblayout_ops work?

Nope, I think I got it right, but maybe you can check/test it. Here is my branch containing the whole rework [1], and here are the qcom relate patches[2][3].

They look good to me. I tried out your branch and I see correct behavior. Thanks for the patches.

Quoted 9 lines

Thanks,

Boris

[1]https://github.com/bbrezillon/linux-0day/commits/nand/ecclayout [2]https://github.com/bbrezillon/linux-0day/commit/85fba29f4177fbbe8e43cabf433848947bd1c311 [3]https://github.com/bbrezillon/linux-0day/commit/2ebab1c79d275e32a049f293aac2d5e918ef37ab

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#123 lore raw

Re: [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver

Quoted 10 lines · On Tue, 22 Mar 2016 18:40:47 +0530 Archit Taneja <[email protected]> wrote:
Quoted 5 lines
Quoted 1 line

Is this something that's blocking your mtd_ooblayout_ops work?

Nope, I think I got it right, but maybe you can check/test it. Here is my branch containing the whole rework [1], and here are the qcom relate patches[2][3].

They look good to me. I tried out your branch and I see correct behavior. Thanks for the patches.

Thanks for testing.

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#124 lore raw

PATCH v8 3/3 dt/bindings: qcom_nandc: Add DT bindings

In reply to Archit Taneja

Add DT bindings document for the Qualcomm NAND controller driver.

---
v6:
- Update compatible tring to something more specific
- Refer to nand.txt for standard properties
- In the example, use 'partitions' node to hold the partition subnodes

v5:
- Make changes to incorporate chip select sub nodes (brcmnand taken as reference)

v3:
- Don't use '0x' when specifying nand controller address space
- Add optional property for on-flash bbt usage

 .../devicetree/bindings/mtd/qcom_nandc.txt         | 86 ++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/qcom_nandc.txt new file +86 -0
new file mode 100644
index 0000000..70dd511
@@ -0,0 +1,86 @@
+* Qualcomm NAND controller
+
+Required properties:
+- compatible:		should be "qcom,ipq806x-nand"
+- reg:			MMIO address range
+- clocks:		must contain core clock and always on clock
+- clock-names:		must contain "core" for the core clock and "aon" for the
+			always on clock
+- dmas:			DMA specifier, consisting of a phandle to the ADM DMA
+			controller node and the channel number to be used for
+			NAND. Refer to dma.txt and qcom_adm.txt for more details
+- dma-names:		must be "rxtx"
+- qcom,cmd-crci:	must contain the ADM command type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- qcom,data-crci:	must contain the ADM data type CRCI block instance
+			number specified for the NAND controller on the given
+			platform
+- #address-cells:	<1> - subnodes give the chip-select number
+- #size-cells:		<0>
+
+* NAND chip-select
+
+Each controller may contain one or more subnodes to represent enabled
+chip-selects which (may) contain NAND flash chips. Their properties are as
+follows.
+
+Required properties:
+- compatible:		should contain "qcom,nandcs"
+- reg:			a single integer representing the chip-select
+			number (e.g., 0, 1, 2, etc.)
+- #address-cells:	see partition.txt
+- #size-cells:		see partition.txt
+- nand-ecc-strength:	see nand.txt
+- nand-ecc-step-size:	must be 512. see nand.txt for more details.
+
+Optional properties:
+- nand-bus-width:	see nand.txt
+
+Each nandcs device node may optionally contain a 'partitions' sub-node, which
+further contains sub-nodes describing the flash partition mapping. See
+partition.txt for more detail.
+
+Example:
+
+nand@1ac00000 {
+	compatible = "qcom,ebi2-nandc";
+	reg = <0x1ac00000 0x800>;
+
+	clocks = <&gcc EBI2_CLK>,
+		 <&gcc EBI2_AON_CLK>;
+	clock-names = "core", "aon";
+
+	dmas = <&adm_dma 3>;
+	dma-names = "rxtx";
+	qcom,cmd-crci = <15>;
+	qcom,data-crci = <3>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nandcs@0 {
+		compatible = "qcom,nandcs";
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "boot-nand";
+				reg = <0 0x58a0000>;
+			};
+
+			partition@58a0000 {
+				label = "fs-nand";
+				reg = <0x58a0000 0x4000000>;
+			};
+		};
+	};
+};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Applied
#125 lore raw
In reply to Archit Taneja
Quoted 9 lines · Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

Quoted 8 lines

The first patch in the series contains a nand_base clean up which the driver will utilize.

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

Pushed to l2-mtd.git, with the following fixup (the layout->oobavail field has been dropped):

drivers/mtd/nand/qcom_nandc.c +0 -1
index 78dc790ae619..f550a57e6eea 100644
@@ -1733,7 +1733,6 @@ qcom_nand_create_layout(struct qcom_nand_host *host)
 
 	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
 	layout->oobfree[0].length = steps << 2;
-	layout->oobavail = steps << 2;
 
 	/*
 	 * the oob bytes in the first n - 1 codewords are all grouped together
#126 lore raw
Quoted 13 lines · Brian Norris
Quoted 12 lines · Archit Taneja

Add support for the NAND controller driver for SoC's that contain EBI2. For now, the only SoC upstream that has EBI2 is IPQ806x.

The previous version added a BBT flag that allowed BBMs to be accessed in raw mode. Adding a flag isn't the right way to fix it, and the proposed fix is to add badblockbits support, and make sure all drivers switch to accessing BBM in raw mode. For now, skip nand_bbt usage, and implement our own versions of chip->block_bad and chip->mark_bad.

The first patch in the series contains a nand_base clean up which the driver will utilize.

Quoted 8 lines
Quoted 5 lines

Based over l2-mtd.git

The patchset requires the v6 ADM dmaengine patches posted by Andy:

https://lkml.org/lkml/2015/3/17/19

Pushed to l2-mtd.git, with the following fixup (the layout->oobavail field has been dropped):

Thanks for taking this in and fixing the issues.

Archit

Quoted 18 lines
drivers/mtd/nand/qcom_nandc.c +0 -2
index 78dc790ae619..f550a57e6eea 100644
@@ -1733,7 +1733,6 @@ qcom_nand_create_layout(struct qcom_nand_host *host)
 
  	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
  	layout->oobfree[0].length = steps << 2;
-	layout->oobavail = steps << 2;
 
  	/*
  	 * the oob bytes in the first n - 1 codewords are all grouped together
--

To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation