As I said in the 1st round series, I am tackling on this driver
to use it for my SoCs.
The previous series was just cosmetic things, but this series
includes *real* changes.
After some more cleanups, I will start to add changes that
are really necessary.
One of the biggest problems I want to solve is a bunch of
hard-coded parameters that prevent me from using this driver for
my SoCs.
I will introduce capability flags that are associated with DT
compatible and make platform-dependent parameters overridable.
I still have lots of reworks to get done (so probably 3rd round
series will come), but I hope it is getting better and
I am showing a big picture now.
Masahiro Yamada (39):
mtd: nand: allow to set only one of ECC size and ECC strength from DT
mtd: nand: denali: remove unused CONFIG option and macros
mtd: nand: denali: remove redundant define of BANK(x)
mtd: nand: denali: remove more unused struct members
mtd: nand: denali: fix comment of denali_nand_info::flash_mem
mtd: nand: denali: fix write_oob_data() function
mtd: nand: denali: transfer OOB only when oob_required is set
mtd: nand: denali: introduce capability flag
mtd: nand: denali: fix erased page check code
mtd: nand: denali: remove redundant if conditional of erased_check
mtd: nand: denali: increment ecc_stats.failed by one per error
mtd: nand: denali: return 0 for uncorrectable ECC error
mtd: nand: denali: increment ecc_stats->corrected
mtd: nand: denali: replace uint{8/16/32}_t with u{8/16/32}
mtd: nand: denali: improve readability of handle_ecc()
mtd: nand: denali: rename handle_ecc() to denali_sw_ecc_fixup()
mtd: nand: denali: support HW_ECC_FIXUP capability
mtd: nand: denali: move denali_read_page_raw() above
denali_read_page()
mtd: nand: denali: perform erased check against raw transferred page
mtd: nand: denali_dt: enable HW_ECC_FIXUP capability for DT platform
mtd: nand: denali: support 64bit capable DMA engine
mtd: nand: denali_dt: remove dma-mask DT property
mtd: nand: denali_dt: use pdev instead of ofdev for platform_device
mtd: nand: denali: add NEW_N_BANKS_FORMAT capability
mtd: nand: denali: use nand_chip to hold frequently accessed data
mtd: nand: denali: call nand_set_flash_node() to set DT node
mtd: nand: denali: do not set mtd->name
mtd: nand: denali: move multi NAND fixup code to a helper function
mtd: nand: denali: refactor multi NAND fixup code in more generic way
mtd: nand: denali: set DEVICES_CONNECTED 1 if not set
mtd: nand: denali: remove meaningless writes to read-only registers
mtd: nand: denali: remove unnecessary writes to ECC_CORRECTION
mtd: nand: denali: support 1024 byte ECC step size
mtd: nand: denali: fix the condition for 15 bit ECC strength
mtd: nand: denali: calculate ecc.strength and ecc.bytes generically
mtd: nand: denali: allow to use SoC-specific ECC strength
mtd: nand: denali: support "nand-ecc-strength" DT property
mtd: nand: denali: remove Toshiba, Hynix specific fixup code
mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
.../devicetree/bindings/mtd/denali-nand.txt | 19 +-
drivers/mtd/nand/Kconfig | 11 -
drivers/mtd/nand/denali.c | 740 ++++++++++++---------
drivers/mtd/nand/denali.h | 84 +--
drivers/mtd/nand/denali_dt.c | 95 ++-
drivers/mtd/nand/denali_pci.c | 2 +
drivers/mtd/nand/nand_base.c | 6 -
7 files changed, 515 insertions(+), 442 deletions(-)
--
2.7.4
The Denali NAND controller IP has several customizable features.
SoC vendors can choose desired functions when a delivery RTL is
created. It means this IP has various variants. For example,
the Intel version is equipped with 32bit DMA, whereas the IP for
UniPhier SoC family with 64bit DMA.
This driver was originally written for some Intel platforms with
Intel specific things hard-coded. What is worse, the revision
register of this IP does not work to distinguish such features.
We need to do something to make the driver available for other SoCs.
Let's introduce a caps member to the denali_nand_info structure to
switch on/off various features. Also, add struct denali_dt_data to
store the capability associated with compatible string.
Refer to the Link tag for discussion where Boris suggested this
approach instead of a new DT property for every feature.
Signed-off-by: Masahiro Yamada <[email protected]>
Link: https://lkml.org/lkml/2016/3/29/142
---
drivers/mtd/nand/denali.h | 1 +
drivers/mtd/nand/denali_dt.c | 18 +++++++++---------
2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 8bec980..95ed32e 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -420,6 +420,7 @@ struct denali_nand_info {
uint32_t devnum; /* represent how many nands connected */
uint32_t bbtskipbytes;
uint32_t max_banks;
+ unsigned int caps;
};
extern int denali_init(struct denali_nand_info *denali);
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 5607fcd..293ddb8 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -29,6 +29,10 @@ struct denali_dt {
struct clk *clk;
};
+struct denali_dt_data {
+ unsigned int caps;
+};
+
static const struct of_device_id denali_nand_dt_ids[] = {
{ .compatible = "denali,denali-nand-dt" },
{ /* sentinel */ }
@@ -42,23 +46,19 @@ static int denali_dt_probe(struct platform_device *ofdev)
{
struct resource *denali_reg, *nand_data;
struct denali_dt *dt;
+ const struct denali_dt_data *data;
struct denali_nand_info *denali;
int ret;
- const struct of_device_id *of_id;
-
- of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
- if (of_id) {
- ofdev->id_entry = of_id->data;
- } else {
- pr_err("Failed to find the right device id.\n");
- return -ENOMEM;
- }
dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
+ data = of_device_get_match_data(&ofdev->dev);
+ if (data)
+ denali->caps = data->caps;
+
denali->platform = DT;
denali->dev = &ofdev->dev;
denali->irq = platform_get_irq(ofdev, 0);
--
2.7.4
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index fd1ae08..4fad43b 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -407,7 +407,6 @@ struct denali_nand_info {
struct nand_buf buf;
struct device *dev;
int total_used_banks;
- uint32_t block; /* stored for future use */
uint16_t page;
void __iomem *flash_reg; /* Mapped io reg base address */
void __iomem *flash_mem; /* Mapped io reg base address */
@@ -416,7 +415,6 @@ struct denali_nand_info {
struct completion complete;
spinlock_t irq_lock;
uint32_t irq_status;
- int irq_debug_array[32];
int irq;
uint32_t devnum; /* represent how many nands connected */
--
2.7.4
If the addressed page is not erased, the two calls of is_erase()
will both return false, then mtd->ecc_stats.failed will be
incremented by two. Rather, increment it by one because the whole
page including OOB area is transferred in one transaction.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index ab59371..ae9a8d2 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1157,9 +1157,8 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
- if (!is_erased(buf, mtd->writesize))
- mtd->ecc_stats.failed++;
- if (!is_erased(chip->oob_poi, mtd->oobsize))
+ if (!is_erased(buf, mtd->writesize) ||
+ !is_erased(chip->oob_poi, mtd->oobsize))
mtd->ecc_stats.failed++;
}
return max_bitflips;
--
2.7.4
The erased page check must be done against the raw transferred data.
The current first call of is_erase() is against the data after ECC
correction. I saw cases where not all of the data in the page are
0xFF after they are manipulated by the ECC correction engine.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index f035dac..ae44c01 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1168,6 +1168,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__ECC_UNCOR_ERR :
INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
bool check_erased_page = false;
+ int ret;
if (page != denali->page) {
dev_err(denali->dev,
@@ -1206,7 +1207,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
* error.
*/
- read_oob_data(mtd, chip->oob_poi, denali->page);
+ ret = denali_read_page_raw(mtd, chip, buf, 1, denali->page);
+ if (ret < 0)
+ return ret;
/* check ECC failures that may have occurred on erased pages */
if (!is_erased(buf, mtd->writesize) ||
--
2.7.4
Some old versions of the Denali IP (perhaps used only for Intel?)
detects ECC errors and provides correct data via a register, but
does not touch the transferred data. So, the software must fixup
the data in the buffer according to the provided ECC correction
information.
Newer versions perform ECC correction before transferring the data.
No more software intervention is needed. The ECC_ERROR_ADDRESS and
ECC_CORRECTION_INFO registers were deprecated. Instead, the number
of corrected bit-flips can be read from the ECC_COR_INFO register.
When an uncorrectable ECC error happens, a status flag is set to the
INTR_STATUS and ECC_COR_INFO registers.
As is often the case with this IP, the register view of INTR_STATUS
had broken compatibility.
For older versions (SW ECC fixup):
bit 0: ECC_TRANSACTION_DONE
bit 1: ECC_ERR
For newer versions (HW ECC fixup):
bit 0: ECC_UNCOR_ERR
bit 1: Reserved
Due to this difference, the irq_mask must be fixed too. The comment
block in the denali_sw_ecc_fixup() has been moved to the common part
because the comment applies to both cases.
The U-Boot port of this driver already supports the HW ECC fixup. I
borrowed the comment "Some versions of ..." in denali.h from U-Boot.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 44 ++++++++++++++++++++++++++++++++++----------
drivers/mtd/nand/denali.h | 14 ++++++++++++++
2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 271b41a..c101e7f 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -894,6 +894,25 @@ static bool is_erased(u8 *buf, int len)
return false;
return true;
}
+
+static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
+ unsigned int *max_bitflips)
+{
+ int bank = denali->flash_bank;
+ u32 ecc_cor;
+
+ ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank));
+ ecc_cor >>= ECC_COR_INFO_SHIFT(bank);
+
+ if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
+ *max_bitflips = 0;
+ return true;
+ }
+
+ *max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
+ return false;
+}
+
#define ECC_SECTOR_SIZE 512
#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
@@ -949,11 +968,6 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
bitflips++;
}
} else {
- /*
- * if the error is not correctable, need to look at the
- * page to see if it is an erased page. if so, then
- * it's not a real ECC error
- */
check_erased_page = true;
}
} while (!ECC_LAST_ERR(err_correction_info));
@@ -1109,12 +1123,12 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);
-
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
-
u32 irq_status;
- u32 irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
+ u32 irq_mask = denali->caps & DENALI_CAPS_HW_ECC_FIXUP ?
+ INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__ECC_UNCOR_ERR :
+ INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
bool check_erased_page = false;
if (page != denali->page) {
@@ -1139,11 +1153,21 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy(buf, denali->buf.buf, mtd->writesize);
- check_erased_page = denali_sw_ecc_fixup(denali, buf, irq_status,
- &max_bitflips);
+ if (denali->caps & DENALI_CAPS_HW_ECC_FIXUP)
+ check_erased_page = denali_hw_ecc_fixup(denali, &max_bitflips);
+ else
+ check_erased_page = denali_sw_ecc_fixup(denali, buf, irq_status,
+ &max_bitflips);
+
denali_enable_dma(denali, false);
if (check_erased_page) {
+ /*
+ * If the error is not correctable, need to look at the page to
+ * see if it is an erased page. If so, then it's not a real ECC
+ * error.
+ */
+
read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 69314d0..beadc8a 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -20,6 +20,7 @@
#ifndef __DENALI_H__
#define __DENALI_H__
+#include <linux/bitops.h>
#include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0
@@ -219,6 +220,13 @@
#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
+/*
+ * Some versions of the IP have the ECC fixup handled in hardware. In this
+ * configuration we only get interrupted when the error is uncorrectable.
+ * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the
+ * old IP.
+ */
+#define INTR_STATUS__ECC_UNCOR_ERR 0x0001
#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001
#define INTR_STATUS__ECC_ERR 0x0002
#define INTR_STATUS__DMA_CMD_COMP 0x0004
@@ -297,6 +305,11 @@
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
+#define ECC_COR_INFO(__bank) (0x650 + (__bank) / 2 * 0x10)
+#define ECC_COR_INFO_SHIFT(__bank) ((__bank) % 2 * 8)
+#define ECC_COR_INFO__MAX_ERRORS 0x007f
+#define ECC_COR_INFO__UNCOR_ERR 0x0080
+
#define DMA_ENABLE 0x700
#define DMA_ENABLE__FLAG 0x0001
@@ -421,6 +434,7 @@ struct denali_nand_info {
u32 bbtskipbytes;
u32 max_banks;
unsigned int caps;
+#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
};
extern int denali_init(struct denali_nand_info *denali);
--
2.7.4
The current driver only supports the DMA engine up to 32 bit
physical address, but there also exists 64 bit capable DMA engine
for this IP.
The data DMA setup sequence is completely different, so I added the
64 bit DMA code as a new function denali_setup_dma64(). The 32 bit
one has been renamed to denali_setup_dma32().
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 39 +++++++++++++++++++++++++++++++++++----
drivers/mtd/nand/denali.h | 1 +
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index ae44c01..752ad98 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -995,8 +995,30 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en)
ioread32(denali->flash_reg + DMA_ENABLE);
}
-/* setups the HW to perform the data DMA */
-static void denali_setup_dma(struct denali_nand_info *denali, int op)
+static void denali_setup_dma64(struct denali_nand_info *denali, int op)
+{
+ u32 mode;
+ const int page_count = 1;
+ u64 addr = denali->buf.dma_buf;
+
+ mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
+
+ /* DMA is a three step process */
+
+ /*
+ * 1. setup transfer type, interrupt when complete,
+ * burst len = 64 bytes, the number of pages
+ */
+ index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
+
+ /* 2. set memory low address */
+ index_addr(denali, mode, addr);
+
+ /* 3. set memory high address */
+ index_addr(denali, mode, addr >> 32);
+}
+
+static void denali_setup_dma32(struct denali_nand_info *denali, int op)
{
u32 mode;
const int page_count = 1;
@@ -1019,6 +1041,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | 0x14000, 0x2400);
}
+static void denali_setup_dma(struct denali_nand_info *denali, int op)
+{
+ if (denali->caps & DENALI_CAPS_DMA_64BIT)
+ denali_setup_dma64(denali, op);
+ else
+ denali_setup_dma32(denali, op);
+}
+
/*
* writes a page. user specifies type, and this function handles the
* configuration details.
@@ -1495,8 +1525,9 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
- /* Is 32-bit DMA supported? */
- ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask(denali->dev,
+ DMA_BIT_MASK(denali->caps & DENALI_CAPS_DMA_64BIT ?
+ 64 : 32));
if (ret) {
dev_err(denali->dev, "no usable DMA configuration\n");
goto failed_req_irq;
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index beadc8a..9bdf037 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -435,6 +435,7 @@ struct denali_nand_info {
u32 max_banks;
unsigned int caps;
#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
+#define DENALI_CAPS_DMA_64BIT BIT(1)
};
extern int denali_init(struct denali_nand_info *denali);
--
2.7.4
I am going to add HW_ECC_FIXUP capability in the next commit.
Rename the software ECC handling function to denali_sw_ecc_fixup()
for clarification.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index b577560..271b41a 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -903,8 +903,8 @@ static bool is_erased(u8 *buf, int len)
#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
-static bool handle_ecc(struct denali_nand_info *denali, u8 *buf,
- u32 irq_status, unsigned int *max_bitflips)
+static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
+ u32 irq_status, unsigned int *max_bitflips)
{
bool check_erased_page = false;
unsigned int bitflips = 0;
@@ -1139,7 +1139,8 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy(buf, denali->buf.buf, mtd->writesize);
- check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
+ check_erased_page = denali_sw_ecc_fixup(denali, buf, irq_status,
+ &max_bitflips);
denali_enable_dma(denali, false);
if (check_erased_page) {
--
2.7.4
Update the number of corrected bit flips when read_page() succeeds.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index a6445d9..4cc8945 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1162,6 +1162,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
mtd->ecc_stats.failed++;
return 0;
}
+
+ mtd->ecc_stats.corrected += max_bitflips;
+
return max_bitflips;
}
--
2.7.4
The denali_init() needs to setup a bunch of parameters of nand_chip.
Replace denali->nand.(member) with chip->(member) for shorter code.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 68 +++++++++++++++++++++++------------------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 614b4a5..07de879 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1474,7 +1474,8 @@ static void denali_drv_init(struct denali_nand_info *denali)
int denali_init(struct denali_nand_info *denali)
{
- struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (denali->platform == INTEL_CE4100) {
@@ -1511,10 +1512,10 @@ int denali_init(struct denali_nand_info *denali)
mtd->name = "denali-nand";
/* register the driver with the NAND core subsystem */
- denali->nand.select_chip = denali_select_chip;
- denali->nand.cmdfunc = denali_cmdfunc;
- denali->nand.read_byte = denali_read_byte;
- denali->nand.waitfunc = denali_waitfunc;
+ chip->select_chip = denali_select_chip;
+ chip->cmdfunc = denali_cmdfunc;
+ chip->read_byte = denali_read_byte;
+ chip->waitfunc = denali_waitfunc;
/*
* scan for NAND devices attached to the controller
@@ -1558,17 +1559,16 @@ int denali_init(struct denali_nand_info *denali)
* the real pagesize and anything necessery
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
- denali->nand.chipsize <<= denali->devnum - 1;
- denali->nand.page_shift += denali->devnum - 1;
- denali->nand.pagemask = (denali->nand.chipsize >>
- denali->nand.page_shift) - 1;
- denali->nand.bbt_erase_shift += denali->devnum - 1;
- denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
- denali->nand.chip_shift += denali->devnum - 1;
+ chip->chipsize <<= denali->devnum - 1;
+ chip->page_shift += denali->devnum - 1;
+ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+ chip->bbt_erase_shift += denali->devnum - 1;
+ chip->phys_erase_shift = chip->bbt_erase_shift;
+ chip->chip_shift += denali->devnum - 1;
mtd->writesize <<= denali->devnum - 1;
mtd->oobsize <<= denali->devnum - 1;
mtd->erasesize <<= denali->devnum - 1;
- mtd->size = denali->nand.numchips * denali->nand.chipsize;
+ mtd->size = chip->numchips * chip->chipsize;
denali->bbtskipbytes *= denali->devnum;
/*
@@ -1578,29 +1578,29 @@ int denali_init(struct denali_nand_info *denali)
*/
/* Bad block management */
- denali->nand.bbt_td = &bbt_main_descr;
- denali->nand.bbt_md = &bbt_mirror_descr;
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
/* skip the scan for now until we have OOB read and write support */
- denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
- denali->nand.options |= NAND_SKIP_BBTSCAN;
- denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+ chip->options |= NAND_SKIP_BBTSCAN;
+ chip->ecc.mode = NAND_ECC_HW_SYNDROME;
/* no subpage writes on denali */
- denali->nand.options |= NAND_NO_SUBPAGE_WRITE;
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible.
* */
- if (!nand_is_slc(&denali->nand) &&
+ if (!nand_is_slc(chip) &&
(mtd->oobsize > (denali->bbtskipbytes +
ECC_15BITS * (mtd->writesize /
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
- denali->nand.ecc.strength = 15;
- denali->nand.ecc.bytes = ECC_15BITS;
+ chip->ecc.strength = 15;
+ chip->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (mtd->oobsize < (denali->bbtskipbytes +
ECC_8BITS * (mtd->writesize /
@@ -1608,24 +1608,24 @@ int denali_init(struct denali_nand_info *denali)
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
- denali->nand.ecc.strength = 8;
- denali->nand.ecc.bytes = ECC_8BITS;
+ chip->ecc.strength = 8;
+ chip->ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
- denali->nand.ecc.bytes *= denali->devnum;
- denali->nand.ecc.strength *= denali->devnum;
+ chip->ecc.bytes *= denali->devnum;
+ chip->ecc.strength *= denali->devnum;
/* override the default read operations */
- denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
- denali->nand.ecc.read_page = denali_read_page;
- denali->nand.ecc.read_page_raw = denali_read_page_raw;
- denali->nand.ecc.write_page = denali_write_page;
- denali->nand.ecc.write_page_raw = denali_write_page_raw;
- denali->nand.ecc.read_oob = denali_read_oob;
- denali->nand.ecc.write_oob = denali_write_oob;
- denali->nand.erase = denali_erase;
+ chip->ecc.size = ECC_SECTOR_SIZE * denali->devnum;
+ chip->ecc.read_page = denali_read_page;
+ chip->ecc.read_page_raw = denali_read_page_raw;
+ chip->ecc.write_page = denali_write_page;
+ chip->ecc.write_page_raw = denali_write_page_raw;
+ chip->ecc.read_oob = denali_read_oob;
+ chip->ecc.write_oob = denali_write_oob;
+ chip->erase = denali_erase;
ret = nand_scan_tail(mtd);
if (ret)
--
2.7.4
Collect multi NAND fixups into a helper function instead of
scattering them in denali_init().
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 51 ++++++++++++++++++++++++++++-------------------
1 file changed, 31 insertions(+), 20 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 60b0858..54dcd83 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1472,6 +1472,34 @@ static void denali_drv_init(struct denali_nand_info *denali)
denali->irq_status = 0;
}
+static void denali_multidev_fixup(struct denali_nand_info *denali)
+{
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /*
+ * Support for multi NAND:
+ * MTD knows nothing about multi NAND, so we should tell it
+ * the real pagesize and anything necessary
+ */
+ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
+
+ mtd->size <<= denali->devnum - 1;
+ mtd->erasesize <<= denali->devnum - 1;
+ mtd->writesize <<= denali->devnum - 1;
+ mtd->oobsize <<= denali->devnum - 1;
+ chip->chipsize <<= denali->devnum - 1;
+ chip->page_shift += denali->devnum - 1;
+ chip->phys_erase_shift += denali->devnum - 1;
+ chip->bbt_erase_shift += denali->devnum - 1;
+ chip->chip_shift += denali->devnum - 1;
+ chip->pagemask <<= denali->devnum - 1;
+ chip->ecc.size *= denali->devnum;
+ chip->ecc.bytes *= denali->devnum;
+ chip->ecc.strength *= denali->devnum;
+ denali->bbtskipbytes *= denali->devnum;
+}
+
int denali_init(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
@@ -1553,23 +1581,6 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
- /*
- * support for multi nand
- * MTD known nothing about multi nand, so we should tell it
- * the real pagesize and anything necessery
- */
- denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
- chip->chipsize <<= denali->devnum - 1;
- chip->page_shift += denali->devnum - 1;
- chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
- chip->bbt_erase_shift += denali->devnum - 1;
- chip->phys_erase_shift = chip->bbt_erase_shift;
- chip->chip_shift += denali->devnum - 1;
- mtd->writesize <<= denali->devnum - 1;
- mtd->oobsize <<= denali->devnum - 1;
- mtd->erasesize <<= denali->devnum - 1;
- mtd->size = chip->numchips * chip->chipsize;
- denali->bbtskipbytes *= denali->devnum;
/*
* second stage of the NAND scan
@@ -1614,11 +1625,9 @@ int denali_init(struct denali_nand_info *denali)
}
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
- chip->ecc.bytes *= denali->devnum;
- chip->ecc.strength *= denali->devnum;
/* override the default read operations */
- chip->ecc.size = ECC_SECTOR_SIZE * denali->devnum;
+ chip->ecc.size = ECC_SECTOR_SIZE;
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page;
@@ -1627,6 +1636,8 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.write_oob = denali_write_oob;
chip->erase = denali_erase;
+ denali_multidev_fixup(denali);
+
ret = nand_scan_tail(mtd);
if (ret)
goto failed_req_irq;
--
2.7.4
The driver sets appropriate DMA mask. Delete the "dma-mask" DT
property. Refer to the Link tag for negative opinions for this
binding.
Signed-off-by: Masahiro Yamada <[email protected]>
Link: https://lkml.org/lkml/2016/2/8/57
---
Documentation/devicetree/bindings/mtd/denali-nand.txt | 2 --
drivers/mtd/nand/denali_dt.c | 9 ---------
2 files changed, 11 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index b04d03a..603110b 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -5,7 +5,6 @@ Required properties:
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
- - dm-mask : DMA bit mask
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
@@ -19,5 +18,4 @@ nand: nand@ff900000 {
reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0 144 4>;
- dma-mask = <0xffffffff>;
};
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 9dcd203..6a486a7 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -40,8 +40,6 @@ static const struct of_device_id denali_nand_dt_ids[] = {
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
-static u64 denali_dma_mask;
-
static int denali_dt_probe(struct platform_device *ofdev)
{
struct resource *denali_reg, *nand_data;
@@ -79,13 +77,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
- if (!of_property_read_u32(ofdev->dev.of_node,
- "dma-mask", (u32 *)&denali_dma_mask)) {
- denali->dev->dma_mask = &denali_dma_mask;
- } else {
- denali->dev->dma_mask = NULL;
- }
-
dt->clk = devm_clk_get(&ofdev->dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n");
--
2.7.4
This will allow nand_dt_init() to parse DT properties in the NAND
controller device node.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 07de879..0f94381b 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1510,6 +1510,7 @@ int denali_init(struct denali_nand_info *denali)
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
mtd->name = "denali-nand";
+ nand_set_flash_node(chip, denali->dev->of_node);
/* register the driver with the NAND core subsystem */
chip->select_chip = denali_select_chip;
--
2.7.4
Currently, the driver expects DEVICE_CONNECTED is automatically set
by the hardware, but this feature is disabled in some cases.
In such cases, it is the software's responsibility to set up the
DEVICES_CONNECTED register.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 71bdf2a..4b2bbcb 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1485,6 +1485,13 @@ static void denali_multidev_fixup(struct denali_nand_info *denali)
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
+ /*
+ * On some SoCs, DEVICES_CONNECTED is not auto-detected. For those SoCs
+ * DEVICES_CONNECT is left to 0. Set 1 if it is the case.
+ */
+ if (denali->devnum == 0)
+ denali->devnum = 1;
+
devnum_shift = fls(denali->devnum) - 1;
if (denali->devnum != BIT(devnum_shift)) {
@@ -1492,9 +1499,10 @@ static void denali_multidev_fixup(struct denali_nand_info *denali)
"DEVICE_CONNECTED=%d is not power of 2. Some devices will not be used.\n",
denali->devnum);
denali->devnum = BIT(devnum_shift);
- iowrite32(denali->devnum, denali->flash_reg + DEVICES_CONNECTED);
}
+ iowrite32(denali->devnum, denali->flash_reg + DEVICES_CONNECTED);
+
mtd->size <<= devnum_shift;
mtd->erasesize <<= devnum_shift;
mtd->writesize <<= devnum_shift;
--
2.7.4
Add two compatible strings for UniPhier SoCs. The revision register
on both shows revision 5.0, but they are different hardware.
Features:
- DMA engine with 64 bit physical address support
- 1024 byte ECC step size
- 8 / 16 / 24 bit ECC strength
- The n_banks format depends on SoC
Signed-off-by: Masahiro Yamada <[email protected]>
---
.../devicetree/bindings/mtd/denali-nand.txt | 10 +++++--
drivers/mtd/nand/denali_dt.c | 33 ++++++++++++++++++++--
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index 51fe195..cea46e2 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -1,13 +1,19 @@
* Denali NAND controller
Required properties:
- - compatible : should be "denali,denali-nand-dt"
+ - compatible : should be one of the following:
+ "denali,denali-nand-dt"
+ "denali,denali-nand-uniphier-v5a"
+ "denali,denali-nand-uniphier-v5b"
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
Optional properties:
- - nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
+ - nand-ecc-step-size: must be 512 or 1024. If not specified, default to:
+ 512 for "denali,denali-nand-dt"
+ 1024 for "denali,denali-nand-uniphier-v5a"
+ 1024 for "denali,denali-nand-uniphier-v5b"
see nand.txt for details.
- nand-ecc-strength: see nand.txt for details
- nand-ecc-maximize: see nand.txt for details
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index aa1e032..b411889 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -34,10 +34,37 @@ struct denali_dt_data {
unsigned int caps;
};
+static const int denali_uniphier_ecc_strength[] = {
+ 24, 16, 8, 0,
+};
+
+static const struct denali_dt_data denali_uniphier_v5a_data = {
+ .ecc_strength_avail = denali_uniphier_ecc_strength,
+ .caps = DENALI_CAPS_DMA_64BIT |
+ DENALI_CAPS_ECC_SIZE_1024,
+};
+
+static const struct denali_dt_data denali_uniphier_v5b_data = {
+ .ecc_strength_avail = denali_uniphier_ecc_strength,
+ .caps = DENALI_CAPS_DMA_64BIT |
+ DENALI_CAPS_NEW_N_BANKS_FORMAT |
+ DENALI_CAPS_ECC_SIZE_1024,
+};
+
static const struct of_device_id denali_nand_dt_ids[] = {
- { .compatible = "denali,denali-nand-dt" },
- { /* sentinel */ }
- };
+ {
+ .compatible = "denali,denali-nand-dt",
+ },
+ {
+ .compatible = "denali,denali-nand-uniphier-v5a",
+ .data = &denali_uniphier_v5a_data,
+ },
+ {
+ .compatible = "denali,denali-nand-uniphier-v5b",
+ .data = &denali_uniphier_v5b_data,
+ },
+ { /* sentinel */ }
+};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
--
2.7.4
It is valid to use the ECC when the OOB size is exactly the same as
the necessary size.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 5d80f16..c17e92b 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1600,7 +1600,7 @@ int denali_init(struct denali_nand_info *denali)
* SLC if possible.
* */
if (!nand_is_slc(chip) &&
- mtd->oobsize > denali->bbtskipbytes +
+ mtd->oobsize >= denali->bbtskipbytes +
ECC_15BITS * (mtd->writesize / chip->ecc.size)) {
/* if MLC OOB size is large enough, use 15bit ECC*/
chip->ecc.strength = 15;
--
2.7.4
Historically, this driver tried to choose as big ECC strength as
possible, but it would be reasonable to allow DT to set a particular
ECC strength with "nand-ecc-strength" property.
Going forward, DT platforms should specify "nand-ecc-strength" or
"nand-ecc-maximize" to show the ECC strength strategy explicitly.
If nothing is specified in DT, "nand-ecc-maximize" is implied since
this was the original behavior. It applies to PCI platforms too.
Signed-off-by: Masahiro Yamada <[email protected]>
---
.../devicetree/bindings/mtd/denali-nand.txt | 5 ++++
drivers/mtd/nand/denali.c | 27 +++++++++++++++++++++-
drivers/mtd/nand/denali_pci.c | 2 ++
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index e9d5818..51fe195 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -9,6 +9,11 @@ Required properties:
Optional properties:
- nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
see nand.txt for details.
+ - nand-ecc-strength: see nand.txt for details
+ - nand-ecc-maximize: see nand.txt for details
+
+Note:
+Either nand-ecc-strength or nand-ecc-maximize should be specified.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 54c9e0c..df174ca 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1393,6 +1393,21 @@ static int denali_set_max_ecc_strength(struct denali_nand_info *denali)
return -EINVAL;
}
+static int denali_check_ecc_strength(struct denali_nand_info *denali)
+{
+ const int *ecc_strength = denali->ecc_strength_avail;
+
+ for (; *ecc_strength; ecc_strength++) {
+ if (*ecc_strength == denali->nand.ecc.strength)
+ return 0;
+ }
+
+ dev_err(denali->dev,
+ "Specified ECC strength is not supported for this controller.\n");
+
+ return -EINVAL;
+}
+
static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -1628,7 +1643,17 @@ int denali_init(struct denali_nand_info *denali)
if (!denali->ecc_strength_avail)
denali->ecc_strength_avail = denali_default_ecc_strength;
- ret = denali_set_max_ecc_strength(denali);
+ if (!chip->ecc.strength && !(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+ dev_info(denali->dev,
+ "No ECC strength is specified. Trying max ECC strength strategy\n");
+ chip->ecc.options |= NAND_ECC_MAXIMIZE;
+ }
+
+ if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+ ret = denali_set_max_ecc_strength(denali);
+ else
+ ret = denali_check_ecc_strength(denali);
+
if (ret)
goto failed_req_irq;
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
index ac84323..0064f3e 100644
--- a/drivers/mtd/nand/denali_pci.c
+++ b/drivers/mtd/nand/denali_pci.c
@@ -85,6 +85,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto failed_remap_reg;
}
+ denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+
ret = denali_init(denali);
if (ret)
goto failed_remap_mem;
--
2.7.4
This driver was originally written for the Intel MRST platform with
several platform specific parameters hard-coded. Another thing we
need to fix is the hard-coded ECC step size. Currently, it is
defined as follows:
#define ECC_SECTOR_SIZE 512
(somehow, it is defined in both denali.c and denali.h)
This must be avoided because the Denali IP supports 1024 byte ECC
size as well. Add a new flag DENALI_CAPS_ECC_SIZE_1024. If it is
specified, ecc.size is set to 1024, otherwise set to 512.
We can use "nand-ecc-step-size" DT property to override the ecc.size
if we want, but this capability flag can provide the reasonable
default because it is associated with the DT compatible strings.
Signed-off-by: Masahiro Yamada <[email protected]>
---
.../devicetree/bindings/mtd/denali-nand.txt | 4 ++++
drivers/mtd/nand/denali.c | 26 +++++++++++-----------
drivers/mtd/nand/denali.h | 3 +--
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index 603110b..e9d5818 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -6,6 +6,10 @@ Required properties:
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
+Optional properties:
+ - nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
+ see nand.txt for details.
+
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 63f7500..5d80f16 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -894,8 +894,6 @@ static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
return false;
}
-#define ECC_SECTOR_SIZE 512
-
#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET))
#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
@@ -908,6 +906,7 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
{
bool check_erased_page = false;
unsigned int bitflips = 0;
+ unsigned int ecc_size = denali->nand.ecc.size;
u32 err_address, err_correction_info, err_byte, err_sector, err_device,
err_correction_value;
@@ -930,18 +929,18 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
/*
- * If err_byte is larger than ECC_SECTOR_SIZE, means error
+ * If err_byte is larger than ecc_size, means error
* happened in OOB, so we ignore it. It's no need for
* us to correct it err_device is represented the NAND
* error bits are happened in if there are more than
* one NAND connected.
*/
- if (err_byte < ECC_SECTOR_SIZE) {
+ if (err_byte < ecc_size) {
struct mtd_info *mtd =
nand_to_mtd(&denali->nand);
int offset;
- offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
+ offset = (err_sector * ecc_size + err_byte) *
denali->devnum + err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
@@ -1590,22 +1589,25 @@ int denali_init(struct denali_nand_info *denali)
/* no subpage writes on denali */
chip->options |= NAND_NO_SUBPAGE_WRITE;
+ /* If "nand-ecc-step-size" DT property is specified, respect it */
+ if (!chip->ecc.size)
+ chip->ecc.size = denali->caps & DENALI_CAPS_ECC_SIZE_1024 ?
+ 1024 : 512;
+
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible.
* */
if (!nand_is_slc(chip) &&
- (mtd->oobsize > (denali->bbtskipbytes +
- ECC_15BITS * (mtd->writesize /
- ECC_SECTOR_SIZE)))) {
+ mtd->oobsize > denali->bbtskipbytes +
+ ECC_15BITS * (mtd->writesize / chip->ecc.size)) {
/* if MLC OOB size is large enough, use 15bit ECC*/
chip->ecc.strength = 15;
chip->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
- } else if (mtd->oobsize < (denali->bbtskipbytes +
- ECC_8BITS * (mtd->writesize /
- ECC_SECTOR_SIZE))) {
+ } else if (mtd->oobsize <
+ denali->bbtskipbytes + ECC_8BITS * (mtd->writesize / chip->ecc.size)) {
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
@@ -1616,8 +1618,6 @@ int denali_init(struct denali_nand_info *denali)
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
- /* override the default read operations */
- chip->ecc.size = ECC_SECTOR_SIZE;
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page;
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index d621b74..5209625 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -396,8 +396,6 @@
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
-#define ECC_SECTOR_SIZE 512
-
struct nand_buf {
int head;
int tail;
@@ -434,6 +432,7 @@ struct denali_nand_info {
#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
#define DENALI_CAPS_DMA_64BIT BIT(1)
#define DENALI_CAPS_NEW_N_BANKS_FORMAT BIT(2)
+#define DENALI_CAPS_ECC_SIZE_1024 BIT(3)
};
extern int denali_init(struct denali_nand_info *denali);
--
2.7.4
Currently, the denali_read_page_raw() always transfers the OOB and
copy the data to chip->oob_poi, ignoring the oob_required argument.
Respect the oob_required argument.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index b2b050b..cbc7f75 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1182,7 +1182,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
BUG();
}
- setup_ecc_for_xfer(denali, false, true);
+ setup_ecc_for_xfer(denali, false, oob_required ? true : false);
denali_enable_dma(denali, true);
dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
@@ -1198,7 +1198,9 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
denali_enable_dma(denali, false);
memcpy(buf, denali->buf.buf, mtd->writesize);
- memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize);
+ if (oob_required)
+ memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize,
+ mtd->oobsize);
return 0;
}
--
2.7.4
"pdev" is much more often used for platform_device, so this will
help the driver code look consistent across the kernel.
While we are here, fix "line over 80 characters" coding style
violations.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali_dt.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 6a486a7..f085626 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -40,7 +40,7 @@ static const struct of_device_id denali_nand_dt_ids[] = {
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
-static int denali_dt_probe(struct platform_device *ofdev)
+static int denali_dt_probe(struct platform_device *pdev)
{
struct resource *denali_reg, *nand_data;
struct denali_dt *dt;
@@ -48,38 +48,40 @@ static int denali_dt_probe(struct platform_device *ofdev)
struct denali_nand_info *denali;
int ret;
- dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
+ dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
- data = of_device_get_match_data(&ofdev->dev);
+ data = of_device_get_match_data(&pdev->dev);
if (data)
denali->caps = data->caps;
denali->caps |= DENALI_CAPS_HW_ECC_FIXUP;
denali->platform = DT;
- denali->dev = &ofdev->dev;
- denali->irq = platform_get_irq(ofdev, 0);
+ denali->dev = &pdev->dev;
+ denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) {
- dev_err(&ofdev->dev, "no irq defined\n");
+ dev_err(&pdev->dev, "no irq defined\n");
return denali->irq;
}
- denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
- denali->flash_reg = devm_ioremap_resource(&ofdev->dev, denali_reg);
+ denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "denali_reg");
+ denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg);
if (IS_ERR(denali->flash_reg))
return PTR_ERR(denali->flash_reg);
- nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
- denali->flash_mem = devm_ioremap_resource(&ofdev->dev, nand_data);
+ nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "nand_data");
+ denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data);
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
- dt->clk = devm_clk_get(&ofdev->dev, NULL);
+ dt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dt->clk)) {
- dev_err(&ofdev->dev, "no clk available\n");
+ dev_err(&pdev->dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
clk_prepare_enable(dt->clk);
@@ -88,7 +90,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (ret)
goto out_disable_clk;
- platform_set_drvdata(ofdev, dt);
+ platform_set_drvdata(pdev, dt);
return 0;
out_disable_clk:
@@ -97,9 +99,9 @@ static int denali_dt_probe(struct platform_device *ofdev)
return ret;
}
-static int denali_dt_remove(struct platform_device *ofdev)
+static int denali_dt_remove(struct platform_device *pdev)
{
- struct denali_dt *dt = platform_get_drvdata(ofdev);
+ struct denali_dt *dt = platform_get_drvdata(pdev);
denali_remove(&dt->denali);
clk_disable_unprepare(dt->clk);
--
2.7.4
Because SUPPORT_15BITECC is defined, the following is dead code:
#elif SUPPORT_8BITECC
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
#endif
Such ifdefs are useless and unacceptable coding style.
These writes are not needed in the first place since ECC_CORRECTION
is set up by the nand_init() function.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 15 +--------------
drivers/mtd/nand/denali.h | 3 ---
2 files changed, 1 insertion(+), 17 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 9193331..63f7500 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -62,8 +62,6 @@ MODULE_PARM_DESC(onfi_timing_mode,
*/
#define CHIP_SELECT_INVALID -1
-#define SUPPORT_8BITECC 1
-
/*
* This macro divides two integers and rounds fractional values up
* to the nearest integer value.
@@ -347,14 +345,8 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali)
* spare area size for some kind of Toshiba NAND device
*/
if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
- (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
+ (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-#if SUPPORT_15BITECC
- iowrite32(15, denali->flash_reg + ECC_CORRECTION);
-#elif SUPPORT_8BITECC
- iowrite32(8, denali->flash_reg + ECC_CORRECTION);
-#endif
- }
}
static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
@@ -366,11 +358,6 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
-#if SUPPORT_15BITECC
- iowrite32(15, denali->flash_reg + ECC_CORRECTION);
-#elif SUPPORT_8BITECC
- iowrite32(8, denali->flash_reg + ECC_CORRECTION);
-#endif
break;
default:
dev_warn(denali->dev,
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index e3fe3bc..d621b74 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -387,9 +387,6 @@
#define CLK_X 5
#define CLK_MULTI 4
-#define SUPPORT_15BITECC 1
-#define SUPPORT_8BITECC 1
-
#define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0
--
2.7.4
Currently, this code expects denali->devnum == 1 or 2, but it can be
written in a more generic way, although denali->devnum should be a
power of 2.
Also, make the code more readable with devnum_shift.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 54dcd83..71bdf2a 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1476,6 +1476,7 @@ static void denali_multidev_fixup(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
+ int devnum_shift;
/*
* Support for multi NAND:
@@ -1484,20 +1485,30 @@ static void denali_multidev_fixup(struct denali_nand_info *denali)
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
- mtd->size <<= denali->devnum - 1;
- mtd->erasesize <<= denali->devnum - 1;
- mtd->writesize <<= denali->devnum - 1;
- mtd->oobsize <<= denali->devnum - 1;
- chip->chipsize <<= denali->devnum - 1;
- chip->page_shift += denali->devnum - 1;
- chip->phys_erase_shift += denali->devnum - 1;
- chip->bbt_erase_shift += denali->devnum - 1;
- chip->chip_shift += denali->devnum - 1;
- chip->pagemask <<= denali->devnum - 1;
- chip->ecc.size *= denali->devnum;
- chip->ecc.bytes *= denali->devnum;
- chip->ecc.strength *= denali->devnum;
- denali->bbtskipbytes *= denali->devnum;
+ devnum_shift = fls(denali->devnum) - 1;
+
+ if (denali->devnum != BIT(devnum_shift)) {
+ dev_warn(denali->dev,
+ "DEVICE_CONNECTED=%d is not power of 2. Some devices will not be used.\n",
+ denali->devnum);
+ denali->devnum = BIT(devnum_shift);
+ iowrite32(denali->devnum, denali->flash_reg + DEVICES_CONNECTED);
+ }
+
+ mtd->size <<= devnum_shift;
+ mtd->erasesize <<= devnum_shift;
+ mtd->writesize <<= devnum_shift;
+ mtd->oobsize <<= devnum_shift;
+ chip->chipsize <<= devnum_shift;
+ chip->page_shift += devnum_shift;
+ chip->phys_erase_shift += devnum_shift;
+ chip->bbt_erase_shift += devnum_shift;
+ chip->chip_shift += devnum_shift;
+ chip->pagemask <<= devnum_shift;
+ chip->ecc.size <<= devnum_shift;
+ chip->ecc.bytes <<= devnum_shift;
+ chip->ecc.strength <<= devnum_shift;
+ denali->bbtskipbytes <<= devnum_shift;
}
int denali_init(struct denali_nand_info *denali)
--
2.7.4
Currently, is_erased() is called against "buf" twice, so the second
call is meaningless. The second one should be checked against
chip->oob_poi.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index cbc7f75..753e9a02 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1160,7 +1160,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
if (check_erased_page) {
if (!is_erased(buf, mtd->writesize))
mtd->ecc_stats.failed++;
- if (!is_erased(buf, mtd->oobsize))
+ if (!is_erased(chip->oob_poi, mtd->oobsize))
mtd->ecc_stats.failed++;
}
}
--
2.7.4
This will be filled by nand_scan_ident() later.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 0f94381b..60b0858 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1509,7 +1509,6 @@ int denali_init(struct denali_nand_info *denali)
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
- mtd->name = "denali-nand";
nand_set_flash_node(chip, denali->dev->of_node);
/* register the driver with the NAND core subsystem */
--
2.7.4
The denali_dt.c was split out by Altera for the SOCFPGA port. The
Denali IP on SOCFPGA incorporates the hardware ECC fixup feature.
Newer versions are very likely to support it. So, it should be OK
to set DENALI_CAPS_HW_ECC_FIXUP for all DT platforms.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali_dt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 293ddb8..9dcd203 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -59,6 +59,8 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (data)
denali->caps = data->caps;
+ denali->caps |= DENALI_CAPS_HW_ECC_FIXUP;
+
denali->platform = DT;
denali->dev = &ofdev->dev;
denali->irq = platform_get_irq(ofdev, 0);
--
2.7.4
The write accesses to LOGICAL_PAGE_{DATA,SPARE}_SIZE have no effect
because the Denali User's Guide says these registers are read-only.
The hardware automatically multiplies the main/spare size by the
number of devices and update LOGICAL_PAGE_{DATA,SPARE}_SIZE.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 4b2bbcb..9193331 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -342,8 +342,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, u8 device_id)
static void get_toshiba_nand_para(struct denali_nand_info *denali)
{
- u32 tmp;
-
/*
* Workaround to fix a controller bug which reports a wrong
* spare area size for some kind of Toshiba NAND device
@@ -351,10 +349,6 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali)
if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
- tmp = ioread32(denali->flash_reg + DEVICES_CONNECTED) *
- ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
- iowrite32(tmp,
- denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
#elif SUPPORT_8BITECC
@@ -365,22 +359,12 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali)
static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
{
- u32 main_size, spare_size;
-
switch (device_id) {
case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
- main_size = 4096 *
- ioread32(denali->flash_reg + DEVICES_CONNECTED);
- spare_size = 224 *
- ioread32(denali->flash_reg + DEVICES_CONNECTED);
- iowrite32(main_size,
- denali->flash_reg + LOGICAL_PAGE_DATA_SIZE);
- iowrite32(spare_size,
- denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
--
2.7.4
This code block is nested by double "if (check_erase_page)".
Remove the redundant inner one.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 753e9a02..ab59371 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1157,12 +1157,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
- if (check_erased_page) {
- if (!is_erased(buf, mtd->writesize))
- mtd->ecc_stats.failed++;
- if (!is_erased(chip->oob_poi, mtd->oobsize))
- mtd->ecc_stats.failed++;
- }
+ if (!is_erased(buf, mtd->writesize))
+ mtd->ecc_stats.failed++;
+ if (!is_erased(chip->oob_poi, mtd->oobsize))
+ mtd->ecc_stats.failed++;
}
return max_bitflips;
}
--
2.7.4
The same comment "Mapped io reg base address" for flash_reg and
flash_mem probably due to the mistake of copy-paste work.
Of course, the latter is not the register base address.
Reword the comments using the terminology in the Denali User's Guide.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 4fad43b..8bec980 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -408,8 +408,8 @@ struct denali_nand_info {
struct device *dev;
int total_used_banks;
uint16_t page;
- void __iomem *flash_reg; /* Mapped io reg base address */
- void __iomem *flash_mem; /* Mapped io reg base address */
+ void __iomem *flash_reg; /* Register Interface */
+ void __iomem *flash_mem; /* Host Data/Command Interface */
/* elements used by ISR */
struct completion complete;
--
2.7.4
Another problem of this driver is hard-coded ecc.strength and
ecc.bytes. Currently ecc.bytes is defined as follows:
#define ECC_8BITS 14
#define ECC_15BITS 26
Such parameters were hard-coded because only the following two cases
are possible on Intel platforms:
- ecc.size = 512, ecc.strength = 8 --> ecc.bytes = 14
- ecc.size = 512, ecc.strength = 15 --> ecc.bytes = 26
However, these are actually customizable parameters, for example,
UniPhier platform supports the following:
- ecc.size = 1024, ecc.strength = 8 --> ecc.bytes = 14
- ecc.size = 1024, ecc.strength = 16 --> ecc.bytes = 28
- ecc.size = 1024, ecc.strength = 24 --> ecc.bytes = 42
So, we need somehow a generic way to calculate these parameters.
Fortunately, the Denali User's Guide explains how to calculate the
ecc.bytes. The formula is:
ecc.bytes = 2 * CEIL(13 * ecc.strength / 16) (for ecc.size = 512)
ecc.bytes = 2 * CEIL(14 * ecc.strength / 16) (for ecc.size = 1024)
This commit implements two functions denali_calc_ecc_bytes() and
denali_set_max_ecc_strength() to prepare for the next commit,
where I will allow to use SoC-dependent ecc.strength values.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 72 +++++++++++++++++++++++++++++------------------
1 file changed, 45 insertions(+), 27 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index c17e92b..f2ed3f8 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1354,13 +1354,44 @@ static void denali_hw_init(struct denali_nand_info *denali)
denali_irq_init(denali);
}
-/*
- * Althogh controller spec said SLC ECC is forceb to be 4bit,
- * but denali controller in MRST only support 15bit and 8bit ECC
- * correction
- */
-#define ECC_8BITS 14
-#define ECC_15BITS 26
+/* default of supported ECC strength for Intel platforms. */
+static const int denali_default_ecc_strength[] = {
+ 15, 8, 0,
+};
+
+static int denali_calc_ecc_bytes(int ecc_size, int ecc_strength)
+{
+ WARN_ON(ecc_size != 512 && ecc_size != 1024);
+
+ return DIV_ROUND_UP(ecc_strength * (ecc_size == 512 ? 13 : 14), 16) * 2;
+}
+
+static int denali_set_max_ecc_strength(struct denali_nand_info *denali)
+{
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int oobsize = mtd->oobsize;
+ int ecc_size = chip->ecc.size;
+ int ecc_steps = mtd->writesize / chip->ecc.size;
+ const int *ecc_strength = denali_default_ecc_strength;
+ int ecc_bytes;
+
+ /* carve out the BBM area */
+ oobsize -= denali->bbtskipbytes;
+
+ for (; *ecc_strength; ecc_strength++) {
+ ecc_bytes = denali_calc_ecc_bytes(ecc_size, *ecc_strength);
+ if (oobsize >= ecc_bytes * ecc_steps) {
+ chip->ecc.strength = *ecc_strength;
+ return 0;
+ }
+ }
+
+ dev_err(denali->dev,
+ "Your NAND chip OOB is too small. No available ECC strength.\n");
+
+ return -EINVAL;
+}
static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
@@ -1594,27 +1625,14 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.size = denali->caps & DENALI_CAPS_ECC_SIZE_1024 ?
1024 : 512;
- /*
- * Denali Controller only support 15bit and 8bit ECC in MRST,
- * so just let controller do 15bit ECC for MLC and 8bit ECC for
- * SLC if possible.
- * */
- if (!nand_is_slc(chip) &&
- mtd->oobsize >= denali->bbtskipbytes +
- ECC_15BITS * (mtd->writesize / chip->ecc.size)) {
- /* if MLC OOB size is large enough, use 15bit ECC*/
- chip->ecc.strength = 15;
- chip->ecc.bytes = ECC_15BITS;
- iowrite32(15, denali->flash_reg + ECC_CORRECTION);
- } else if (mtd->oobsize <
- denali->bbtskipbytes + ECC_8BITS * (mtd->writesize / chip->ecc.size)) {
- pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
+ ret = denali_set_max_ecc_strength(denali);
+ if (ret)
goto failed_req_irq;
- } else {
- chip->ecc.strength = 8;
- chip->ecc.bytes = ECC_8BITS;
- iowrite32(8, denali->flash_reg + ECC_CORRECTION);
- }
+
+ chip->ecc.bytes = denali_calc_ecc_bytes(chip->ecc.size,
+ chip->ecc.strength);
+
+ iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION);
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
--
2.7.4
The Denali IP can automatically detect device parameters such as
page size, device width, etc. and this driver currently relies on it.
However, this hardware function is problematic.
[1] Due to a hardware bug, various misdetected cases are known.
That is why get_toshiba_nand_para(), get_hynix_nand_para() exist
to fix the misdetected parameters. It is not realistic to add a
new NAND device to the *black list* every time we are hit by a
misdetected case. We would never be able to guarantee that all
the cases are covered.
[2] Because this feature is unreliable, it is disabled on some
platforms.
The nand_scan_ident() sets device parameters such as mtd->writesize,
mtd->erasesize, etc. in a more tested way. We should not set the
hardware registers in a different, unreliable way. Instead, set
the parameters from nand_scan_ident() back to the registers.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 39 ++++++---------------------------------
1 file changed, 6 insertions(+), 33 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index df174ca..1aa19ec 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -338,35 +338,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, u8 device_id)
}
}
-static void get_toshiba_nand_para(struct denali_nand_info *denali)
-{
- /*
- * Workaround to fix a controller bug which reports a wrong
- * spare area size for some kind of Toshiba NAND device
- */
- if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
- (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
- iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-}
-
-static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
-{
- switch (device_id) {
- case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
- case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
- iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
- iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
- iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
- iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
- break;
- default:
- dev_warn(denali->dev,
- "Unknown Hynix NAND (Device ID: 0x%x).\n"
- "Will use default parameter values instead.\n",
- device_id);
- }
-}
-
/*
* determines how many NAND chips are connected to the controller. Note for
* Intel CE4100 devices we don't support more than one device.
@@ -468,10 +439,6 @@ static u16 denali_nand_timing_set(struct denali_nand_info *denali)
return FAIL;
} else if (maf_id == 0xEC) { /* Samsung NAND */
get_samsung_nand_para(denali, device_id);
- } else if (maf_id == 0x98) { /* Toshiba NAND */
- get_toshiba_nand_para(denali);
- } else if (maf_id == 0xAD) { /* Hynix NAND */
- get_hynix_nand_para(denali, device_id);
}
dev_info(denali->dev,
@@ -1661,6 +1628,12 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.strength);
iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION);
+ iowrite32(mtd->erasesize / mtd->writesize,
+ denali->flash_reg + PAGES_PER_BLOCK);
+ iowrite32(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
+ denali->flash_reg + DEVICE_WIDTH);
+ iowrite32(mtd->writesize, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
+ iowrite32(mtd->oobsize, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
--
2.7.4
This function is unreadable due to the deep nesting. Note this
function does a job only when INTR_STATUS__ECC_ERR is set.
So, if the flag is not set, let it bail-out.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 119 +++++++++++++++++++++++-----------------------
1 file changed, 59 insertions(+), 60 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index a7dc692..b577560 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -908,69 +908,68 @@ static bool handle_ecc(struct denali_nand_info *denali, u8 *buf,
{
bool check_erased_page = false;
unsigned int bitflips = 0;
+ u32 err_address, err_correction_info, err_byte, err_sector, err_device,
+ err_correction_value;
- if (irq_status & INTR_STATUS__ECC_ERR) {
- /* read the ECC errors. we'll ignore them for now */
- u32 err_address, err_correction_info, err_byte,
- err_sector, err_device, err_correction_value;
- denali_set_intr_modes(denali, false);
-
- do {
- err_address = ioread32(denali->flash_reg +
- ECC_ERROR_ADDRESS);
- err_sector = ECC_SECTOR(err_address);
- err_byte = ECC_BYTE(err_address);
-
- err_correction_info = ioread32(denali->flash_reg +
- ERR_CORRECTION_INFO);
- err_correction_value =
+ if (!(irq_status & INTR_STATUS__ECC_ERR))
+ goto out;
+
+ /* read the ECC errors. we'll ignore them for now */
+ denali_set_intr_modes(denali, false);
+
+ do {
+ err_address = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
+ err_sector = ECC_SECTOR(err_address);
+ err_byte = ECC_BYTE(err_address);
+
+ err_correction_info = ioread32(denali->flash_reg +
+ ERR_CORRECTION_INFO);
+ err_correction_value =
ECC_CORRECTION_VALUE(err_correction_info);
- err_device = ECC_ERR_DEVICE(err_correction_info);
-
- if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
- /*
- * If err_byte is larger than ECC_SECTOR_SIZE,
- * means error happened in OOB, so we ignore
- * it. It's no need for us to correct it
- * err_device is represented the NAND error
- * bits are happened in if there are more
- * than one NAND connected.
- */
- if (err_byte < ECC_SECTOR_SIZE) {
- struct mtd_info *mtd =
- nand_to_mtd(&denali->nand);
- int offset;
-
- offset = (err_sector *
- ECC_SECTOR_SIZE +
- err_byte) *
- denali->devnum +
- err_device;
- /* correct the ECC error */
- buf[offset] ^= err_correction_value;
- mtd->ecc_stats.corrected++;
- bitflips++;
- }
- } else {
- /*
- * if the error is not correctable, need to
- * look at the page to see if it is an erased
- * page. if so, then it's not a real ECC error
- */
- check_erased_page = true;
+ err_device = ECC_ERR_DEVICE(err_correction_info);
+
+ if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
+ /*
+ * If err_byte is larger than ECC_SECTOR_SIZE, means error
+ * happened in OOB, so we ignore it. It's no need for
+ * us to correct it err_device is represented the NAND
+ * error bits are happened in if there are more than
+ * one NAND connected.
+ */
+ if (err_byte < ECC_SECTOR_SIZE) {
+ struct mtd_info *mtd =
+ nand_to_mtd(&denali->nand);
+ int offset;
+
+ offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
+ denali->devnum + err_device;
+ /* correct the ECC error */
+ buf[offset] ^= err_correction_value;
+ mtd->ecc_stats.corrected++;
+ bitflips++;
}
- } while (!ECC_LAST_ERR(err_correction_info));
- /*
- * Once handle all ecc errors, controller will triger
- * a ECC_TRANSACTION_DONE interrupt, so here just wait
- * for a while for this interrupt
- */
- while (!(read_interrupt_status(denali) &
- INTR_STATUS__ECC_TRANSACTION_DONE))
- cpu_relax();
- clear_interrupts(denali);
- denali_set_intr_modes(denali, true);
- }
+ } else {
+ /*
+ * if the error is not correctable, need to look at the
+ * page to see if it is an erased page. if so, then
+ * it's not a real ECC error
+ */
+ check_erased_page = true;
+ }
+ } while (!ECC_LAST_ERR(err_correction_info));
+
+ /*
+ * Once handle all ecc errors, controller will triger a
+ * ECC_TRANSACTION_DONE interrupt, so here just wait for
+ * a while for this interrupt
+ */
+ while (!(read_interrupt_status(denali) &
+ INTR_STATUS__ECC_TRANSACTION_DONE))
+ cpu_relax();
+ clear_interrupts(denali);
+ denali_set_intr_modes(denali, true);
+
+ out:
*max_bitflips = bitflips;
return check_erased_page;
}
--
2.7.4
Currently, it is valid to specify both "nand-ecc-step-size" and
"nand-ecc-strength", but not allowed to set only one of them.
This requirement has a conflict with "nand-ecc-maximize"; this flag
is used when you want the driver to choose the best ECC strength.
If "nand-ecc-maximize" is set, "nand-ecc-strength" is very likely to
be unset.
It would be possible to make the if-conditional more complex by
adding the check for the NAND_ECC_MAXIMIZE flag, but I chose to drop
the check entirely. I thought of the situation where the hardware
has a fixed ECC step size (so it can be hard-coded in the driver),
whereas the ECC strength is configurable by software. In that case,
we may want to only set "nand-ecc-strength" (or "nand-ecc-maximize")
in DT.
Signed-off-by: Masahiro Yamada <[email protected]>
---
The Denali NAND is the case.
The ecc.size is fixed when the RTL is delivered, while the
driver can choose ecc.strength from some supported values.
For Intel and Altera, available ecc.strength are 8, 15.
For Socionext UniPhier, available ecc.strength are 8, 16, 24.
drivers/mtd/nand/nand_base.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8c74d8c..c1ed91d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4266,12 +4266,6 @@ static int nand_dt_init(struct nand_chip *chip)
ecc_strength = of_get_nand_ecc_strength(dn);
ecc_step = of_get_nand_ecc_step_size(dn);
- if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
- (!(ecc_step >= 0) && ecc_strength >= 0)) {
- pr_err("must set both strength and step size in DT\n");
- return -EINVAL;
- }
-
if (ecc_mode >= 0)
chip->ecc.mode = ecc_mode;
--
2.7.4
The function write_oob_data() performs write access to the spare
area, so passing "false" to the 3rd argument (transfer_spare) of
denali_send_pipeline_cmd() is weird.
Actually, the transfer_spare is ignored for MAP10 operation with
SPARE_ACCESS (0x41), so this change has no impact on the hardware
behavior. Yet, we should keep our code to make sense.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 61e1e33..b2b050b 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -834,7 +834,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
denali->page = page;
- if (denali_send_pipeline_cmd(denali, false, false, SPARE_ACCESS,
+ if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
DENALI_WRITE) == PASS) {
write_data_to_flash_mem(denali, buf, mtd->oobsize);
--
2.7.4
This will make the code shorter and avoid 80 columns wrap-around
in some places.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 188 ++++++++++++++++++++++------------------------
drivers/mtd/nand/denali.h | 12 +--
2 files changed, 95 insertions(+), 105 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 4cc8945..a7dc692 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -104,11 +104,9 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
/* forward declarations */
static void clear_interrupts(struct denali_nand_info *denali);
-static uint32_t wait_for_irq(struct denali_nand_info *denali,
- uint32_t irq_mask);
-static void denali_irq_enable(struct denali_nand_info *denali,
- uint32_t int_mask);
-static uint32_t read_interrupt_status(struct denali_nand_info *denali);
+static u32 wait_for_irq(struct denali_nand_info *denali, u32 irq_mask);
+static void denali_irq_enable(struct denali_nand_info *denali, u32 int_mask);
+static u32 read_interrupt_status(struct denali_nand_info *denali);
/*
* Certain operations for the denali NAND controller use an indexed mode to
@@ -116,8 +114,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali);
* of the command to the device memory followed by the data. This function
* abstracts this common operation.
*/
-static void index_addr(struct denali_nand_info *denali,
- uint32_t address, uint32_t data)
+static void index_addr(struct denali_nand_info *denali, u32 address, u32 data)
{
iowrite32(address, denali->flash_mem);
iowrite32(data, denali->flash_mem + 0x10);
@@ -125,7 +122,7 @@ static void index_addr(struct denali_nand_info *denali,
/* Perform an indexed read of the device */
static void index_addr_read_data(struct denali_nand_info *denali,
- uint32_t address, uint32_t *pdata)
+ u32 address, u32 *pdata)
{
iowrite32(address, denali->flash_mem);
*pdata = ioread32(denali->flash_mem + 0x10);
@@ -140,7 +137,7 @@ static void reset_buf(struct denali_nand_info *denali)
denali->buf.head = denali->buf.tail = 0;
}
-static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
+static void write_byte_to_buf(struct denali_nand_info *denali, u8 byte)
{
denali->buf.buf[denali->buf.tail++] = byte;
}
@@ -148,7 +145,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
/* reads the status of the device */
static void read_status(struct denali_nand_info *denali)
{
- uint32_t cmd;
+ u32 cmd;
/* initialize the data buffer to store status */
reset_buf(denali);
@@ -163,8 +160,8 @@ static void read_status(struct denali_nand_info *denali)
/* resets a specific device connected to the core */
static void reset_bank(struct denali_nand_info *denali)
{
- uint32_t irq_status;
- uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
+ u32 irq_status;
+ u32 irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
clear_interrupts(denali);
@@ -177,7 +174,7 @@ static void reset_bank(struct denali_nand_info *denali)
}
/* Reset the flash controller */
-static uint16_t denali_nand_reset(struct denali_nand_info *denali)
+static u16 denali_nand_reset(struct denali_nand_info *denali)
{
int i;
@@ -208,27 +205,26 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
* programs the clocking register accordingly. The mode is determined by
* the get_onfi_nand_para routine.
*/
-static void nand_onfi_timing_set(struct denali_nand_info *denali,
- uint16_t mode)
+static void nand_onfi_timing_set(struct denali_nand_info *denali, u16 mode)
{
- uint16_t Trea[6] = {40, 30, 25, 20, 20, 16};
- uint16_t Trp[6] = {50, 25, 17, 15, 12, 10};
- uint16_t Treh[6] = {30, 15, 15, 10, 10, 7};
- uint16_t Trc[6] = {100, 50, 35, 30, 25, 20};
- uint16_t Trhoh[6] = {0, 15, 15, 15, 15, 15};
- uint16_t Trloh[6] = {0, 0, 0, 0, 5, 5};
- uint16_t Tcea[6] = {100, 45, 30, 25, 25, 25};
- uint16_t Tadl[6] = {200, 100, 100, 100, 70, 70};
- uint16_t Trhw[6] = {200, 100, 100, 100, 100, 100};
- uint16_t Trhz[6] = {200, 100, 100, 100, 100, 100};
- uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60};
- uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15};
-
- uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid;
- uint16_t dv_window = 0;
- uint16_t en_lo, en_hi;
- uint16_t acc_clks;
- uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
+ u16 Trea[6] = {40, 30, 25, 20, 20, 16};
+ u16 Trp[6] = {50, 25, 17, 15, 12, 10};
+ u16 Treh[6] = {30, 15, 15, 10, 10, 7};
+ u16 Trc[6] = {100, 50, 35, 30, 25, 20};
+ u16 Trhoh[6] = {0, 15, 15, 15, 15, 15};
+ u16 Trloh[6] = {0, 0, 0, 0, 5, 5};
+ u16 Tcea[6] = {100, 45, 30, 25, 25, 25};
+ u16 Tadl[6] = {200, 100, 100, 100, 70, 70};
+ u16 Trhw[6] = {200, 100, 100, 100, 100, 100};
+ u16 Trhz[6] = {200, 100, 100, 100, 100, 100};
+ u16 Twhr[6] = {120, 80, 80, 60, 60, 60};
+ u16 Tcs[6] = {70, 35, 25, 25, 20, 15};
+
+ u16 data_invalid_rhoh, data_invalid_rloh, data_invalid;
+ u16 dv_window = 0;
+ u16 en_lo, en_hi;
+ u16 acc_clks;
+ u16 addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
en_lo = CEIL_DIV(Trp[mode], CLK_X);
en_hi = CEIL_DIV(Treh[mode], CLK_X);
@@ -300,7 +296,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
}
/* queries the NAND device to see what ONFI modes it supports. */
-static uint16_t get_onfi_nand_para(struct denali_nand_info *denali)
+static u16 get_onfi_nand_para(struct denali_nand_info *denali)
{
int i;
@@ -330,8 +326,7 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali)
return PASS;
}
-static void get_samsung_nand_para(struct denali_nand_info *denali,
- uint8_t device_id)
+static void get_samsung_nand_para(struct denali_nand_info *denali, u8 device_id)
{
if (device_id == 0xd3) { /* Samsung K9WAG08U1A */
/* Set timing register values according to datasheet */
@@ -347,7 +342,7 @@ static void get_samsung_nand_para(struct denali_nand_info *denali,
static void get_toshiba_nand_para(struct denali_nand_info *denali)
{
- uint32_t tmp;
+ u32 tmp;
/*
* Workaround to fix a controller bug which reports a wrong
@@ -368,10 +363,9 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali)
}
}
-static void get_hynix_nand_para(struct denali_nand_info *denali,
- uint8_t device_id)
+static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
{
- uint32_t main_size, spare_size;
+ u32 main_size, spare_size;
switch (device_id) {
case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
@@ -408,7 +402,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
*/
static void find_valid_banks(struct denali_nand_info *denali)
{
- uint32_t id[denali->max_banks];
+ u32 id[denali->max_banks];
int i;
denali->total_used_banks = 1;
@@ -453,7 +447,7 @@ static void find_valid_banks(struct denali_nand_info *denali)
*/
static void detect_max_banks(struct denali_nand_info *denali)
{
- uint32_t features = ioread32(denali->flash_reg + FEATURES);
+ u32 features = ioread32(denali->flash_reg + FEATURES);
/*
* Read the revision register, so we can calculate the max_banks
* properly: the encoding changed from rev 5.0 to 5.1
@@ -467,11 +461,11 @@ static void detect_max_banks(struct denali_nand_info *denali)
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
}
-static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
+static u16 denali_nand_timing_set(struct denali_nand_info *denali)
{
- uint16_t status = PASS;
- uint32_t id_bytes[8], addr;
- uint8_t maf_id, device_id;
+ u16 status = PASS;
+ u32 id_bytes[8], addr;
+ u8 maf_id, device_id;
int i;
/*
@@ -526,7 +520,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
}
static void denali_set_intr_modes(struct denali_nand_info *denali,
- uint16_t INT_ENABLE)
+ u16 INT_ENABLE)
{
if (INT_ENABLE)
iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
@@ -545,7 +539,7 @@ static inline bool is_flash_bank_valid(int flash_bank)
static void denali_irq_init(struct denali_nand_info *denali)
{
- uint32_t int_mask;
+ u32 int_mask;
int i;
/* Disable global interrupts */
@@ -565,8 +559,7 @@ static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
denali_set_intr_modes(denali, false);
}
-static void denali_irq_enable(struct denali_nand_info *denali,
- uint32_t int_mask)
+static void denali_irq_enable(struct denali_nand_info *denali, u32 int_mask)
{
int i;
@@ -578,16 +571,16 @@ static void denali_irq_enable(struct denali_nand_info *denali,
* This function only returns when an interrupt that this driver cares about
* occurs. This is to reduce the overhead of servicing interrupts
*/
-static inline uint32_t denali_irq_detected(struct denali_nand_info *denali)
+static inline u32 denali_irq_detected(struct denali_nand_info *denali)
{
return read_interrupt_status(denali) & DENALI_IRQ_ALL;
}
/* Interrupts are cleared by writing a 1 to the appropriate status bit */
static inline void clear_interrupt(struct denali_nand_info *denali,
- uint32_t irq_mask)
+ u32 irq_mask)
{
- uint32_t intr_status_reg;
+ u32 intr_status_reg;
intr_status_reg = INTR_STATUS(denali->flash_bank);
@@ -596,7 +589,7 @@ static inline void clear_interrupt(struct denali_nand_info *denali,
static void clear_interrupts(struct denali_nand_info *denali)
{
- uint32_t status;
+ u32 status;
spin_lock_irq(&denali->irq_lock);
@@ -607,9 +600,9 @@ static void clear_interrupts(struct denali_nand_info *denali)
spin_unlock_irq(&denali->irq_lock);
}
-static uint32_t read_interrupt_status(struct denali_nand_info *denali)
+static u32 read_interrupt_status(struct denali_nand_info *denali)
{
- uint32_t intr_status_reg;
+ u32 intr_status_reg;
intr_status_reg = INTR_STATUS(denali->flash_bank);
@@ -623,7 +616,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali)
static irqreturn_t denali_isr(int irq, void *dev_id)
{
struct denali_nand_info *denali = dev_id;
- uint32_t irq_status;
+ u32 irq_status;
irqreturn_t result = IRQ_NONE;
spin_lock(&denali->irq_lock);
@@ -654,10 +647,10 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
return result;
}
-static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
+static u32 wait_for_irq(struct denali_nand_info *denali, u32 irq_mask)
{
unsigned long comp_res;
- uint32_t intr_status;
+ u32 intr_status;
unsigned long timeout = msecs_to_jiffies(1000);
do {
@@ -717,8 +710,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
int access_type, int op)
{
int status = PASS;
- uint32_t page_count = 1;
- uint32_t addr, cmd, irq_status, irq_mask;
+ u32 page_count = 1;
+ u32 addr, cmd, irq_status, irq_mask;
if (op == DENALI_READ)
irq_mask = INTR_STATUS__LOAD_COMP;
@@ -783,9 +776,9 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
/* helper function that simply writes a buffer to the flash */
static int write_data_to_flash_mem(struct denali_nand_info *denali,
- const uint8_t *buf, int len)
+ const u8 *buf, int len)
{
- uint32_t *buf32;
+ u32 *buf32;
int i;
/*
@@ -795,7 +788,7 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali,
BUG_ON((len % 4) != 0);
/* write the data to the flash memory */
- buf32 = (uint32_t *)buf;
+ buf32 = (u32 *)buf;
for (i = 0; i < len / 4; i++)
iowrite32(*buf32++, denali->flash_mem + 0x10);
return i * 4; /* intent is to return the number of bytes read */
@@ -803,9 +796,9 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali,
/* helper function that simply reads a buffer from the flash */
static int read_data_from_flash_mem(struct denali_nand_info *denali,
- uint8_t *buf, int len)
+ u8 *buf, int len)
{
- uint32_t *buf32;
+ u32 *buf32;
int i;
/*
@@ -817,19 +810,18 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali,
BUG_ON((len % 4) != 0);
/* transfer the data from the flash */
- buf32 = (uint32_t *)buf;
+ buf32 = (u32 *)buf;
for (i = 0; i < len / 4; i++)
*buf32++ = ioread32(denali->flash_mem + 0x10);
return i * 4; /* intent is to return the number of bytes read */
}
/* writes OOB data to the device */
-static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+static int write_oob_data(struct mtd_info *mtd, u8 *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
- uint32_t irq_status;
- uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
- INTR_STATUS__PROGRAM_FAIL;
+ u32 irq_status;
+ u32 irq_mask = INTR_STATUS__PROGRAM_COMP | INTR_STATUS__PROGRAM_FAIL;
int status = 0;
denali->page = page;
@@ -853,11 +845,11 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
}
/* reads OOB data from the device */
-static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+static void read_oob_data(struct mtd_info *mtd, u8 *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
- uint32_t irq_mask = INTR_STATUS__LOAD_COMP;
- uint32_t irq_status, addr, cmd;
+ u32 irq_mask = INTR_STATUS__LOAD_COMP;
+ u32 irq_status, addr, cmd;
denali->page = page;
@@ -893,7 +885,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
* this function examines buffers to see if they contain data that
* indicate that the buffer is part of an erased region of flash.
*/
-static bool is_erased(uint8_t *buf, int len)
+static bool is_erased(u8 *buf, int len)
{
int i;
@@ -911,16 +903,16 @@ static bool is_erased(uint8_t *buf, int len)
#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
-static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
- uint32_t irq_status, unsigned int *max_bitflips)
+static bool handle_ecc(struct denali_nand_info *denali, u8 *buf,
+ u32 irq_status, unsigned int *max_bitflips)
{
bool check_erased_page = false;
unsigned int bitflips = 0;
if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */
- uint32_t err_address, err_correction_info, err_byte,
- err_sector, err_device, err_correction_value;
+ u32 err_address, err_correction_info, err_byte,
+ err_sector, err_device, err_correction_value;
denali_set_intr_modes(denali, false);
do {
@@ -993,9 +985,9 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en)
/* setups the HW to perform the data DMA */
static void denali_setup_dma(struct denali_nand_info *denali, int op)
{
- uint32_t mode;
+ u32 mode;
const int page_count = 1;
- uint32_t addr = denali->buf.dma_buf;
+ u32 addr = denali->buf.dma_buf;
mode = MODE_10 | BANK(denali->flash_bank);
@@ -1019,14 +1011,13 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
* configuration details.
*/
static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, bool raw_xfer)
+ const u8 *buf, bool raw_xfer)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
- uint32_t irq_status;
- uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
- INTR_STATUS__PROGRAM_FAIL;
+ u32 irq_status;
+ u32 irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL;
/*
* if it is a raw xfer, we want to disable ecc and send the spare area.
@@ -1075,7 +1066,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
* by write_page above.
*/
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+ const u8 *buf, int oob_required, int page)
{
/*
* for regular page writes, we let HW handle all the ECC
@@ -1090,7 +1081,7 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
* write_page() function above.
*/
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
+ const u8 *buf, int oob_required,
int page)
{
/*
@@ -1115,7 +1106,7 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
}
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+ u8 *buf, int oob_required, int page)
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);
@@ -1123,9 +1114,8 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
- uint32_t irq_status;
- uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
- INTR_STATUS__ECC_ERR;
+ u32 irq_status;
+ u32 irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
bool check_erased_page = false;
if (page != denali->page) {
@@ -1169,12 +1159,12 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+ u8 *buf, int oob_required, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
- uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
+ u32 irq_mask = INTR_STATUS__DMA_CMD_COMP;
if (page != denali->page) {
dev_err(denali->dev,
@@ -1206,10 +1196,10 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static u8 denali_read_byte(struct mtd_info *mtd)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
- uint8_t result = 0xff;
+ u8 result = 0xff;
if (denali->buf.head < denali->buf.tail)
result = denali->buf.buf[denali->buf.head++];
@@ -1240,7 +1230,7 @@ static int denali_erase(struct mtd_info *mtd, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
- uint32_t cmd, irq_status;
+ u32 cmd, irq_status;
clear_interrupts(denali);
@@ -1259,7 +1249,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
- uint32_t addr, id;
+ u32 addr, id;
int i;
switch (cmd) {
@@ -1370,8 +1360,8 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
.free = denali_ooblayout_free,
};
-static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
static struct nand_bbt_descr bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 95ed32e..69314d0 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -391,7 +391,7 @@
struct nand_buf {
int head;
int tail;
- uint8_t *buf;
+ u8 *buf;
dma_addr_t dma_buf;
};
@@ -407,19 +407,19 @@ struct denali_nand_info {
struct nand_buf buf;
struct device *dev;
int total_used_banks;
- uint16_t page;
+ u16 page;
void __iomem *flash_reg; /* Register Interface */
void __iomem *flash_mem; /* Host Data/Command Interface */
/* elements used by ISR */
struct completion complete;
spinlock_t irq_lock;
- uint32_t irq_status;
+ u32 irq_status;
int irq;
- uint32_t devnum; /* represent how many nands connected */
- uint32_t bbtskipbytes;
- uint32_t max_banks;
+ u32 devnum; /* represent how many nands connected */
+ u32 bbtskipbytes;
+ u32 max_banks;
unsigned int caps;
};
--
2.7.4
When uncorrectable ECC error happens, whether the page is erased or
not, the ecc.read_page() should return zero.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index ae9a8d2..a6445d9 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1160,6 +1160,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
if (!is_erased(buf, mtd->writesize) ||
!is_erased(chip->oob_poi, mtd->oobsize))
mtd->ecc_stats.failed++;
+ return 0;
}
return max_bitflips;
}
--
2.7.4
This macro is defined twice in denali.c (around line 103 and
line 656), so remove the second one.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 9b3140f..61e1e33 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -653,7 +653,6 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
spin_unlock(&denali->irq_lock);
return result;
}
-#define BANK(x) ((x) << 24)
static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
{
--
2.7.4
All of these macros are not used at all.
CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR is not used for anything but
defining SCRATCH_REG_ADDR. The config option should go away as well.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/Kconfig | 11 -----------
drivers/mtd/nand/denali.h | 42 ------------------------------------------
2 files changed, 53 deletions(-)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..5eb643e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -60,17 +60,6 @@ config MTD_NAND_DENALI_DT
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
-config MTD_NAND_DENALI_SCRATCH_REG_ADDR
- hex "Denali NAND size scratch register address"
- default "0xFF108018"
- depends on MTD_NAND_DENALI_PCI
- help
- Some platforms place the NAND chip size in a scratch register
- because (some versions of) the driver aren't able to automatically
- determine the size of certain chips. Set the address of the
- scratch register here to enable this feature. On Intel Moorestown
- boards, the scratch register is at 0xFF108018.
-
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index ea22191..fd1ae08 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -367,33 +367,16 @@
#define MIN_MAX_BANK__MIN_VALUE 0x0003
#define MIN_MAX_BANK__MAX_VALUE 0x000c
-
-/* ffsdefs.h */
-#define CLEAR 0 /*use this to clear a field instead of "fail"*/
-#define SET 1 /*use this to set a field instead of "pass"*/
#define FAIL 1 /*failed flag*/
#define PASS 0 /*success flag*/
#define ERR -1 /*error flag*/
-/* lld.h */
-#define GOOD_BLOCK 0
-#define DEFECTIVE_BLOCK 1
-#define READ_ERROR 2
-
#define CLK_X 5
#define CLK_MULTI 4
-/* KBV - Updated to LNW scratch register address */
-#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
-#define SCRATCH_REG_SIZE 64
-
-#define GLOB_HWCTL_DEFAULT_BLKS 2048
-
#define SUPPORT_15BITECC 1
#define SUPPORT_8BITECC 1
-#define CUSTOM_CONF_PARAMS 0
-
#define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0
@@ -403,31 +386,6 @@
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
-
-#define DATA_TRANSFER_MODE 0
-#define PROTECTION_PER_BLOCK 1
-#define LOAD_WAIT_COUNT 2
-#define PROGRAM_WAIT_COUNT 3
-#define ERASE_WAIT_COUNT 4
-#define INT_MONITOR_CYCLE_COUNT 5
-#define READ_BUSY_PIN_ENABLED 6
-#define MULTIPLANE_OPERATION_SUPPORT 7
-#define PRE_FETCH_MODE 8
-#define CE_DONT_CARE_SUPPORT 9
-#define COPYBACK_SUPPORT 10
-#define CACHE_WRITE_SUPPORT 11
-#define CACHE_READ_SUPPORT 12
-#define NUM_PAGES_IN_BLOCK 13
-#define ECC_ENABLE_SELECT 14
-#define WRITE_ENABLE_2_READ_ENABLE 15
-#define ADDRESS_2_DATA 16
-#define READ_ENABLE_2_WRITE_ENABLE 17
-#define TWO_ROW_ADDRESS_CYCLES 18
-#define MULTIPLANE_ADDRESS_RESTRICT 19
-#define ACC_CLOCKS 20
-#define READ_WRITE_ENABLE_LOW_COUNT 21
-#define READ_WRITE_ENABLE_HIGH_COUNT 22
-
#define ECC_SECTOR_SIZE 512
struct nand_buf {
--
2.7.4
This will be needed in the next commit to call denali_read_page_raw()
from denali_read_page().
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 76 +++++++++++++++++++++++------------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index c101e7f..f035dac 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1118,6 +1118,44 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
+static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ dma_addr_t addr = denali->buf.dma_buf;
+ size_t size = mtd->writesize + mtd->oobsize;
+ u32 irq_mask = INTR_STATUS__DMA_CMD_COMP;
+
+ if (page != denali->page) {
+ dev_err(denali->dev,
+ "IN %s: page %d is not equal to denali->page %d",
+ __func__, page, denali->page);
+ BUG();
+ }
+
+ setup_ecc_for_xfer(denali, false, oob_required ? true : false);
+ denali_enable_dma(denali, true);
+
+ dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
+
+ clear_interrupts(denali);
+ denali_setup_dma(denali, DENALI_READ);
+
+ /* wait for operation to complete */
+ wait_for_irq(denali, irq_mask);
+
+ dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
+
+ denali_enable_dma(denali, false);
+
+ memcpy(buf, denali->buf.buf, mtd->writesize);
+ if (oob_required)
+ memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize,
+ mtd->oobsize);
+
+ return 0;
+}
+
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page)
{
@@ -1182,44 +1220,6 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips;
}
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
-{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
- dma_addr_t addr = denali->buf.dma_buf;
- size_t size = mtd->writesize + mtd->oobsize;
- u32 irq_mask = INTR_STATUS__DMA_CMD_COMP;
-
- if (page != denali->page) {
- dev_err(denali->dev,
- "IN %s: page %d is not equal to denali->page %d",
- __func__, page, denali->page);
- BUG();
- }
-
- setup_ecc_for_xfer(denali, false, oob_required ? true : false);
- denali_enable_dma(denali, true);
-
- dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
-
- clear_interrupts(denali);
- denali_setup_dma(denali, DENALI_READ);
-
- /* wait for operation to complete */
- wait_for_irq(denali, irq_mask);
-
- dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
-
- denali_enable_dma(denali, false);
-
- memcpy(buf, denali->buf.buf, mtd->writesize);
- if (oob_required)
- memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize,
- mtd->oobsize);
-
- return 0;
-}
-
static u8 denali_read_byte(struct mtd_info *mtd)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
--
2.7.4
Commit 271707b1d817 ("mtd: nand: denali: max_banks calculation
changed in revision 5.1") added a revision check to support the
new max_banks encoding. Its git-log states "The encoding of
max_banks changed in Denali revision 5.1" but I doubt it.
The revision register on some UniPhier SoCs says the IP is 5.0
but the max_banks is encoded in the new format. The revision of
this IP is often useless.
In order to provide a way to calculate correct max_banks without
relying on the revision register, add DENALI_CAPS_NEW_N_BANKS_FORMAT
capability (quirk).
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 24 +++++++++++++++++-------
drivers/mtd/nand/denali.h | 1 +
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 752ad98..614b4a5 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -448,17 +448,27 @@ static void find_valid_banks(struct denali_nand_info *denali)
static void detect_max_banks(struct denali_nand_info *denali)
{
u32 features = ioread32(denali->flash_reg + FEATURES);
+ bool old_format;
+
/*
- * Read the revision register, so we can calculate the max_banks
- * properly: the encoding changed from rev 5.0 to 5.1
+ * There are some IP versions with different n_banks encoding.
+ * Some people say the change happened from rev 5.0 to 5.1, while
+ * there exist variants with revision older than 5.1 but new encoding.
+ * The option flag is available in case the revision is useless.
*/
- u32 revision = MAKE_COMPARABLE_REVISION(
+ if (denali->caps & DENALI_CAPS_NEW_N_BANKS_FORMAT)
+ old_format = false;
+ else {
+ u32 revision = MAKE_COMPARABLE_REVISION(
ioread32(denali->flash_reg + REVISION));
- if (revision < REVISION_5_1)
- denali->max_banks = 2 << (features & FEATURES__N_BANKS);
- else
- denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+ old_format = revision < REVISION_5_1;
+ }
+
+ denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+
+ if (old_format)
+ denali->max_banks <<= 1;
}
static u16 denali_nand_timing_set(struct denali_nand_info *denali)
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 9bdf037..e3fe3bc 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -436,6 +436,7 @@ struct denali_nand_info {
unsigned int caps;
#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
#define DENALI_CAPS_DMA_64BIT BIT(1)
+#define DENALI_CAPS_NEW_N_BANKS_FORMAT BIT(2)
};
extern int denali_init(struct denali_nand_info *denali);
--
2.7.4
The ecc.strength of this IP is a platform-dependent parameter.
I chose {15, 8} as the default to respect the historical reason of
this driver, but it should be overridable to use this driver for
other SoCs.
If necessary, SoCs can provide their own ecc_strength_avail.
This must be an array of supported ecc.strength in descending order,
terminated by zero.
Signed-off-by: Masahiro Yamada <[email protected]>
---
drivers/mtd/nand/denali.c | 5 ++++-
drivers/mtd/nand/denali.h | 1 +
drivers/mtd/nand/denali_dt.c | 5 ++++-
3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index f2ed3f8..54c9e0c 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1373,7 +1373,7 @@ static int denali_set_max_ecc_strength(struct denali_nand_info *denali)
int oobsize = mtd->oobsize;
int ecc_size = chip->ecc.size;
int ecc_steps = mtd->writesize / chip->ecc.size;
- const int *ecc_strength = denali_default_ecc_strength;
+ const int *ecc_strength = denali->ecc_strength_avail;
int ecc_bytes;
/* carve out the BBM area */
@@ -1625,6 +1625,9 @@ int denali_init(struct denali_nand_info *denali)
chip->ecc.size = denali->caps & DENALI_CAPS_ECC_SIZE_1024 ?
1024 : 512;
+ if (!denali->ecc_strength_avail)
+ denali->ecc_strength_avail = denali_default_ecc_strength;
+
ret = denali_set_max_ecc_strength(denali);
if (ret)
goto failed_req_irq;
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 5209625..2892e46 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -428,6 +428,7 @@ struct denali_nand_info {
u32 devnum; /* represent how many nands connected */
u32 bbtskipbytes;
u32 max_banks;
+ const int *ecc_strength_avail;
unsigned int caps;
#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
#define DENALI_CAPS_DMA_64BIT BIT(1)
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index f085626..aa1e032 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -30,6 +30,7 @@ struct denali_dt {
};
struct denali_dt_data {
+ const int *ecc_strength_avail;
unsigned int caps;
};
@@ -54,8 +55,10 @@ static int denali_dt_probe(struct platform_device *pdev)
denali = &dt->denali;
data = of_device_get_match_data(&pdev->dev);
- if (data)
+ if (data) {
+ denali->ecc_strength_avail = data->ecc_strength_avail;
denali->caps = data->caps;
+ }
denali->caps |= DENALI_CAPS_HW_ECC_FIXUP;
--
2.7.4
On Sun, 27 Nov 2016 03:05:47 +0900
Masahiro Yamada <[email protected]> wrote:
> Currently, it is valid to specify both "nand-ecc-step-size" and
> "nand-ecc-strength", but not allowed to set only one of them.
>
> This requirement has a conflict with "nand-ecc-maximize"; this flag
> is used when you want the driver to choose the best ECC strength.
> If "nand-ecc-maximize" is set, "nand-ecc-strength" is very likely to
> be unset.
Well, when I added nand-ecc-maximize I was assuming that the driver
would choose both step-size and strength to maximize the ECC strength
on the whole page, but you're right, we might need fine-grained
tweaking (forcing the step-size but letting the driver choose the ECC
strength).
>
> It would be possible to make the if-conditional more complex by
> adding the check for the NAND_ECC_MAXIMIZE flag, but I chose to drop
> the check entirely. I thought of the situation where the hardware
> has a fixed ECC step size (so it can be hard-coded in the driver),
> whereas the ECC strength is configurable by software. In that case,
> we may want to only set "nand-ecc-strength" (or "nand-ecc-maximize")
> in DT.
I would also add that checking things at this level is not really
relevant. The driver is likely to check the ecc.size and ecc.strength
values anyway, and pick a default value (chip->nand_ecc_xx_ds or some
hard-coded values if the ECC engine only support one specific case) if
one of them is unassigned (left to 0).
I'll let some time for others to review before queuing this patch for
4.11.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> The Denali NAND is the case.
>
> The ecc.size is fixed when the RTL is delivered, while the
> driver can choose ecc.strength from some supported values.
>
> For Intel and Altera, available ecc.strength are 8, 15.
> For Socionext UniPhier, available ecc.strength are 8, 16, 24.
>
>
> drivers/mtd/nand/nand_base.c | 6 ------
> 1 file changed, 6 deletions(-)
>
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index 8c74d8c..c1ed91d 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -4266,12 +4266,6 @@ static int nand_dt_init(struct nand_chip *chip)
> ecc_strength = of_get_nand_ecc_strength(dn);
> ecc_step = of_get_nand_ecc_step_size(dn);
>
> - if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
> - (!(ecc_step >= 0) && ecc_strength >= 0)) {
> - pr_err("must set both strength and step size in DT\n");
> - return -EINVAL;
> - }
> -
> if (ecc_mode >= 0)
> chip->ecc.mode = ecc_mode;
>
+Andy
Hi Masahiro,
On Sun, 27 Nov 2016 03:05:46 +0900
Masahiro Yamada <[email protected]> wrote:
> As I said in the 1st round series, I am tackling on this driver
> to use it for my SoCs.
>
> The previous series was just cosmetic things, but this series
> includes *real* changes.
>
> After some more cleanups, I will start to add changes that
> are really necessary.
> One of the biggest problems I want to solve is a bunch of
> hard-coded parameters that prevent me from using this driver for
> my SoCs.
>
> I will introduce capability flags that are associated with DT
> compatible and make platform-dependent parameters overridable.
>
> I still have lots of reworks to get done (so probably 3rd round
> series will come), but I hope it is getting better and
> I am showing a big picture now.
>
Thanks for posting this 2nd round of patches, I know have a clearer
view of what you're trying to achieve.
Could you be a bit more specific about the remaining rework (your 3rd
round)?
Also, if you don't mind, I'd like to have reviews and testing from intel
users before applying the series. Can you Cc Andy (and possibly other
intel maintainers) for the next round.
Thanks,
Boris
>
>
> Masahiro Yamada (39):
> mtd: nand: allow to set only one of ECC size and ECC strength from DT
> mtd: nand: denali: remove unused CONFIG option and macros
> mtd: nand: denali: remove redundant define of BANK(x)
> mtd: nand: denali: remove more unused struct members
> mtd: nand: denali: fix comment of denali_nand_info::flash_mem
> mtd: nand: denali: fix write_oob_data() function
> mtd: nand: denali: transfer OOB only when oob_required is set
> mtd: nand: denali: introduce capability flag
> mtd: nand: denali: fix erased page check code
> mtd: nand: denali: remove redundant if conditional of erased_check
> mtd: nand: denali: increment ecc_stats.failed by one per error
> mtd: nand: denali: return 0 for uncorrectable ECC error
> mtd: nand: denali: increment ecc_stats->corrected
> mtd: nand: denali: replace uint{8/16/32}_t with u{8/16/32}
> mtd: nand: denali: improve readability of handle_ecc()
> mtd: nand: denali: rename handle_ecc() to denali_sw_ecc_fixup()
> mtd: nand: denali: support HW_ECC_FIXUP capability
> mtd: nand: denali: move denali_read_page_raw() above
> denali_read_page()
> mtd: nand: denali: perform erased check against raw transferred page
> mtd: nand: denali_dt: enable HW_ECC_FIXUP capability for DT platform
> mtd: nand: denali: support 64bit capable DMA engine
> mtd: nand: denali_dt: remove dma-mask DT property
> mtd: nand: denali_dt: use pdev instead of ofdev for platform_device
> mtd: nand: denali: add NEW_N_BANKS_FORMAT capability
> mtd: nand: denali: use nand_chip to hold frequently accessed data
> mtd: nand: denali: call nand_set_flash_node() to set DT node
> mtd: nand: denali: do not set mtd->name
> mtd: nand: denali: move multi NAND fixup code to a helper function
> mtd: nand: denali: refactor multi NAND fixup code in more generic way
> mtd: nand: denali: set DEVICES_CONNECTED 1 if not set
> mtd: nand: denali: remove meaningless writes to read-only registers
> mtd: nand: denali: remove unnecessary writes to ECC_CORRECTION
> mtd: nand: denali: support 1024 byte ECC step size
> mtd: nand: denali: fix the condition for 15 bit ECC strength
> mtd: nand: denali: calculate ecc.strength and ecc.bytes generically
> mtd: nand: denali: allow to use SoC-specific ECC strength
> mtd: nand: denali: support "nand-ecc-strength" DT property
> mtd: nand: denali: remove Toshiba, Hynix specific fixup code
> mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
>
> .../devicetree/bindings/mtd/denali-nand.txt | 19 +-
> drivers/mtd/nand/Kconfig | 11 -
> drivers/mtd/nand/denali.c | 740 ++++++++++++---------
> drivers/mtd/nand/denali.h | 84 +--
> drivers/mtd/nand/denali_dt.c | 95 ++-
> drivers/mtd/nand/denali_pci.c | 2 +
> drivers/mtd/nand/nand_base.c | 6 -
> 7 files changed, 515 insertions(+), 442 deletions(-)
>
On Sun, 27 Nov 2016 03:05:50 +0900
Masahiro Yamada <[email protected]> wrote:
Please add a description here.
Also, this commit tends to validate my fears: you should have wait for
the full rework/cleanup to be done before submitting the first round of
cleanups. Indeed, commit c4ae0977f57d ("mtd: nand: denali: remove unused
struct member denali_nand_info::idx") was removing one of these unused
fields, leaving 2 of them behind.
While I like when things I clearly separated in different commits, when
you push the logic too far, you end up with big series which are not
necessarily easier to review, and several commits that are achieving
the same goal...
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.h | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
> index fd1ae08..4fad43b 100644
> --- a/drivers/mtd/nand/denali.h
> +++ b/drivers/mtd/nand/denali.h
> @@ -407,7 +407,6 @@ struct denali_nand_info {
> struct nand_buf buf;
> struct device *dev;
> int total_used_banks;
> - uint32_t block; /* stored for future use */
> uint16_t page;
> void __iomem *flash_reg; /* Mapped io reg base address */
> void __iomem *flash_mem; /* Mapped io reg base address */
> @@ -416,7 +415,6 @@ struct denali_nand_info {
> struct completion complete;
> spinlock_t irq_lock;
> uint32_t irq_status;
> - int irq_debug_array[32];
> int irq;
>
> uint32_t devnum; /* represent how many nands connected */
On Sun, 27 Nov 2016 03:05:55 +0900
Masahiro Yamada <[email protected]> wrote:
> Currently, is_erased() is called against "buf" twice, so the second
> call is meaningless. The second one should be checked against
> chip->oob_poi.
>
IMO, patch 9 to 12 should be squashed in a single patch. All you're
doing in these patch is fixing the check_erased_page logic.
You can describe the different broken thing in the commit message, but
splitting things as you do does not help much.
Also, please have at nand_check_erased_ecc_chunk() [1] instead of using
a private method (is_erased()) to check if the page is erased.
With this method you get bitflips in erased pages correction for free.
[1]http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_base.c#L1212
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index cbc7f75..753e9a02 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -1160,7 +1160,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> if (check_erased_page) {
> if (!is_erased(buf, mtd->writesize))
> mtd->ecc_stats.failed++;
> - if (!is_erased(buf, mtd->oobsize))
> + if (!is_erased(chip->oob_poi, mtd->oobsize))
> mtd->ecc_stats.failed++;
> }
> }
On Sun, 27 Nov 2016 03:05:59 +0900
Masahiro Yamada <[email protected]> wrote:
> Update the number of corrected bit flips when read_page() succeeds.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index a6445d9..4cc8945 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -1162,6 +1162,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> mtd->ecc_stats.failed++;
> return 0;
> }
> +
> + mtd->ecc_stats.corrected += max_bitflips;
First of all, ecc_stats.corrected should contain the total number of
bitflips detected on the MTD device, here you're just adding the
maximum number of bitflips per ECC chunk for the current page, which is
slightly different.
Then, ecc_stats.corrected seems to be properly updated in handle_ecc()
[1], so I see no reason to do it here.
[1]http://lxr.free-electrons.com/source/drivers/mtd/nand/denali.c#L1003
> +
> return max_bitflips;
> }
>
On Sun, 27 Nov 2016 03:06:01 +0900
Masahiro Yamada <[email protected]> wrote:
> This function is unreadable due to the deep nesting. Note this
> function does a job only when INTR_STATUS__ECC_ERR is set.
> So, if the flag is not set, let it bail-out.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 119 +++++++++++++++++++++++-----------------------
> 1 file changed, 59 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index a7dc692..b577560 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -908,69 +908,68 @@ static bool handle_ecc(struct denali_nand_info *denali, u8 *buf,
> {
> bool check_erased_page = false;
> unsigned int bitflips = 0;
> + u32 err_address, err_correction_info, err_byte, err_sector, err_device,
> + err_correction_value;
Please use single line definitions for local variables:
u32 err_address, err_correction_info, err_byte, err_sector;
u32 err_device, err_correction_value;
Also, maybe you should use shorter names to avoid 80 chars wrapping as
much as possible.
>
> - if (irq_status & INTR_STATUS__ECC_ERR) {
> - /* read the ECC errors. we'll ignore them for now */
> - u32 err_address, err_correction_info, err_byte,
> - err_sector, err_device, err_correction_value;
> - denali_set_intr_modes(denali, false);
> -
> - do {
> - err_address = ioread32(denali->flash_reg +
> - ECC_ERROR_ADDRESS);
> - err_sector = ECC_SECTOR(err_address);
> - err_byte = ECC_BYTE(err_address);
> -
> - err_correction_info = ioread32(denali->flash_reg +
> - ERR_CORRECTION_INFO);
> - err_correction_value =
> + if (!(irq_status & INTR_STATUS__ECC_ERR))
> + goto out;
> +
> + /* read the ECC errors. we'll ignore them for now */
> + denali_set_intr_modes(denali, false);
> +
> + do {
> + err_address = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
> + err_sector = ECC_SECTOR(err_address);
> + err_byte = ECC_BYTE(err_address);
> +
> + err_correction_info = ioread32(denali->flash_reg +
> + ERR_CORRECTION_INFO);
> + err_correction_value =
> ECC_CORRECTION_VALUE(err_correction_info);
> - err_device = ECC_ERR_DEVICE(err_correction_info);
> -
> - if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
> - /*
> - * If err_byte is larger than ECC_SECTOR_SIZE,
> - * means error happened in OOB, so we ignore
> - * it. It's no need for us to correct it
> - * err_device is represented the NAND error
> - * bits are happened in if there are more
> - * than one NAND connected.
> - */
> - if (err_byte < ECC_SECTOR_SIZE) {
> - struct mtd_info *mtd =
> - nand_to_mtd(&denali->nand);
> - int offset;
> -
> - offset = (err_sector *
> - ECC_SECTOR_SIZE +
> - err_byte) *
> - denali->devnum +
> - err_device;
> - /* correct the ECC error */
> - buf[offset] ^= err_correction_value;
> - mtd->ecc_stats.corrected++;
> - bitflips++;
> - }
> - } else {
> - /*
> - * if the error is not correctable, need to
> - * look at the page to see if it is an erased
> - * page. if so, then it's not a real ECC error
> - */
> - check_erased_page = true;
> + err_device = ECC_ERR_DEVICE(err_correction_info);
> +
> + if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
> + /*
> + * If err_byte is larger than ECC_SECTOR_SIZE, means error
> + * happened in OOB, so we ignore it. It's no need for
> + * us to correct it err_device is represented the NAND
> + * error bits are happened in if there are more than
> + * one NAND connected.
> + */
> + if (err_byte < ECC_SECTOR_SIZE) {
> + struct mtd_info *mtd =
> + nand_to_mtd(&denali->nand);
> + int offset;
> +
> + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
> + denali->devnum + err_device;
> + /* correct the ECC error */
> + buf[offset] ^= err_correction_value;
> + mtd->ecc_stats.corrected++;
> + bitflips++;
> }
> - } while (!ECC_LAST_ERR(err_correction_info));
> - /*
> - * Once handle all ecc errors, controller will triger
> - * a ECC_TRANSACTION_DONE interrupt, so here just wait
> - * for a while for this interrupt
> - */
> - while (!(read_interrupt_status(denali) &
> - INTR_STATUS__ECC_TRANSACTION_DONE))
> - cpu_relax();
> - clear_interrupts(denali);
> - denali_set_intr_modes(denali, true);
> - }
> + } else {
> + /*
> + * if the error is not correctable, need to look at the
> + * page to see if it is an erased page. if so, then
> + * it's not a real ECC error
> + */
> + check_erased_page = true;
> + }
> + } while (!ECC_LAST_ERR(err_correction_info));
> +
> + /*
> + * Once handle all ecc errors, controller will triger a
> + * ECC_TRANSACTION_DONE interrupt, so here just wait for
> + * a while for this interrupt
> + */
> + while (!(read_interrupt_status(denali) &
> + INTR_STATUS__ECC_TRANSACTION_DONE))
> + cpu_relax();
> + clear_interrupts(denali);
> + denali_set_intr_modes(denali, true);
> +
> + out:
> *max_bitflips = bitflips;
> return check_erased_page;
> }
On Sun, 27 Nov 2016 03:06:01 +0900
Masahiro Yamada <[email protected]> wrote:
> This function is unreadable due to the deep nesting. Note this
> function does a job only when INTR_STATUS__ECC_ERR is set.
> So, if the flag is not set, let it bail-out.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 119 +++++++++++++++++++++++-----------------------
> 1 file changed, 59 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index a7dc692..b577560 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -908,69 +908,68 @@ static bool handle_ecc(struct denali_nand_info *denali, u8 *buf,
> {
> bool check_erased_page = false;
> unsigned int bitflips = 0;
> + u32 err_address, err_correction_info, err_byte, err_sector, err_device,
> + err_correction_value;
>
> - if (irq_status & INTR_STATUS__ECC_ERR) {
> - /* read the ECC errors. we'll ignore them for now */
> - u32 err_address, err_correction_info, err_byte,
> - err_sector, err_device, err_correction_value;
> - denali_set_intr_modes(denali, false);
> -
> - do {
> - err_address = ioread32(denali->flash_reg +
> - ECC_ERROR_ADDRESS);
> - err_sector = ECC_SECTOR(err_address);
> - err_byte = ECC_BYTE(err_address);
> -
> - err_correction_info = ioread32(denali->flash_reg +
> - ERR_CORRECTION_INFO);
> - err_correction_value =
> + if (!(irq_status & INTR_STATUS__ECC_ERR))
> + goto out;
> +
> + /* read the ECC errors. we'll ignore them for now */
> + denali_set_intr_modes(denali, false);
> +
> + do {
> + err_address = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
> + err_sector = ECC_SECTOR(err_address);
> + err_byte = ECC_BYTE(err_address);
> +
> + err_correction_info = ioread32(denali->flash_reg +
> + ERR_CORRECTION_INFO);
> + err_correction_value =
> ECC_CORRECTION_VALUE(err_correction_info);
> - err_device = ECC_ERR_DEVICE(err_correction_info);
> -
> - if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
> - /*
> - * If err_byte is larger than ECC_SECTOR_SIZE,
> - * means error happened in OOB, so we ignore
> - * it. It's no need for us to correct it
> - * err_device is represented the NAND error
> - * bits are happened in if there are more
> - * than one NAND connected.
> - */
> - if (err_byte < ECC_SECTOR_SIZE) {
> - struct mtd_info *mtd =
> - nand_to_mtd(&denali->nand);
> - int offset;
> -
> - offset = (err_sector *
> - ECC_SECTOR_SIZE +
> - err_byte) *
> - denali->devnum +
> - err_device;
> - /* correct the ECC error */
> - buf[offset] ^= err_correction_value;
> - mtd->ecc_stats.corrected++;
> - bitflips++;
> - }
> - } else {
> - /*
> - * if the error is not correctable, need to
> - * look at the page to see if it is an erased
> - * page. if so, then it's not a real ECC error
> - */
> - check_erased_page = true;
> + err_device = ECC_ERR_DEVICE(err_correction_info);
> +
> + if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
> + /*
> + * If err_byte is larger than ECC_SECTOR_SIZE, means error
> + * happened in OOB, so we ignore it. It's no need for
> + * us to correct it err_device is represented the NAND
> + * error bits are happened in if there are more than
> + * one NAND connected.
> + */
> + if (err_byte < ECC_SECTOR_SIZE) {
> + struct mtd_info *mtd =
> + nand_to_mtd(&denali->nand);
> + int offset;
> +
> + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
> + denali->devnum + err_device;
> + /* correct the ECC error */
> + buf[offset] ^= err_correction_value;
> + mtd->ecc_stats.corrected++;
> + bitflips++;
Hm, bitflips is what is set in max_bitflips, and apparently the
implementation (which is not yours) is not doing what the core expects.
You should first count bitflips per sector with something like that:
bitflips[err_sector]++;
And then once you've iterated over all errors do:
for (i = 0; i < nsectors; i++)
max_bitflips = max(bitflips[err_sector], max_bitflips);
> }
> - } while (!ECC_LAST_ERR(err_correction_info));
> - /*
> - * Once handle all ecc errors, controller will triger
> - * a ECC_TRANSACTION_DONE interrupt, so here just wait
> - * for a while for this interrupt
> - */
> - while (!(read_interrupt_status(denali) &
> - INTR_STATUS__ECC_TRANSACTION_DONE))
> - cpu_relax();
> - clear_interrupts(denali);
> - denali_set_intr_modes(denali, true);
> - }
> + } else {
> + /*
> + * if the error is not correctable, need to look at the
> + * page to see if it is an erased page. if so, then
> + * it's not a real ECC error
> + */
> + check_erased_page = true;
> + }
> + } while (!ECC_LAST_ERR(err_correction_info));
> +
> + /*
> + * Once handle all ecc errors, controller will triger a
> + * ECC_TRANSACTION_DONE interrupt, so here just wait for
> + * a while for this interrupt
> + */
> + while (!(read_interrupt_status(denali) &
> + INTR_STATUS__ECC_TRANSACTION_DONE))
> + cpu_relax();
> + clear_interrupts(denali);
> + denali_set_intr_modes(denali, true);
> +
> + out:
> *max_bitflips = bitflips;
> return check_erased_page;
> }
On Sun, 27 Nov 2016 03:06:03 +0900
Masahiro Yamada <[email protected]> wrote:
> Some old versions of the Denali IP (perhaps used only for Intel?)
> detects ECC errors and provides correct data via a register, but
> does not touch the transferred data. So, the software must fixup
> the data in the buffer according to the provided ECC correction
> information.
>
> Newer versions perform ECC correction before transferring the data.
> No more software intervention is needed. The ECC_ERROR_ADDRESS and
> ECC_CORRECTION_INFO registers were deprecated. Instead, the number
> of corrected bit-flips can be read from the ECC_COR_INFO register.
> When an uncorrectable ECC error happens, a status flag is set to the
> INTR_STATUS and ECC_COR_INFO registers.
>
> As is often the case with this IP, the register view of INTR_STATUS
> had broken compatibility.
>
> For older versions (SW ECC fixup):
> bit 0: ECC_TRANSACTION_DONE
> bit 1: ECC_ERR
>
> For newer versions (HW ECC fixup):
> bit 0: ECC_UNCOR_ERR
> bit 1: Reserved
>
> Due to this difference, the irq_mask must be fixed too. The comment
> block in the denali_sw_ecc_fixup() has been moved to the common part
> because the comment applies to both cases.
>
> The U-Boot port of this driver already supports the HW ECC fixup. I
> borrowed the comment "Some versions of ..." in denali.h from U-Boot.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 44 ++++++++++++++++++++++++++++++++++----------
> drivers/mtd/nand/denali.h | 14 ++++++++++++++
> 2 files changed, 48 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index 271b41a..c101e7f 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -894,6 +894,25 @@ static bool is_erased(u8 *buf, int len)
> return false;
> return true;
> }
> +
> +static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
> + unsigned int *max_bitflips)
> +{
> + int bank = denali->flash_bank;
> + u32 ecc_cor;
> +
> + ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank));
> + ecc_cor >>= ECC_COR_INFO_SHIFT(bank);
> +
> + if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
> + *max_bitflips = 0;
> + return true;
> + }
> +
> + *max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
> + return false;
> +}
> +
> #define ECC_SECTOR_SIZE 512
>
> #define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
> @@ -949,11 +968,6 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
> bitflips++;
> }
> } else {
> - /*
> - * if the error is not correctable, need to look at the
> - * page to see if it is an erased page. if so, then
> - * it's not a real ECC error
> - */
> check_erased_page = true;
> }
> } while (!ECC_LAST_ERR(err_correction_info));
> @@ -1109,12 +1123,12 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> {
> unsigned int max_bitflips;
> struct denali_nand_info *denali = mtd_to_denali(mtd);
> -
> dma_addr_t addr = denali->buf.dma_buf;
> size_t size = mtd->writesize + mtd->oobsize;
> -
> u32 irq_status;
> - u32 irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
> + u32 irq_mask = denali->caps & DENALI_CAPS_HW_ECC_FIXUP ?
> + INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__ECC_UNCOR_ERR :
> + INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
> bool check_erased_page = false;
>
> if (page != denali->page) {
> @@ -1139,11 +1153,21 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
>
> memcpy(buf, denali->buf.buf, mtd->writesize);
>
> - check_erased_page = denali_sw_ecc_fixup(denali, buf, irq_status,
> - &max_bitflips);
> + if (denali->caps & DENALI_CAPS_HW_ECC_FIXUP)
> + check_erased_page = denali_hw_ecc_fixup(denali, &max_bitflips);
> + else
> + check_erased_page = denali_sw_ecc_fixup(denali, buf, irq_status,
> + &max_bitflips);
Okay, so you currently have two ways of handling ECC errors. What if a
new revision introduces yet another way to do it?
How about making denali_caps a structure where you have one (or several)
function pointers to implement operations differently depending on the
IP revision?
struct denali_caps {
u32 feature_flags; /* If needed. */
bool (*handle_ecc)(...);
...
};
> +
> denali_enable_dma(denali, false);
>
> if (check_erased_page) {
> + /*
> + * If the error is not correctable, need to look at the page to
> + * see if it is an erased page. If so, then it's not a real ECC
> + * error.
> + */
> +
> read_oob_data(mtd, chip->oob_poi, denali->page);
>
> /* check ECC failures that may have occurred on erased pages */
> diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
> index 69314d0..beadc8a 100644
> --- a/drivers/mtd/nand/denali.h
> +++ b/drivers/mtd/nand/denali.h
> @@ -20,6 +20,7 @@
> #ifndef __DENALI_H__
> #define __DENALI_H__
>
> +#include <linux/bitops.h>
> #include <linux/mtd/nand.h>
>
> #define DEVICE_RESET 0x0
> @@ -219,6 +220,13 @@
> #define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
> #define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
>
> +/*
> + * Some versions of the IP have the ECC fixup handled in hardware. In this
> + * configuration we only get interrupted when the error is uncorrectable.
> + * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the
> + * old IP.
> + */
> +#define INTR_STATUS__ECC_UNCOR_ERR 0x0001
> #define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001
> #define INTR_STATUS__ECC_ERR 0x0002
> #define INTR_STATUS__DMA_CMD_COMP 0x0004
> @@ -297,6 +305,11 @@
> #define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
> #define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
>
> +#define ECC_COR_INFO(__bank) (0x650 + (__bank) / 2 * 0x10)
> +#define ECC_COR_INFO_SHIFT(__bank) ((__bank) % 2 * 8)
> +#define ECC_COR_INFO__MAX_ERRORS 0x007f
> +#define ECC_COR_INFO__UNCOR_ERR 0x0080
> +
> #define DMA_ENABLE 0x700
> #define DMA_ENABLE__FLAG 0x0001
>
> @@ -421,6 +434,7 @@ struct denali_nand_info {
> u32 bbtskipbytes;
> u32 max_banks;
> unsigned int caps;
> +#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
> };
>
> extern int denali_init(struct denali_nand_info *denali);
On Sun, 27 Nov 2016 03:06:04 +0900
Masahiro Yamada <[email protected]> wrote:
> This will be needed in the next commit to call denali_read_page_raw()
> from denali_read_page().
Please squash this change into patch 19. It's clearly useless to
dissociate them.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 76 +++++++++++++++++++++++------------------------
> 1 file changed, 38 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index c101e7f..f035dac 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -1118,6 +1118,44 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
> return 0;
> }
>
> +static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> + u8 *buf, int oob_required, int page)
> +{
> + struct denali_nand_info *denali = mtd_to_denali(mtd);
> + dma_addr_t addr = denali->buf.dma_buf;
> + size_t size = mtd->writesize + mtd->oobsize;
> + u32 irq_mask = INTR_STATUS__DMA_CMD_COMP;
> +
> + if (page != denali->page) {
> + dev_err(denali->dev,
> + "IN %s: page %d is not equal to denali->page %d",
> + __func__, page, denali->page);
> + BUG();
> + }
> +
> + setup_ecc_for_xfer(denali, false, oob_required ? true : false);
> + denali_enable_dma(denali, true);
> +
> + dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
> +
> + clear_interrupts(denali);
> + denali_setup_dma(denali, DENALI_READ);
> +
> + /* wait for operation to complete */
> + wait_for_irq(denali, irq_mask);
> +
> + dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
> +
> + denali_enable_dma(denali, false);
> +
> + memcpy(buf, denali->buf.buf, mtd->writesize);
> + if (oob_required)
> + memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize,
> + mtd->oobsize);
> +
> + return 0;
> +}
> +
> static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> u8 *buf, int oob_required, int page)
> {
> @@ -1182,44 +1220,6 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> return max_bitflips;
> }
>
> -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> - u8 *buf, int oob_required, int page)
> -{
> - struct denali_nand_info *denali = mtd_to_denali(mtd);
> - dma_addr_t addr = denali->buf.dma_buf;
> - size_t size = mtd->writesize + mtd->oobsize;
> - u32 irq_mask = INTR_STATUS__DMA_CMD_COMP;
> -
> - if (page != denali->page) {
> - dev_err(denali->dev,
> - "IN %s: page %d is not equal to denali->page %d",
> - __func__, page, denali->page);
> - BUG();
> - }
> -
> - setup_ecc_for_xfer(denali, false, oob_required ? true : false);
> - denali_enable_dma(denali, true);
> -
> - dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
> -
> - clear_interrupts(denali);
> - denali_setup_dma(denali, DENALI_READ);
> -
> - /* wait for operation to complete */
> - wait_for_irq(denali, irq_mask);
> -
> - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
> -
> - denali_enable_dma(denali, false);
> -
> - memcpy(buf, denali->buf.buf, mtd->writesize);
> - if (oob_required)
> - memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize,
> - mtd->oobsize);
> -
> - return 0;
> -}
> -
> static u8 denali_read_byte(struct mtd_info *mtd)
> {
> struct denali_nand_info *denali = mtd_to_denali(mtd);
On Sun, 27 Nov 2016 03:06:05 +0900
Masahiro Yamada <[email protected]> wrote:
> The erased page check must be done against the raw transferred data.
> The current first call of is_erase() is against the data after ECC
> correction. I saw cases where not all of the data in the page are
> 0xFF after they are manipulated by the ECC correction engine.
Hm, that's surprising. Usually ECC engines leaves data unchanged when
uncorrectable errors are detected. Do you have examples where this
happens? How did you trigger this case?
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index f035dac..ae44c01 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -1168,6 +1168,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__ECC_UNCOR_ERR :
> INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR;
> bool check_erased_page = false;
> + int ret;
>
> if (page != denali->page) {
> dev_err(denali->dev,
> @@ -1206,7 +1207,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> * error.
> */
>
> - read_oob_data(mtd, chip->oob_poi, denali->page);
> + ret = denali_read_page_raw(mtd, chip, buf, 1, denali->page);
> + if (ret < 0)
> + return ret;
>
> /* check ECC failures that may have occurred on erased pages */
> if (!is_erased(buf, mtd->writesize) ||
On Sun, 27 Nov 2016 03:06:06 +0900
Masahiro Yamada <[email protected]> wrote:
> The denali_dt.c was split out by Altera for the SOCFPGA port. The
> Denali IP on SOCFPGA incorporates the hardware ECC fixup feature.
> Newer versions are very likely to support it. So, it should be OK
> to set DENALI_CAPS_HW_ECC_FIXUP for all DT platforms.
Seems like a bad idea. What's the problem with setting this flag in the
data->caps definition of each revision?
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali_dt.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
> index 293ddb8..9dcd203 100644
> --- a/drivers/mtd/nand/denali_dt.c
> +++ b/drivers/mtd/nand/denali_dt.c
> @@ -59,6 +59,8 @@ static int denali_dt_probe(struct platform_device *ofdev)
> if (data)
> denali->caps = data->caps;
>
> + denali->caps |= DENALI_CAPS_HW_ECC_FIXUP;
> +
> denali->platform = DT;
> denali->dev = &ofdev->dev;
> denali->irq = platform_get_irq(ofdev, 0);
On Sun, 27 Nov 2016 03:06:07 +0900
Masahiro Yamada <[email protected]> wrote:
> The current driver only supports the DMA engine up to 32 bit
> physical address, but there also exists 64 bit capable DMA engine
> for this IP.
>
> The data DMA setup sequence is completely different, so I added the
> 64 bit DMA code as a new function denali_setup_dma64(). The 32 bit
> one has been renamed to denali_setup_dma32().
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 39 +++++++++++++++++++++++++++++++++++----
> drivers/mtd/nand/denali.h | 1 +
> 2 files changed, 36 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index ae44c01..752ad98 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -995,8 +995,30 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en)
> ioread32(denali->flash_reg + DMA_ENABLE);
> }
>
> -/* setups the HW to perform the data DMA */
> -static void denali_setup_dma(struct denali_nand_info *denali, int op)
> +static void denali_setup_dma64(struct denali_nand_info *denali, int op)
> +{
> + u32 mode;
> + const int page_count = 1;
> + u64 addr = denali->buf.dma_buf;
> +
> + mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
> +
> + /* DMA is a three step process */
> +
> + /*
> + * 1. setup transfer type, interrupt when complete,
> + * burst len = 64 bytes, the number of pages
> + */
> + index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
> +
> + /* 2. set memory low address */
> + index_addr(denali, mode, addr);
> +
> + /* 3. set memory high address */
> + index_addr(denali, mode, addr >> 32);
> +}
> +
> +static void denali_setup_dma32(struct denali_nand_info *denali, int op)
> {
> u32 mode;
> const int page_count = 1;
> @@ -1019,6 +1041,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
> index_addr(denali, mode | 0x14000, 0x2400);
> }
>
> +static void denali_setup_dma(struct denali_nand_info *denali, int op)
> +{
> + if (denali->caps & DENALI_CAPS_DMA_64BIT)
> + denali_setup_dma64(denali, op);
> + else
> + denali_setup_dma32(denali, op);
> +}
> +
If you follow my suggestions of definition function pointers, you'll
just have to add a function pointer to the denali_caps struct:
void (*setup_dma)(struct denali_nand_info *denali, int op);
> /*
> * writes a page. user specifies type, and this function handles the
> * configuration details.
> @@ -1495,8 +1525,9 @@ int denali_init(struct denali_nand_info *denali)
> goto failed_req_irq;
> }
>
> - /* Is 32-bit DMA supported? */
> - ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
> + ret = dma_set_mask(denali->dev,
> + DMA_BIT_MASK(denali->caps & DENALI_CAPS_DMA_64BIT ?
> + 64 : 32));
> if (ret) {
> dev_err(denali->dev, "no usable DMA configuration\n");
> goto failed_req_irq;
> diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
> index beadc8a..9bdf037 100644
> --- a/drivers/mtd/nand/denali.h
> +++ b/drivers/mtd/nand/denali.h
> @@ -435,6 +435,7 @@ struct denali_nand_info {
> u32 max_banks;
> unsigned int caps;
> #define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
> +#define DENALI_CAPS_DMA_64BIT BIT(1)
> };
>
> extern int denali_init(struct denali_nand_info *denali);
On Sun, 27 Nov 2016 03:06:14 +0900
Masahiro Yamada <[email protected]> wrote:
> Collect multi NAND fixups into a helper function instead of
> scattering them in denali_init().
Can you tell me more about this multi-NAND feature?
The core is already able to detect multi-die NAND chips in a generic
way, but I fear this is something else, like "put two 8-bits chips on a
16bits bus to emulate a single 16bits chip".
If that's a case, and this feature is actually used, then it's a bad
idea IMHO.
For example, how do you handle the case where one block is bad on a
chip but not on the other? And I fear this is not the only problem
with this approach :-/.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 51 ++++++++++++++++++++++++++++-------------------
> 1 file changed, 31 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index 60b0858..54dcd83 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -1472,6 +1472,34 @@ static void denali_drv_init(struct denali_nand_info *denali)
> denali->irq_status = 0;
> }
>
> +static void denali_multidev_fixup(struct denali_nand_info *denali)
> +{
> + struct nand_chip *chip = &denali->nand;
> + struct mtd_info *mtd = nand_to_mtd(chip);
> +
> + /*
> + * Support for multi NAND:
> + * MTD knows nothing about multi NAND, so we should tell it
> + * the real pagesize and anything necessary
> + */
> + denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
> +
> + mtd->size <<= denali->devnum - 1;
> + mtd->erasesize <<= denali->devnum - 1;
> + mtd->writesize <<= denali->devnum - 1;
> + mtd->oobsize <<= denali->devnum - 1;
> + chip->chipsize <<= denali->devnum - 1;
> + chip->page_shift += denali->devnum - 1;
> + chip->phys_erase_shift += denali->devnum - 1;
> + chip->bbt_erase_shift += denali->devnum - 1;
> + chip->chip_shift += denali->devnum - 1;
> + chip->pagemask <<= denali->devnum - 1;
> + chip->ecc.size *= denali->devnum;
> + chip->ecc.bytes *= denali->devnum;
> + chip->ecc.strength *= denali->devnum;
> + denali->bbtskipbytes *= denali->devnum;
> +}
> +
> int denali_init(struct denali_nand_info *denali)
> {
> struct nand_chip *chip = &denali->nand;
> @@ -1553,23 +1581,6 @@ int denali_init(struct denali_nand_info *denali)
> goto failed_req_irq;
> }
>
> - /*
> - * support for multi nand
> - * MTD known nothing about multi nand, so we should tell it
> - * the real pagesize and anything necessery
> - */
> - denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
> - chip->chipsize <<= denali->devnum - 1;
> - chip->page_shift += denali->devnum - 1;
> - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
> - chip->bbt_erase_shift += denali->devnum - 1;
> - chip->phys_erase_shift = chip->bbt_erase_shift;
> - chip->chip_shift += denali->devnum - 1;
> - mtd->writesize <<= denali->devnum - 1;
> - mtd->oobsize <<= denali->devnum - 1;
> - mtd->erasesize <<= denali->devnum - 1;
> - mtd->size = chip->numchips * chip->chipsize;
> - denali->bbtskipbytes *= denali->devnum;
>
> /*
> * second stage of the NAND scan
> @@ -1614,11 +1625,9 @@ int denali_init(struct denali_nand_info *denali)
> }
>
> mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
> - chip->ecc.bytes *= denali->devnum;
> - chip->ecc.strength *= denali->devnum;
>
> /* override the default read operations */
> - chip->ecc.size = ECC_SECTOR_SIZE * denali->devnum;
> + chip->ecc.size = ECC_SECTOR_SIZE;
> chip->ecc.read_page = denali_read_page;
> chip->ecc.read_page_raw = denali_read_page_raw;
> chip->ecc.write_page = denali_write_page;
> @@ -1627,6 +1636,8 @@ int denali_init(struct denali_nand_info *denali)
> chip->ecc.write_oob = denali_write_oob;
> chip->erase = denali_erase;
>
> + denali_multidev_fixup(denali);
> +
> ret = nand_scan_tail(mtd);
> if (ret)
> goto failed_req_irq;
On Sun, 27 Nov 2016 03:06:24 +0900
Masahiro Yamada <[email protected]> wrote:
> The Denali IP can automatically detect device parameters such as
> page size, device width, etc. and this driver currently relies on it.
> However, this hardware function is problematic.
>
> [1] Due to a hardware bug, various misdetected cases are known.
> That is why get_toshiba_nand_para(), get_hynix_nand_para() exist
> to fix the misdetected parameters. It is not realistic to add a
> new NAND device to the *black list* every time we are hit by a
> misdetected case. We would never be able to guarantee that all
> the cases are covered.
>
> [2] Because this feature is unreliable, it is disabled on some
> platforms.
>
> The nand_scan_ident() sets device parameters such as mtd->writesize,
> mtd->erasesize, etc. in a more tested way. We should not set the
> hardware registers in a different, unreliable way. Instead, set
> the parameters from nand_scan_ident() back to the registers.
>
Thanks a lot for fixing that.
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> drivers/mtd/nand/denali.c | 39 ++++++---------------------------------
> 1 file changed, 6 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index df174ca..1aa19ec 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -338,35 +338,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, u8 device_id)
> }
> }
>
> -static void get_toshiba_nand_para(struct denali_nand_info *denali)
> -{
> - /*
> - * Workaround to fix a controller bug which reports a wrong
> - * spare area size for some kind of Toshiba NAND device
> - */
> - if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
> - (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
> - iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
> -}
> -
> -static void get_hynix_nand_para(struct denali_nand_info *denali, u8 device_id)
> -{
> - switch (device_id) {
> - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
> - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
> - iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
> - iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
> - iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
> - iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
> - break;
> - default:
> - dev_warn(denali->dev,
> - "Unknown Hynix NAND (Device ID: 0x%x).\n"
> - "Will use default parameter values instead.\n",
> - device_id);
> - }
> -}
> -
> /*
> * determines how many NAND chips are connected to the controller. Note for
> * Intel CE4100 devices we don't support more than one device.
> @@ -468,10 +439,6 @@ static u16 denali_nand_timing_set(struct denali_nand_info *denali)
> return FAIL;
> } else if (maf_id == 0xEC) { /* Samsung NAND */
> get_samsung_nand_para(denali, device_id);
> - } else if (maf_id == 0x98) { /* Toshiba NAND */
> - get_toshiba_nand_para(denali);
> - } else if (maf_id == 0xAD) { /* Hynix NAND */
> - get_hynix_nand_para(denali, device_id);
> }
>
> dev_info(denali->dev,
> @@ -1661,6 +1628,12 @@ int denali_init(struct denali_nand_info *denali)
> chip->ecc.strength);
>
> iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION);
> + iowrite32(mtd->erasesize / mtd->writesize,
> + denali->flash_reg + PAGES_PER_BLOCK);
> + iowrite32(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
> + denali->flash_reg + DEVICE_WIDTH);
> + iowrite32(mtd->writesize, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
> + iowrite32(mtd->oobsize, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
>
> mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
>
On Sun, 27 Nov 2016 03:05:46 +0900
Masahiro Yamada <[email protected]> wrote:
> As I said in the 1st round series, I am tackling on this driver
> to use it for my SoCs.
>
> The previous series was just cosmetic things, but this series
> includes *real* changes.
>
> After some more cleanups, I will start to add changes that
> are really necessary.
> One of the biggest problems I want to solve is a bunch of
> hard-coded parameters that prevent me from using this driver for
> my SoCs.
>
> I will introduce capability flags that are associated with DT
> compatible and make platform-dependent parameters overridable.
>
> I still have lots of reworks to get done (so probably 3rd round
> series will come), but I hope it is getting better and
> I am showing a big picture now.
>
I still need to carefully review some of those patches, but I must
admit I like some of the cleanups/rework you're doing here.
Thanks for all your work.
Boris
>
>
> Masahiro Yamada (39):
> mtd: nand: allow to set only one of ECC size and ECC strength from DT
> mtd: nand: denali: remove unused CONFIG option and macros
> mtd: nand: denali: remove redundant define of BANK(x)
> mtd: nand: denali: remove more unused struct members
> mtd: nand: denali: fix comment of denali_nand_info::flash_mem
> mtd: nand: denali: fix write_oob_data() function
> mtd: nand: denali: transfer OOB only when oob_required is set
> mtd: nand: denali: introduce capability flag
> mtd: nand: denali: fix erased page check code
> mtd: nand: denali: remove redundant if conditional of erased_check
> mtd: nand: denali: increment ecc_stats.failed by one per error
> mtd: nand: denali: return 0 for uncorrectable ECC error
> mtd: nand: denali: increment ecc_stats->corrected
> mtd: nand: denali: replace uint{8/16/32}_t with u{8/16/32}
> mtd: nand: denali: improve readability of handle_ecc()
> mtd: nand: denali: rename handle_ecc() to denali_sw_ecc_fixup()
> mtd: nand: denali: support HW_ECC_FIXUP capability
> mtd: nand: denali: move denali_read_page_raw() above
> denali_read_page()
> mtd: nand: denali: perform erased check against raw transferred page
> mtd: nand: denali_dt: enable HW_ECC_FIXUP capability for DT platform
> mtd: nand: denali: support 64bit capable DMA engine
> mtd: nand: denali_dt: remove dma-mask DT property
> mtd: nand: denali_dt: use pdev instead of ofdev for platform_device
> mtd: nand: denali: add NEW_N_BANKS_FORMAT capability
> mtd: nand: denali: use nand_chip to hold frequently accessed data
> mtd: nand: denali: call nand_set_flash_node() to set DT node
> mtd: nand: denali: do not set mtd->name
> mtd: nand: denali: move multi NAND fixup code to a helper function
> mtd: nand: denali: refactor multi NAND fixup code in more generic way
> mtd: nand: denali: set DEVICES_CONNECTED 1 if not set
> mtd: nand: denali: remove meaningless writes to read-only registers
> mtd: nand: denali: remove unnecessary writes to ECC_CORRECTION
> mtd: nand: denali: support 1024 byte ECC step size
> mtd: nand: denali: fix the condition for 15 bit ECC strength
> mtd: nand: denali: calculate ecc.strength and ecc.bytes generically
> mtd: nand: denali: allow to use SoC-specific ECC strength
> mtd: nand: denali: support "nand-ecc-strength" DT property
> mtd: nand: denali: remove Toshiba, Hynix specific fixup code
> mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
>
> .../devicetree/bindings/mtd/denali-nand.txt | 19 +-
> drivers/mtd/nand/Kconfig | 11 -
> drivers/mtd/nand/denali.c | 740 ++++++++++++---------
> drivers/mtd/nand/denali.h | 84 +--
> drivers/mtd/nand/denali_dt.c | 95 ++-
> drivers/mtd/nand/denali_pci.c | 2 +
> drivers/mtd/nand/nand_base.c | 6 -
> 7 files changed, 515 insertions(+), 442 deletions(-)
>
Hi Boris
2016-11-28 1:12 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:06:05 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> The erased page check must be done against the raw transferred data.
>> The current first call of is_erase() is against the data after ECC
>> correction. I saw cases where not all of the data in the page are
>> 0xFF after they are manipulated by the ECC correction engine.
>
> Hm, that's surprising. Usually ECC engines leaves data unchanged when
> uncorrectable errors are detected. Do you have examples where this
> happens? How did you trigger this case?
It always happens on some of my boards.
At the bottom of this mail, I attached a dump of an erased page
after it was manipulated by the ECC engine.
See offset 0x2c1, 0x6c1
The data is 0xfd, not 0xff.
I think basically two ways for erased page checking.
[1] Read the whole of page + oob in raw mode transfer,
then check if all the data are 0xFF.
[2] Read the ECC-corrected page + oob,
then check if *most* of the data are 0xFF.
bit-flips less than ecc.strength are allowed.
I think [2] is equivalent to calling nand_check_erased_ecc_chunk()
with ecc.strength for threshold,
as you suggested in 09/39
But, the current Denali driver does:
[3] Read the ECC-corrected page + oob,
then check if all the data are 0xFF.
(no bit-flips are allowed)
I think this is wrong
because this erased page checking is false negative.
This patches adopts [1] to solve my problem, but [2] will work as well.
In my case, only one bit-flip (0xff -> 0xfd) in each ECC section.
[ 19.194200] 0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.200275] 10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.206355] 20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.212430] 30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.218511] 40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.224586] 50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.230659] 60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.236733] 70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.242807] 80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.248881] 90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.254955] a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.261030] b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.267102] c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.273177] d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.279254] e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.285326] f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.291407] 100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.297481] 110: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.303555] 120: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.309630] 130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.315702] 140: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.321778] 150: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.327850] 160: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.333927] 170: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.340006] 180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.346082] 190: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.352154] 1a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.358230] 1b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.364303] 1c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.370377] 1d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.376451] 1e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.382525] 1f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.388598] 200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.394674] 210: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.400754] 220: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.406829] 230: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.412903] 240: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.418977] 250: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.425049] 260: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.431124] 270: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.437199] 280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.443274] 290: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.449354] 2a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.455431] 2b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.461503] 2c0: ff fd ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.467578] 2d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.473651] 2e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.479727] 2f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.485812] 300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.491883] 310: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.497963] 320: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.504040] 330: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.510120] 340: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.516195] 350: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.522267] 360: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.528343] 370: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.534416] 380: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.540490] 390: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.546565] 3a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.552638] 3b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.558711] 3c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.564787] 3d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.570868] 3e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.576944] 3f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.583024] 400: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.589100] 410: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.595172] 420: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.601247] 430: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.607319] 440: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.613395] 450: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.619467] 460: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.625542] 470: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.631615] 480: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.637690] 490: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.643764] 4a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.649839] 4b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.655911] 4c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.661986] 4d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.668058] 4e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.674133] 4f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.680208] 500: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.686282] 510: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.692356] 520: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.698431] 530: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.704510] 540: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.710586] 550: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.716659] 560: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.722734] 570: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.728806] 580: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.734881] 590: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.740954] 5a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.747030] 5b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.753103] 5c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.759178] 5d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.765250] 5e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.771326] 5f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.777398] 600: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.783473] 610: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.789547] 620: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.795621] 630: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.801698] 640: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.807770] 650: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.813850] 660: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.819925] 670: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.825997] 680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.832074] 690: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.838154] 6a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.844230] 6b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.850303] 6c0: ff fd ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.856378] 6d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.862450] 6e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.868525] 6f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.874597] 700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.880673] 710: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.886746] 720: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.892821] 730: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.898894] 740: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.904969] 750: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.911042] 760: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.917118] 770: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.923198] 780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.929274] 790: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.935346] 7a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.941421] 7b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.947493] 7c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.953569] 7d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.959642] 7e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 19.965717] 7f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 1:24 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:06:14 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> Collect multi NAND fixups into a helper function instead of
>> scattering them in denali_init().
>
> Can you tell me more about this multi-NAND feature?
> The core is already able to detect multi-die NAND chips in a generic
> way,
This is not the case.
> but I fear this is something else, like "put two 8-bits chips on a
> 16bits bus to emulate a single 16bits chip".
Yes, it is.
(I have never used this controller like that.
But, I am pretty sure it is
from the code and the
Denali's User Guide mentions such usage.)
Just in case, I will clearly rephrase the comment block like follows in v2:
/*
* Support for multi device:
* When the IP configuration is x16 capable and two x8 chips are
* connected in parallel, DEVICES_CONNECTED should be set to 2.
* In this case, the core framework knows nothing about this fact,
* so we should tell it the _logical_ pagesize and anything necessary.
*/
> If that's a case, and this feature is actually used, then it's a bad
> idea IMHO.
> For example, how do you handle the case where one block is bad on a
> chip but not on the other? And I fear this is not the only problem
> with this approach :-/.
As you expect, if one block is bad,
the correspond block on the other chip can not be used.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 1:10 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:06:04 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> This will be needed in the next commit to call denali_read_page_raw()
>> from denali_read_page().
>
> Please squash this change into patch 19. It's clearly useless to
> dissociate them.
>
I will.
But as I mentioned in the reply to 19/39,
I am thinking that another solution may be possible.
In that case, both 18/39 and 19/39 will be unnecessary.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 1:14 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:06:06 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> The denali_dt.c was split out by Altera for the SOCFPGA port. The
>> Denali IP on SOCFPGA incorporates the hardware ECC fixup feature.
>> Newer versions are very likely to support it. So, it should be OK
>> to set DENALI_CAPS_HW_ECC_FIXUP for all DT platforms.
>
> Seems like a bad idea. What's the problem with setting this flag in the
> data->caps definition of each revision?
No problem.
I will follow your suggestion in v2.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 1:09 GMT+09:00 Boris Brezillon <[email protected]>:
&max_bitflips);
>
> Okay, so you currently have two ways of handling ECC errors. What if a
> new revision introduces yet another way to do it?
>
> How about making denali_caps a structure where you have one (or several)
> function pointers to implement operations differently depending on the
> IP revision?
>
> struct denali_caps {
> u32 feature_flags; /* If needed. */
> bool (*handle_ecc)(...);
> ...
> };
>
I think a problem is the difference of function arguments:
static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
unsigned int *max_bitflips)
vs
static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
u32 irq_status, unsigned int *max_bitflips)
I do not want to pass redundant arguments,
which are used for one, but not used for the other.
We do not need to think about the situation that may not happen.
If happens, we can refactor the code any time.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 1:16 GMT+09:00 Boris Brezillon <[email protected]>:
>
> If you follow my suggestions of definition function pointers, you'll
> just have to add a function pointer to the denali_caps struct:
>
> void (*setup_dma)(struct denali_nand_info *denali, int op);
>
This is possible because both 32B and 64B variants have
the same function prototype.
However, I am not keen on doing so for ecc_handle(),
so, at this moment, I am not keen on doing so only for setup_dma() either.
If I see more cases that fit in callback handler approach,
I will think about switching to it with consistency.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 0:12 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:05:50 +0900
> Masahiro Yamada <[email protected]> wrote:
>
> Please add a description here.
>
> Also, this commit tends to validate my fears: you should have wait for
> the full rework/cleanup to be done before submitting the first round of
> cleanups. Indeed, commit c4ae0977f57d ("mtd: nand: denali: remove unused
> struct member denali_nand_info::idx") was removing one of these unused
> fields, leaving 2 of them behind.
Right.
No difference except that
denali->idx was initialized to zero(, but not referenced).
I could squash the two patches.
> While I like when things I clearly separated in different commits, when
> you push the logic too far, you end up with big series which are not
> necessarily easier to review, and several commits that are achieving
> the same goal...
I must admit that I hurried up in posting the first round.
But, please note I did not ask you to pick it up for v4.10-rc1.
After all, it was your choice whether you picked it soon or
waited until you saw the big picture.
You could have postponed it until v4.11-rc1 if you had wanted.
My idea was, I'd like to get feedback earlier
(especially from Intel engineers).
I fear that I do not reveal anything until I complete my work.
If I am doing wrong in the early patches in my big series,
I might end up with lots of effort to turn around.
I dropped various Intel-specific things,
for example commit c9e025843242 ("mtd: nand: denali: remove
detect_partition_feature()")
removed the whole function I do not understand.
There was possibility that it might be locally used by Intel platforms.
If I had gotten negative comments for removal, I'd have needed more efforts
to not break any old functions.
As a result, nobody was opposed to delete such things.
So, I can confidently continue my work on cleaner and more *stable* base.
--
Best Regards
Masahiro Yamada
On Wed, 30 Nov 2016 16:11:53 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
> 2016-11-28 1:16 GMT+09:00 Boris Brezillon <[email protected]>:
> >
> > If you follow my suggestions of definition function pointers, you'll
> > just have to add a function pointer to the denali_caps struct:
> >
> > void (*setup_dma)(struct denali_nand_info *denali, int op);
> >
>
>
> This is possible because both 32B and 64B variants have
> the same function prototype.
>
>
> However, I am not keen on doing so for ecc_handle(),
> so, at this moment, I am not keen on doing so only for setup_dma() either.
>
> If I see more cases that fit in callback handler approach,
> I will think about switching to it with consistency.
>
Pretty much all the flags you define in this series could be turned
into function pointers. I still think the function pointers approach is
more future-proof, but I won't fight on that, so do as you wish.
On Wed, 30 Nov 2016 16:16:35 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
>
> 2016-11-28 0:12 GMT+09:00 Boris Brezillon <[email protected]>:
> > On Sun, 27 Nov 2016 03:05:50 +0900
> > Masahiro Yamada <[email protected]> wrote:
> >
> > Please add a description here.
> >
> > Also, this commit tends to validate my fears: you should have wait for
> > the full rework/cleanup to be done before submitting the first round of
> > cleanups. Indeed, commit c4ae0977f57d ("mtd: nand: denali: remove unused
> > struct member denali_nand_info::idx") was removing one of these unused
> > fields, leaving 2 of them behind.
>
> Right.
> No difference except that
> denali->idx was initialized to zero(, but not referenced).
>
> I could squash the two patches.
That's not a big deal.
>
>
> > While I like when things I clearly separated in different commits, when
> > you push the logic too far, you end up with big series which are not
> > necessarily easier to review, and several commits that are achieving
> > the same goal...
>
>
> I must admit that I hurried up in posting the first round.
> But, please note I did not ask you to pick it up for v4.10-rc1.
> After all, it was your choice whether you picked it soon or
> waited until you saw the big picture.
> You could have postponed it until v4.11-rc1 if you had wanted.
That's true. But it was not clear from your cover letter that you
were posting this series just to get feedback and not necessarily to
get them applied.
>
> My idea was, I'd like to get feedback earlier
> (especially from Intel engineers).
>
> I fear that I do not reveal anything until I complete my work.
> If I am doing wrong in the early patches in my big series,
> I might end up with lots of effort to turn around.
>
> I dropped various Intel-specific things,
> for example commit c9e025843242 ("mtd: nand: denali: remove
> detect_partition_feature()")
> removed the whole function I do not understand.
> There was possibility that it might be locally used by Intel platforms.
>
> If I had gotten negative comments for removal, I'd have needed more efforts
> to not break any old functions.
>
> As a result, nobody was opposed to delete such things.
> So, I can confidently continue my work on cleaner and more *stable* base.
>
>
Okay, got it. So, I should not apply any patches from this series until
you've completed your rework (round2+3 posted).
I think I'll still apply patch 1 early, because it's not directly
related to the denali rework, and the fix looks good.
Regards,
Boris
On Wed, 30 Nov 2016 15:20:10 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
>
> 2016-11-28 1:09 GMT+09:00 Boris Brezillon <[email protected]>:
> &max_bitflips);
> >
> > Okay, so you currently have two ways of handling ECC errors. What if a
> > new revision introduces yet another way to do it?
> >
> > How about making denali_caps a structure where you have one (or several)
> > function pointers to implement operations differently depending on the
> > IP revision?
> >
> > struct denali_caps {
> > u32 feature_flags; /* If needed. */
> > bool (*handle_ecc)(...);
> > ...
> > };
> >
>
> I think a problem is the difference of function arguments:
>
> static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
> unsigned int *max_bitflips)
>
> vs
>
> static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
> u32 irq_status, unsigned int *max_bitflips)
>
>
> I do not want to pass redundant arguments,
> which are used for one, but not used for the other.
>
We do that all the time when defining generic interfaces.
>
> We do not need to think about the situation that may not happen.
> If happens, we can refactor the code any time.
>
Well, as I said in my other reply, I still think it's better to plan
for this now, rather than having to change a lot things when we appear
to need this. But that's only my POV, and I don't care enough to fight.
On Wed, 30 Nov 2016 14:36:13 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris
>
>
> 2016-11-28 1:12 GMT+09:00 Boris Brezillon <[email protected]>:
> > On Sun, 27 Nov 2016 03:06:05 +0900
> > Masahiro Yamada <[email protected]> wrote:
> >
> >> The erased page check must be done against the raw transferred data.
> >> The current first call of is_erase() is against the data after ECC
> >> correction. I saw cases where not all of the data in the page are
> >> 0xFF after they are manipulated by the ECC correction engine.
> >
> > Hm, that's surprising. Usually ECC engines leaves data unchanged when
> > uncorrectable errors are detected. Do you have examples where this
> > happens? How did you trigger this case?
>
>
> It always happens on some of my boards.
> At the bottom of this mail, I attached a dump of an erased page
> after it was manipulated by the ECC engine.
>
> See offset 0x2c1, 0x6c1
> The data is 0xfd, not 0xff.
So you confirm that is dump is done with ECC engine enabled, right?
All I see is 2 bitflips in an erased page, and AFAICT, the engine did
not try to fix other things (with the risk of making it worst).
My point was that, if you already have the in-band data, and can easily
retrieve the ECC and OOB sections, then it's more efficient than
transferring the whole page again.
>
>
> I think basically two ways for erased page checking.
>
> [1] Read the whole of page + oob in raw mode transfer,
> then check if all the data are 0xFF.
I'm pretty sure you have bitflips even when reading in raw mode in your
specific case.
>
> [2] Read the ECC-corrected page + oob,
> then check if *most* of the data are 0xFF.
> bit-flips less than ecc.strength are allowed.
That's how other drivers are doing it.
>
>
> I think [2] is equivalent to calling nand_check_erased_ecc_chunk()
> with ecc.strength for threshold,
> as you suggested in 09/39
Yep, you can use this helper and pass the data and ECC sections (you'll
have to loop over the different ECC chunks and call this function for
each iteration)
>
>
> But, the current Denali driver does:
>
> [3] Read the ECC-corrected page + oob,
> then check if all the data are 0xFF.
> (no bit-flips are allowed)
>
> I think this is wrong
> because this erased page checking is false negative.
Yep, that does not work as soon as you have at least one bitflip in the
page, which can be a problem on MLCs or modern SLCs.
>
>
>
> This patches adopts [1] to solve my problem, but [2] will work as well.
Yes, but as I said, I'm don't understand how #1 can work here. I'd
expect to see the same bitflips when reading in raw mode.
>
> In my case, only one bit-flip (0xff -> 0xfd) in each ECC section.
>
>
>
> [ 19.194200] 0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.200275] 10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.206355] 20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.212430] 30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.218511] 40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.224586] 50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.230659] 60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.236733] 70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.242807] 80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.248881] 90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.254955] a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.261030] b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.267102] c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.273177] d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.279254] e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.285326] f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.291407] 100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.297481] 110: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.303555] 120: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.309630] 130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.315702] 140: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.321778] 150: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.327850] 160: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.333927] 170: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.340006] 180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.346082] 190: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.352154] 1a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.358230] 1b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.364303] 1c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.370377] 1d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.376451] 1e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.382525] 1f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.388598] 200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.394674] 210: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.400754] 220: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.406829] 230: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.412903] 240: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.418977] 250: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.425049] 260: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.431124] 270: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.437199] 280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.443274] 290: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.449354] 2a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.455431] 2b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.461503] 2c0: ff fd ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.467578] 2d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.473651] 2e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.479727] 2f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.485812] 300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.491883] 310: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.497963] 320: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.504040] 330: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.510120] 340: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.516195] 350: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.522267] 360: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.528343] 370: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.534416] 380: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.540490] 390: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.546565] 3a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.552638] 3b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.558711] 3c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.564787] 3d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.570868] 3e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.576944] 3f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.583024] 400: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.589100] 410: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.595172] 420: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.601247] 430: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.607319] 440: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.613395] 450: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.619467] 460: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.625542] 470: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.631615] 480: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.637690] 490: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.643764] 4a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.649839] 4b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.655911] 4c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.661986] 4d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.668058] 4e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.674133] 4f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.680208] 500: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.686282] 510: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.692356] 520: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.698431] 530: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.704510] 540: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.710586] 550: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.716659] 560: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.722734] 570: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.728806] 580: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.734881] 590: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.740954] 5a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.747030] 5b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.753103] 5c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.759178] 5d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.765250] 5e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.771326] 5f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.777398] 600: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.783473] 610: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.789547] 620: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.795621] 630: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.801698] 640: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.807770] 650: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.813850] 660: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.819925] 670: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.825997] 680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.832074] 690: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.838154] 6a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.844230] 6b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.850303] 6c0: ff fd ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.856378] 6d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.862450] 6e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.868525] 6f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.874597] 700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.880673] 710: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.886746] 720: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.892821] 730: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.898894] 740: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.904969] 750: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.911042] 760: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.917118] 770: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.923198] 780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.929274] 790: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.935346] 7a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.941421] 7b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.947493] 7c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.953569] 7d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.959642] 7e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 19.965717] 7f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>
>
>
>
Hi.
2016-11-28 0:04 GMT+09:00 Boris Brezillon <[email protected]>:
> +Andy
>
> Hi Masahiro,
>
> On Sun, 27 Nov 2016 03:05:46 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> As I said in the 1st round series, I am tackling on this driver
>> to use it for my SoCs.
>>
>> The previous series was just cosmetic things, but this series
>> includes *real* changes.
>>
>> After some more cleanups, I will start to add changes that
>> are really necessary.
>> One of the biggest problems I want to solve is a bunch of
>> hard-coded parameters that prevent me from using this driver for
>> my SoCs.
>>
>> I will introduce capability flags that are associated with DT
>> compatible and make platform-dependent parameters overridable.
>>
>> I still have lots of reworks to get done (so probably 3rd round
>> series will come), but I hope it is getting better and
>> I am showing a big picture now.
>>
>
> Thanks for posting this 2nd round of patches, I know have a clearer
> view of what you're trying to achieve.
> Could you be a bit more specific about the remaining rework (your 3rd
> round)?
[1]
I want to remove
get_samsung_nand_para()
get_onfi_nand_para()
The driver should not hard-code timing parameters of Samsung specific
chips. For ONFI, it is duplicating effort of the core framework.
I am thinking if it would be possible to implement
chip->setup_data_interface() in order to set up
timings in a generic way.
[2]
Remove driver-internal bounce buffer.
The current Denali driver allocate DMA_BIDIRECTIONAL buffer
to use it as a driver-internal bounce buffer.
The hardware transfer page data into the bounce buffer,
then CPU copies from the bounce buffer to a given buf (and oob_poi).
This is not efficient.
So, I want to set NAND_USE_BOUNCE_BUFFER flag
and do dma_map_single directly for a given buffer.
[3]
Fix raw and oob callbacks.
I asked in another thread,
the current driver just puts the physically accessed OOB data
into oob_poi, which is not a collection of ECC data.
Raw write/read() are wrong as well.
After fixing those, enable BBT scan by removing the following flag:
/* skip the scan for now until we have OOB read and write support */
chip->options |= NAND_SKIP_BBTSCAN;
> Also, if you don't mind, I'd like to have reviews and testing from intel
> users before applying the series. Can you Cc Andy (and possibly other
> intel maintainers) for the next round.
Sure.
Anyway, this series already missed the pull-req for 4.10-rc1,
we have plenty of time until 4.11-rc1.
Review/test from Intel engineers are very appreciated
because I have no access to their boards.
--
Best Regards
Masahiro Yamada
On Wed, 30 Nov 2016 15:09:27 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
>
> 2016-11-28 1:24 GMT+09:00 Boris Brezillon <[email protected]>:
> > On Sun, 27 Nov 2016 03:06:14 +0900
> > Masahiro Yamada <[email protected]> wrote:
> >
> >> Collect multi NAND fixups into a helper function instead of
> >> scattering them in denali_init().
> >
> > Can you tell me more about this multi-NAND feature?
> > The core is already able to detect multi-die NAND chips in a generic
> > way,
>
> This is not the case.
>
> > but I fear this is something else, like "put two 8-bits chips on a
> > 16bits bus to emulate a single 16bits chip".
>
> Yes, it is.
>
> (I have never used this controller like that.
> But, I am pretty sure it is
> from the code and the
> Denali's User Guide mentions such usage.)
>
>
> Just in case, I will clearly rephrase the comment block like follows in v2:
>
> /*
> * Support for multi device:
> * When the IP configuration is x16 capable and two x8 chips are
> * connected in parallel, DEVICES_CONNECTED should be set to 2.
> * In this case, the core framework knows nothing about this fact,
> * so we should tell it the _logical_ pagesize and anything necessary.
> */
>
BTW, you should also set the NAND_BUSWIDTH_16 flag in this case.
>
>
>
> > If that's a case, and this feature is actually used, then it's a bad
> > idea IMHO.
> > For example, how do you handle the case where one block is bad on a
> > chip but not on the other? And I fear this is not the only problem
> > with this approach :-/.
>
> As you expect, if one block is bad,
> the correspond block on the other chip can not be used.
>
Hm, last time I thought about this usage I found others things that
could cause problems, but I can't remember exactly what.
Anyway, if this feature is already used, let's keep it.
2016-11-28 0:04 GMT+09:00 Boris Brezillon <[email protected]>:
> +Andy
>
> Hi Masahiro,
>
> On Sun, 27 Nov 2016 03:05:46 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> As I said in the 1st round series, I am tackling on this driver
>> to use it for my SoCs.
>>
>> The previous series was just cosmetic things, but this series
>> includes *real* changes.
>>
>> After some more cleanups, I will start to add changes that
>> are really necessary.
>> One of the biggest problems I want to solve is a bunch of
>> hard-coded parameters that prevent me from using this driver for
>> my SoCs.
>>
>> I will introduce capability flags that are associated with DT
>> compatible and make platform-dependent parameters overridable.
>>
>> I still have lots of reworks to get done (so probably 3rd round
>> series will come), but I hope it is getting better and
>> I am showing a big picture now.
>>
>
> Thanks for posting this 2nd round of patches, I know have a clearer
> view of what you're trying to achieve.
> Could you be a bit more specific about the remaining rework (your 3rd
> round)?
We still have plenty of time, and no reason to hurry now.
So, you do not have to apply this series
until you see an even bigger picture.
I will try my best to include as many of my plans as possible
in this round.
I may end up with dropping my on-going work to the ML occasionally
because I want early feedback in case I am doing something wrong.
--
Best Regards
Masahiro Yamada
On Wed, 30 Nov 2016 17:02:16 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi.
>
> 2016-11-28 0:04 GMT+09:00 Boris Brezillon <[email protected]>:
> > +Andy
> >
> > Hi Masahiro,
> >
> > On Sun, 27 Nov 2016 03:05:46 +0900
> > Masahiro Yamada <[email protected]> wrote:
> >
> >> As I said in the 1st round series, I am tackling on this driver
> >> to use it for my SoCs.
> >>
> >> The previous series was just cosmetic things, but this series
> >> includes *real* changes.
> >>
> >> After some more cleanups, I will start to add changes that
> >> are really necessary.
> >> One of the biggest problems I want to solve is a bunch of
> >> hard-coded parameters that prevent me from using this driver for
> >> my SoCs.
> >>
> >> I will introduce capability flags that are associated with DT
> >> compatible and make platform-dependent parameters overridable.
> >>
> >> I still have lots of reworks to get done (so probably 3rd round
> >> series will come), but I hope it is getting better and
> >> I am showing a big picture now.
> >>
> >
> > Thanks for posting this 2nd round of patches, I know have a clearer
> > view of what you're trying to achieve.
> > Could you be a bit more specific about the remaining rework (your 3rd
> > round)?
>
>
> [1]
> I want to remove
> get_samsung_nand_para()
> get_onfi_nand_para()
>
> The driver should not hard-code timing parameters of Samsung specific
> chips. For ONFI, it is duplicating effort of the core framework.
Definitely.
>
> I am thinking if it would be possible to implement
> chip->setup_data_interface() in order to set up
> timings in a generic way.
Indeed, and that'd be really cool to have this driver converted to this
new interface.
>
> [2]
> Remove driver-internal bounce buffer.
> The current Denali driver allocate DMA_BIDIRECTIONAL buffer
> to use it as a driver-internal bounce buffer.
>
> The hardware transfer page data into the bounce buffer,
> then CPU copies from the bounce buffer to a given buf (and oob_poi).
> This is not efficient.
>
> So, I want to set NAND_USE_BOUNCE_BUFFER flag
> and do dma_map_single directly for a given buffer.
Sounds good. Be careful though, when you use the generic bounce buffer
interface you might have to clear the page cache info (->pagebuf = -1).
>
> [3]
> Fix raw and oob callbacks.
>
> I asked in another thread,
> the current driver just puts the physically accessed OOB data
> into oob_poi, which is not a collection of ECC data.
> Raw write/read() are wrong as well.
That's all good things too.
>
> After fixing those, enable BBT scan by removing the following flag:
> /* skip the scan for now until we have OOB read and write support */
> chip->options |= NAND_SKIP_BBTSCAN;
>
Hm, here you have a problem. The layout you described replaces BBMs by
payload data, thus preventing the BBM scan approach (or at least, it
won't work with factory BBMs).
Some drivers/controllers have an extra 'switch BBM/data bytes' step to
restore the BBM at the correct place before flushing the data to the
NAND or after reading a page, but I'm not sure this is the case here.
>
>
> > Also, if you don't mind, I'd like to have reviews and testing from intel
> > users before applying the series. Can you Cc Andy (and possibly other
> > intel maintainers) for the next round.
>
> Sure.
>
> Anyway, this series already missed the pull-req for 4.10-rc1,
> we have plenty of time until 4.11-rc1.
>
> Review/test from Intel engineers are very appreciated
> because I have no access to their boards.
>
>
Hi Boris,
2016-11-30 17:17 GMT+09:00 Boris Brezillon <[email protected]>:
>> [3]
>> Fix raw and oob callbacks.
>>
>> I asked in another thread,
>> the current driver just puts the physically accessed OOB data
>> into oob_poi, which is not a collection of ECC data.
>> Raw write/read() are wrong as well.
>
> That's all good things too.
>
>>
>> After fixing those, enable BBT scan by removing the following flag:
>> /* skip the scan for now until we have OOB read and write support */
>> chip->options |= NAND_SKIP_BBTSCAN;
>>
>
> Hm, here you have a problem. The layout you described replaces BBMs by
> payload data, thus preventing the BBM scan approach (or at least, it
> won't work with factory BBMs).
As I answered in another mail, the Denali IP expects BBMs
at the beginning of each OOB area (standard location).
They are protected from the ECC engine.
I just did not mention the BBM-reserved area
to make the story simpler.
So, after fixing oob read/write functions,
the driver will be able to enable BBT-scanning.
--
Best Regards
Masahiro Yamada
On Sun, Nov 27, 2016 at 03:06:08AM +0900, Masahiro Yamada wrote:
> The driver sets appropriate DMA mask. Delete the "dma-mask" DT
> property. Refer to the Link tag for negative opinions for this
> binding.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> Link: https://lkml.org/lkml/2016/2/8/57
> ---
>
> Documentation/devicetree/bindings/mtd/denali-nand.txt | 2 --
> drivers/mtd/nand/denali_dt.c | 9 ---------
> 2 files changed, 11 deletions(-)
Acked-by: Rob Herring <[email protected]>
On Sun, Nov 27, 2016 at 03:06:19AM +0900, Masahiro Yamada wrote:
> This driver was originally written for the Intel MRST platform with
> several platform specific parameters hard-coded. Another thing we
> need to fix is the hard-coded ECC step size. Currently, it is
> defined as follows:
>
> #define ECC_SECTOR_SIZE 512
>
> (somehow, it is defined in both denali.c and denali.h)
>
> This must be avoided because the Denali IP supports 1024 byte ECC
> size as well. Add a new flag DENALI_CAPS_ECC_SIZE_1024. If it is
> specified, ecc.size is set to 1024, otherwise set to 512.
>
> We can use "nand-ecc-step-size" DT property to override the ecc.size
> if we want, but this capability flag can provide the reasonable
> default because it is associated with the DT compatible strings.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> .../devicetree/bindings/mtd/denali-nand.txt | 4 ++++
Acked-by: Rob Herring <[email protected]>
> drivers/mtd/nand/denali.c | 26 +++++++++++-----------
> drivers/mtd/nand/denali.h | 3 +--
> 3 files changed, 18 insertions(+), 15 deletions(-)
On Sun, Nov 27, 2016 at 03:06:25AM +0900, Masahiro Yamada wrote:
> Add two compatible strings for UniPhier SoCs. The revision register
> on both shows revision 5.0, but they are different hardware.
>
> Features:
> - DMA engine with 64 bit physical address support
> - 1024 byte ECC step size
> - 8 / 16 / 24 bit ECC strength
> - The n_banks format depends on SoC
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> .../devicetree/bindings/mtd/denali-nand.txt | 10 +++++--
> drivers/mtd/nand/denali_dt.c | 33 ++++++++++++++++++++--
> 2 files changed, 38 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
> index 51fe195..cea46e2 100644
> --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
> +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
> @@ -1,13 +1,19 @@
> * Denali NAND controller
>
> Required properties:
> - - compatible : should be "denali,denali-nand-dt"
> + - compatible : should be one of the following:
> + "denali,denali-nand-dt"
There are multiple things wrong with this string. denali,denali is
redundant is one. It's also fairly useless as this IP has several
versions and numerous configuration options IIRC. This should be
deprecated IMO.
> + "denali,denali-nand-uniphier-v5a"
> + "denali,denali-nand-uniphier-v5b"
Use your vendor prefix, not denali. The 2nd denali can probably be
dropped because it is not likely you have another kind of nand
controller in the SoC.
> - reg : should contain registers location and length for data and reg.
> - reg-names: Should contain the reg names "nand_data" and "denali_reg"
> - interrupts : The interrupt number.
>
> Optional properties:
> - - nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
> + - nand-ecc-step-size: must be 512 or 1024. If not specified, default to:
> + 512 for "denali,denali-nand-dt"
> + 1024 for "denali,denali-nand-uniphier-v5a"
> + 1024 for "denali,denali-nand-uniphier-v5b"
> see nand.txt for details.
> - nand-ecc-strength: see nand.txt for details
> - nand-ecc-maximize: see nand.txt for details
On Sun, Nov 27, 2016 at 03:06:23AM +0900, Masahiro Yamada wrote:
> Historically, this driver tried to choose as big ECC strength as
> possible, but it would be reasonable to allow DT to set a particular
> ECC strength with "nand-ecc-strength" property.
>
> Going forward, DT platforms should specify "nand-ecc-strength" or
> "nand-ecc-maximize" to show the ECC strength strategy explicitly.
>
> If nothing is specified in DT, "nand-ecc-maximize" is implied since
> this was the original behavior. It applies to PCI platforms too.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> .../devicetree/bindings/mtd/denali-nand.txt | 5 ++++
I'd prefer all the DT changes be in 1 patch, but
Acked-by: Rob Herring <[email protected]>
> drivers/mtd/nand/denali.c | 27 +++++++++++++++++++++-
> drivers/mtd/nand/denali_pci.c | 2 ++
> 3 files changed, 33 insertions(+), 1 deletion(-)
Hi Rob,
(+CC Dinh)
2016-12-02 1:05 GMT+09:00 Rob Herring <[email protected]>:
> On Sun, Nov 27, 2016 at 03:06:25AM +0900, Masahiro Yamada wrote:
>> Add two compatible strings for UniPhier SoCs. The revision register
>> on both shows revision 5.0, but they are different hardware.
>>
>> Features:
>> - DMA engine with 64 bit physical address support
>> - 1024 byte ECC step size
>> - 8 / 16 / 24 bit ECC strength
>> - The n_banks format depends on SoC
>>
>> Signed-off-by: Masahiro Yamada <[email protected]>
>> ---
>>
>> .../devicetree/bindings/mtd/denali-nand.txt | 10 +++++--
>> drivers/mtd/nand/denali_dt.c | 33 ++++++++++++++++++++--
>> 2 files changed, 38 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
>> index 51fe195..cea46e2 100644
>> --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
>> +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
>> @@ -1,13 +1,19 @@
>> * Denali NAND controller
>>
>> Required properties:
>> - - compatible : should be "denali,denali-nand-dt"
>> + - compatible : should be one of the following:
>> + "denali,denali-nand-dt"
>
> There are multiple things wrong with this string. denali,denali is
> redundant is one.
One more redundancy; "-dt" is weird because
DT compatible should be a name of hardware.
> It's also fairly useless as this IP has several
> versions and numerous configuration options IIRC. This should be
> deprecated IMO.
Right. There are several customizable parameters for this IP,
so a generic compatible string like this is probably useless.
This DT binding was added by commit 30f9f2f for Altera SOCFPGA,
A funny thing is that they upstreamed DT binding, but they did not upstream
needed changes for the Denali driver core.
So, the mainline driver has never worked on SOCFPGA
(or any of DT-based SoCs).
>> + "denali,denali-nand-uniphier-v5a"
>> + "denali,denali-nand-uniphier-v5b"
>
> Use your vendor prefix, not denali. The 2nd denali can probably be
> dropped because it is not likely you have another kind of nand
> controller in the SoC.
Hmm, your statement implies that a vendor prefix
belongs to an SoC vendor, not an IP vendor.
(I was not quite sure about this.)
It is unlikely to happen to have two different NAND controllers on one SoC.
But, we used a different NAND controller for our SoC family before
introducing the Denali IP.
It also implies that Socionext may use a different NAND IP in the future.
I'd like to include "denali" somewhere because it is clearly associated with
the driver name.
Also, this will give an idea what kind of _basic_ hardware is used,
even though we know various parameters are customizable.
(Plan A)
"denali,socfpga-nand" (for Altera SOCFPGA variant)
"denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
"denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
(Plan B)
"altera,denali-nand" (for Altera SOCFPGA variant)
"socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
"socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
I think Plan B is nearer to your suggestion,
and I think it is OK for Socionext (hopefully for Altera too).
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 0:42 GMT+09:00 Boris Brezillon <[email protected]>:
>> + if (err_byte < ECC_SECTOR_SIZE) {
>> + struct mtd_info *mtd =
>> + nand_to_mtd(&denali->nand);
>> + int offset;
>> +
>> + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
>> + denali->devnum + err_device;
>> + /* correct the ECC error */
>> + buf[offset] ^= err_correction_value;
>> + mtd->ecc_stats.corrected++;
>> + bitflips++;
>
> Hm, bitflips is what is set in max_bitflips, and apparently the
> implementation (which is not yours) is not doing what the core expects.
>
> You should first count bitflips per sector with something like that:
>
> bitflips[err_sector]++;
>
>
> And then once you've iterated over all errors do:
>
> for (i = 0; i < nsectors; i++)
> max_bitflips = max(bitflips[err_sector], max_bitflips);
I see.
For soft ECC fixup, we can calculate bitflips
for each ECC sector, so I can fix the max_bitflips
as the core framework expects.
For hard ECC fixup, the register only reports
the number of corrected bit-flips
in the whole page (sum from all ECC sectors).
We cannot calculate max_bitflips, I think.
BTW, I noticed another problem of the current code.
buf[offset] ^= err_correction_value;
mtd->ecc_stats.corrected++;
bitflips++;
This code is counting the number of corrected bytes,
not the number of corrected bits.
I think multiple bit-flips within one byte can happen.
Perhaps, we should add
hweight8(buf[offset] ^ err_correction_value)
to ecc_stats.corrected and bitflips.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 0:31 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:05:59 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> Update the number of corrected bit flips when read_page() succeeds.
>>
>> Signed-off-by: Masahiro Yamada <[email protected]>
>> ---
>>
>> drivers/mtd/nand/denali.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
>> index a6445d9..4cc8945 100644
>> --- a/drivers/mtd/nand/denali.c
>> +++ b/drivers/mtd/nand/denali.c
>> @@ -1162,6 +1162,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
>> mtd->ecc_stats.failed++;
>> return 0;
>> }
>> +
>> + mtd->ecc_stats.corrected += max_bitflips;
>
> First of all, ecc_stats.corrected should contain the total number of
> bitflips detected on the MTD device, here you're just adding the
> maximum number of bitflips per ECC chunk for the current page, which is
> slightly different.
>
> Then, ecc_stats.corrected seems to be properly updated in handle_ecc()
> [1], so I see no reason to do it here.
>
You are right.
This patch is completely wrong, so I will drop it in v2.
--
Best Regards
Masahiro Yamada
Hi Boris,
2016-11-28 0:21 GMT+09:00 Boris Brezillon <[email protected]>:
> On Sun, 27 Nov 2016 03:05:55 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> Currently, is_erased() is called against "buf" twice, so the second
>> call is meaningless. The second one should be checked against
>> chip->oob_poi.
>>
>
> IMO, patch 9 to 12 should be squashed in a single patch. All you're
> doing in these patch is fixing the check_erased_page logic.
>
> You can describe the different broken thing in the commit message, but
> splitting things as you do does not help much.
OK. I will do so.
I realized some mistakes in this part
(both in my patches and in the current mainline code),
so I will rework it in a more sensible chunk.
> Also, please have at nand_check_erased_ecc_chunk() [1] instead of using
> a private method (is_erased()) to check if the page is erased.
> With this method you get bitflips in erased pages correction for free.
I will use this helper, thanks!
With this, I think I answered all of your questions to v1.
(Please tell me if there is something I missed to answer.)
Thanks a lot for your review.
--
Best Regards
Masahiro Yamada
On Fri, 2 Dec 2016 13:26:27 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
>
> 2016-11-28 0:42 GMT+09:00 Boris Brezillon <[email protected]>:
> >> + if (err_byte < ECC_SECTOR_SIZE) {
> >> + struct mtd_info *mtd =
> >> + nand_to_mtd(&denali->nand);
> >> + int offset;
> >> +
> >> + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
> >> + denali->devnum + err_device;
> >> + /* correct the ECC error */
> >> + buf[offset] ^= err_correction_value;
> >> + mtd->ecc_stats.corrected++;
> >> + bitflips++;
> >
> > Hm, bitflips is what is set in max_bitflips, and apparently the
> > implementation (which is not yours) is not doing what the core expects.
> >
> > You should first count bitflips per sector with something like that:
> >
> > bitflips[err_sector]++;
> >
> >
> > And then once you've iterated over all errors do:
> >
> > for (i = 0; i < nsectors; i++)
> > max_bitflips = max(bitflips[err_sector], max_bitflips);
>
>
> I see.
>
> For soft ECC fixup, we can calculate bitflips
> for each ECC sector, so I can fix the max_bitflips
> as the core framework expects.
>
> For hard ECC fixup, the register only reports
> the number of corrected bit-flips
> in the whole page (sum from all ECC sectors).
> We cannot calculate max_bitflips, I think.
>
That's unfortunate. This means you'll return -EUCLEAN more quickly
(which will trigger UBI eraseblock move), since the NAND framework is
basing its 'too many bitflips' detection logic on the max_bitflips per
ECC chunk and the bitflips threshold (by default 3/4 of the ECC
strength).
That doesn't mean it won't work, you'll just wear your NAND more
quickly :-(.
ITOH, doing max_bitflips = nbitflips / nsteps is not good either,
because the bitflips might be all concentrated in the same ECC chunk,
and in this case you really want to return -EUCLEAN.
>
>
> BTW, I noticed another problem of the current code.
>
> buf[offset] ^= err_correction_value;
> mtd->ecc_stats.corrected++;
> bitflips++;
>
> This code is counting the number of corrected bytes,
> not the number of corrected bits.
>
>
> I think multiple bit-flips within one byte can happen.
Yes.
>
>
> Perhaps, we should add
>
> hweight8(buf[offset] ^ err_correction_value)
>
> to ecc_stats.corrected and bitflips.
>
Looks good.
On Fri, 2 Dec 2016 13:33:58 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
>
> 2016-11-28 0:21 GMT+09:00 Boris Brezillon <[email protected]>:
> > On Sun, 27 Nov 2016 03:05:55 +0900
> > Masahiro Yamada <[email protected]> wrote:
> >
> >> Currently, is_erased() is called against "buf" twice, so the second
> >> call is meaningless. The second one should be checked against
> >> chip->oob_poi.
> >>
> >
> > IMO, patch 9 to 12 should be squashed in a single patch. All you're
> > doing in these patch is fixing the check_erased_page logic.
> >
> > You can describe the different broken thing in the commit message, but
> > splitting things as you do does not help much.
>
>
> OK. I will do so.
>
> I realized some mistakes in this part
> (both in my patches and in the current mainline code),
> so I will rework it in a more sensible chunk.
>
>
> > Also, please have at nand_check_erased_ecc_chunk() [1] instead of using
> > a private method (is_erased()) to check if the page is erased.
> > With this method you get bitflips in erased pages correction for free.
>
> I will use this helper, thanks!
>
>
>
>
> With this, I think I answered all of your questions to v1.
You did. I'm waiting for the v2 now ;)
>
> (Please tell me if there is something I missed to answer.)
>
> Thanks a lot for your review.
>
>
>
On Thu, Dec 1, 2016 at 8:54 PM, Masahiro Yamada
<[email protected]> wrote:
> Hi Rob,
> (+CC Dinh)
>
> 2016-12-02 1:05 GMT+09:00 Rob Herring <[email protected]>:
>> On Sun, Nov 27, 2016 at 03:06:25AM +0900, Masahiro Yamada wrote:
>>> Add two compatible strings for UniPhier SoCs. The revision register
>>> on both shows revision 5.0, but they are different hardware.
>>>
>>> Features:
>>> - DMA engine with 64 bit physical address support
>>> - 1024 byte ECC step size
>>> - 8 / 16 / 24 bit ECC strength
>>> - The n_banks format depends on SoC
>>>
>>> Signed-off-by: Masahiro Yamada <[email protected]>
>>> ---
>>>
>>> .../devicetree/bindings/mtd/denali-nand.txt | 10 +++++--
>>> drivers/mtd/nand/denali_dt.c | 33 ++++++++++++++++++++--
>>> 2 files changed, 38 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
>>> index 51fe195..cea46e2 100644
>>> --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
>>> +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
>>> @@ -1,13 +1,19 @@
>>> * Denali NAND controller
>>>
>>> Required properties:
>>> - - compatible : should be "denali,denali-nand-dt"
>>> + - compatible : should be one of the following:
>>> + "denali,denali-nand-dt"
>>
>> There are multiple things wrong with this string. denali,denali is
>> redundant is one.
>
> One more redundancy; "-dt" is weird because
> DT compatible should be a name of hardware.
>
>
>> It's also fairly useless as this IP has several
>> versions and numerous configuration options IIRC. This should be
>> deprecated IMO.
>
> Right. There are several customizable parameters for this IP,
> so a generic compatible string like this is probably useless.
>
> This DT binding was added by commit 30f9f2f for Altera SOCFPGA,
> A funny thing is that they upstreamed DT binding, but they did not upstream
> needed changes for the Denali driver core.
> So, the mainline driver has never worked on SOCFPGA
> (or any of DT-based SoCs).
>
>
>
>>> + "denali,denali-nand-uniphier-v5a"
>>> + "denali,denali-nand-uniphier-v5b"
>>
>> Use your vendor prefix, not denali. The 2nd denali can probably be
>> dropped because it is not likely you have another kind of nand
>> controller in the SoC.
>
> Hmm, your statement implies that a vendor prefix
> belongs to an SoC vendor, not an IP vendor.
> (I was not quite sure about this.)
Right. We do have some IP vendor strings, but they are usually
fallbacks. Sometimes, I guess they are useful, but IMO over time they
prove to not be useful.
> It is unlikely to happen to have two different NAND controllers on one SoC.
> But, we used a different NAND controller for our SoC family before
> introducing the Denali IP.
> It also implies that Socionext may use a different NAND IP in the future.
> I'd like to include "denali" somewhere because it is clearly associated with
> the driver name.
> Also, this will give an idea what kind of _basic_ hardware is used,
> even though we know various parameters are customizable.
>
>
>
> (Plan A)
> "denali,socfpga-nand" (for Altera SOCFPGA variant)
> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>
> (Plan B)
> "altera,denali-nand" (for Altera SOCFPGA variant)
> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
Let the Altera folks worry about their stuff. At least for soft IP in
FPGA, it's a bit of a special case. The old string can remain as bad
as it is. I simply would do "socionext,uniphier-v5b-nand" (and v5a).
The fact that it is denali is part of the documentation.
Rob
Hi Rob,
2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>
>>
>> (Plan A)
>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>
>> (Plan B)
>> "altera,denali-nand" (for Altera SOCFPGA variant)
>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
> Let the Altera folks worry about their stuff. At least for soft IP in
> FPGA, it's a bit of a special case. The old string can remain as bad
> as it is.
Hmm, I am not sure if this IP would fit in FPGA
(to use it along with NIOS-II?)
(even if it happened, nothing of this IP would be customizable on users' side.
When buying the IP, SoC vendors submit a list of desired features.
Denali (now Cadence) generates the RTL according to the configuration sheet.
The function is fixed at this point. So, generic compatible would be
useless anyway.)
If we are talking about SOCFPGA,
SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
It consists of two parts:
[1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
USB, SD, NAND, ...)
[2] FPGA part (User design logic)
The Denali NAND controller is included in [1].
So, as far as we talk about the Denali on SOCFPGA,
it is as hard-wired as Intel, Socionext's ones.
> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
> The fact that it is denali is part of the documentation.
>
Let me think about this.
Socionext bought two version of Denali IP,
and we are now re-using the newer one (v5b) for several SoCs.
Socionext has some more product lines other than Uniphier SoC family,
perhaps wider re-use might happen in the future.
At first, I included "uniphier" in compatible, but I am still wondering
if such a specific string is good or not.
Also, comments from Altera engineers are appreciated.
--
Best Regards
Masahiro Yamada
On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
> Hi Rob,
Hi!
> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>
>>>
>>>
>>> (Plan A)
>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>
>>> (Plan B)
>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>
>> Let the Altera folks worry about their stuff. At least for soft IP in
>> FPGA, it's a bit of a special case. The old string can remain as bad
>> as it is.
>
>
> Hmm, I am not sure if this IP would fit in FPGA
> (to use it along with NIOS-II?)
>
> (even if it happened, nothing of this IP would be customizable on users' side.
> When buying the IP, SoC vendors submit a list of desired features.
> Denali (now Cadence) generates the RTL according to the configuration sheet.
> The function is fixed at this point. So, generic compatible would be
> useless anyway.)
>
>
> If we are talking about SOCFPGA,
> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
> It consists of two parts:
> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
> USB, SD, NAND, ...)
> [2] FPGA part (User design logic)
>
> The Denali NAND controller is included in [1].
> So, as far as we talk about the Denali on SOCFPGA,
> it is as hard-wired as Intel, Socionext's ones.
That's correct, the Denali NAND IP in altera socfpga is a hardware
block. You can make it available to the fabric too, but by default
it's used by the ARM part of the chip, so for this discussion, you
can forget that the FPGA part exists altogether.
I would be in favor of plan B, since it seems to be the more often
taken approach. A nice example is ci-hdrc:
$ git grep compatible drivers/usb/chipidea/
>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>> The fact that it is denali is part of the documentation.
>>
>
> Let me think about this.
>
> Socionext bought two version of Denali IP,
> and we are now re-using the newer one (v5b) for several SoCs.
> Socionext has some more product lines other than Uniphier SoC family,
> perhaps wider re-use might happen in the future.
>
> At first, I included "uniphier" in compatible, but I am still wondering
> if such a specific string is good or not.
>
> Also, comments from Altera engineers are appreciated.
Adding a few more on Cc
--
Best regards,
Marek Vasut
Hi,
On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>> Hi Rob,
>
> Hi!
>
>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>
>>>>
>>>>
>>>> (Plan A)
>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>
>>>> (Plan B)
>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>
>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>> as it is.
>>
>>
>> Hmm, I am not sure if this IP would fit in FPGA
>> (to use it along with NIOS-II?)
>>
>> (even if it happened, nothing of this IP would be customizable on users' side.
>> When buying the IP, SoC vendors submit a list of desired features.
>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>> The function is fixed at this point. So, generic compatible would be
>> useless anyway.)
>>
>>
>> If we are talking about SOCFPGA,
>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>> It consists of two parts:
>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>> USB, SD, NAND, ...)
>> [2] FPGA part (User design logic)
>>
>> The Denali NAND controller is included in [1].
>> So, as far as we talk about the Denali on SOCFPGA,
>> it is as hard-wired as Intel, Socionext's ones.
>
> That's correct, the Denali NAND IP in altera socfpga is a hardware
> block. You can make it available to the fabric too, but by default
> it's used by the ARM part of the chip, so for this discussion, you
> can forget that the FPGA part exists altogether.
>
> I would be in favor of plan B, since it seems to be the more often
> taken approach. A nice example is ci-hdrc:
>
> $ git grep compatible drivers/usb/chipidea/
>
>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>> The fact that it is denali is part of the documentation.
>>>
>>
>> Let me think about this.
>>
>> Socionext bought two version of Denali IP,
>> and we are now re-using the newer one (v5b) for several SoCs.
>> Socionext has some more product lines other than Uniphier SoC family,
>> perhaps wider re-use might happen in the future.
>>
>> At first, I included "uniphier" in compatible, but I am still wondering
>> if such a specific string is good or not.
>>
>> Also, comments from Altera engineers are appreciated.
Sorry, it's taken me a while to add comments. My altera email is very spotty now
that the Intel merge is completed. Please use [email protected] for any future
communications.
Yes, everything that is said so far for the NAND controller on the
SoCFPGA is correct. I added the binding for the controller a while
back, but unfortunately, we never added the NAND interface to the
devkit, so we did not do much in terms of enabling it.
I think the only SoCFPGA board I know that has the NAND interface active is
the TRCom board, but I have never seen that board.
I don't have any strong opinions on this matter, just as long as the
original binding
"denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
that binding.
Dinh
Hi Dinh,
2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
> Hi,
>
> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>> Hi Rob,
>>
>> Hi!
>>
>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>
>>>>>
>>>>>
>>>>> (Plan A)
>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>
>>>>> (Plan B)
>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>
>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>> as it is.
>>>
>>>
>>> Hmm, I am not sure if this IP would fit in FPGA
>>> (to use it along with NIOS-II?)
>>>
>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>> When buying the IP, SoC vendors submit a list of desired features.
>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>> The function is fixed at this point. So, generic compatible would be
>>> useless anyway.)
>>>
>>>
>>> If we are talking about SOCFPGA,
>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>> It consists of two parts:
>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>> USB, SD, NAND, ...)
>>> [2] FPGA part (User design logic)
>>>
>>> The Denali NAND controller is included in [1].
>>> So, as far as we talk about the Denali on SOCFPGA,
>>> it is as hard-wired as Intel, Socionext's ones.
>>
>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>> block. You can make it available to the fabric too, but by default
>> it's used by the ARM part of the chip, so for this discussion, you
>> can forget that the FPGA part exists altogether.
>>
>> I would be in favor of plan B, since it seems to be the more often
>> taken approach. A nice example is ci-hdrc:
>>
>> $ git grep compatible drivers/usb/chipidea/
>>
>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>> The fact that it is denali is part of the documentation.
>>>>
>>>
>>> Let me think about this.
>>>
>>> Socionext bought two version of Denali IP,
>>> and we are now re-using the newer one (v5b) for several SoCs.
>>> Socionext has some more product lines other than Uniphier SoC family,
>>> perhaps wider re-use might happen in the future.
>>>
>>> At first, I included "uniphier" in compatible, but I am still wondering
>>> if such a specific string is good or not.
>>>
>>> Also, comments from Altera engineers are appreciated.
>
> Sorry, it's taken me a while to add comments. My altera email is very spotty now
> that the Intel merge is completed. Please use [email protected] for any future
> communications.
>
> Yes, everything that is said so far for the NAND controller on the
> SoCFPGA is correct. I added the binding for the controller a while
> back, but unfortunately, we never added the NAND interface to the
> devkit, so we did not do much in terms of enabling it.
>
> I think the only SoCFPGA board I know that has the NAND interface active is
> the TRCom board, but I have never seen that board.
>
> I don't have any strong opinions on this matter, just as long as the
> original binding
> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
> that binding.
>
I am proposing to add "altera,denali-nand" for Altera.
For what, do you need the generic compatible?
This IP has no default for it to fallback to.
--
Best Regards
Masahiro Yamada
On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
> Hi Dinh,
>
>
> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>> Hi,
>>
>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>> Hi Rob,
>>>
>>> Hi!
>>>
>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>
>>>>>>
>>>>>>
>>>>>> (Plan A)
>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>
>>>>>> (Plan B)
>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>
>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>> as it is.
>>>>
>>>>
>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>> (to use it along with NIOS-II?)
>>>>
>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>> The function is fixed at this point. So, generic compatible would be
>>>> useless anyway.)
>>>>
>>>>
>>>> If we are talking about SOCFPGA,
>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>> It consists of two parts:
>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>> USB, SD, NAND, ...)
>>>> [2] FPGA part (User design logic)
>>>>
>>>> The Denali NAND controller is included in [1].
>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>> it is as hard-wired as Intel, Socionext's ones.
>>>
>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>> block. You can make it available to the fabric too, but by default
>>> it's used by the ARM part of the chip, so for this discussion, you
>>> can forget that the FPGA part exists altogether.
>>>
>>> I would be in favor of plan B, since it seems to be the more often
>>> taken approach. A nice example is ci-hdrc:
>>>
>>> $ git grep compatible drivers/usb/chipidea/
>>>
>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>> The fact that it is denali is part of the documentation.
>>>>>
>>>>
>>>> Let me think about this.
>>>>
>>>> Socionext bought two version of Denali IP,
>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>> perhaps wider re-use might happen in the future.
>>>>
>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>> if such a specific string is good or not.
>>>>
>>>> Also, comments from Altera engineers are appreciated.
>>
>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>> that the Intel merge is completed. Please use [email protected] for any future
>> communications.
>>
>> Yes, everything that is said so far for the NAND controller on the
>> SoCFPGA is correct. I added the binding for the controller a while
>> back, but unfortunately, we never added the NAND interface to the
>> devkit, so we did not do much in terms of enabling it.
>>
>> I think the only SoCFPGA board I know that has the NAND interface active is
>> the TRCom board, but I have never seen that board.
>>
>> I don't have any strong opinions on this matter, just as long as the
>> original binding
>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>> that binding.
>>
>
> I am proposing to add "altera,denali-nand" for Altera.
> For what, do you need the generic compatible?
> This IP has no default for it to fallback to.
IMO just for compatibility reasons with old DTs .
I'm also for "altera,denali-nand" or maybe "altera,socfpga-denali-nand"
to be more precise ?
--
Best regards,
Marek Vasut
Hi Marek,
2016-12-05 12:44 GMT+09:00 Marek Vasut <[email protected]>:
> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>> Hi Dinh,
>>
>>
>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>>> Hi,
>>>
>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>> Hi Rob,
>>>>
>>>> Hi!
>>>>
>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>>
>>>>>>>
>>>>>>>
>>>>>>> (Plan A)
>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>
>>>>>>> (Plan B)
>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>
>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>> as it is.
>>>>>
>>>>>
>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>> (to use it along with NIOS-II?)
>>>>>
>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>> The function is fixed at this point. So, generic compatible would be
>>>>> useless anyway.)
>>>>>
>>>>>
>>>>> If we are talking about SOCFPGA,
>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>> It consists of two parts:
>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>> USB, SD, NAND, ...)
>>>>> [2] FPGA part (User design logic)
>>>>>
>>>>> The Denali NAND controller is included in [1].
>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>
>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>> block. You can make it available to the fabric too, but by default
>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>> can forget that the FPGA part exists altogether.
>>>>
>>>> I would be in favor of plan B, since it seems to be the more often
>>>> taken approach. A nice example is ci-hdrc:
>>>>
>>>> $ git grep compatible drivers/usb/chipidea/
>>>>
>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>> The fact that it is denali is part of the documentation.
>>>>>>
>>>>>
>>>>> Let me think about this.
>>>>>
>>>>> Socionext bought two version of Denali IP,
>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>> perhaps wider re-use might happen in the future.
>>>>>
>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>> if such a specific string is good or not.
>>>>>
>>>>> Also, comments from Altera engineers are appreciated.
>>>
>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>> that the Intel merge is completed. Please use [email protected] for any future
>>> communications.
>>>
>>> Yes, everything that is said so far for the NAND controller on the
>>> SoCFPGA is correct. I added the binding for the controller a while
>>> back, but unfortunately, we never added the NAND interface to the
>>> devkit, so we did not do much in terms of enabling it.
>>>
>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>> the TRCom board, but I have never seen that board.
>>>
>>> I don't have any strong opinions on this matter, just as long as the
>>> original binding
>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>> that binding.
>>>
>>
>> I am proposing to add "altera,denali-nand" for Altera.
>> For what, do you need the generic compatible?
>> This IP has no default for it to fallback to.
>
> IMO just for compatibility reasons with old DTs .
We generally contribute for
a "working driver" (at least, should be functional to some extent)
and "DT binding" bundled together.
However, Altera upstreamed the DT binding first
(then some parts of the DT binding turned out wrong),
but they did not upstream needed driver changes in the end.
So, the mainline driver has never worked on SOCFPGA, right?
Removing "denali,denali-nand-dt" is not breakage at all,
so I do not owe anything to them, right?
--
Best Regards
Masahiro Yamada
On 12/05/2016 05:10 AM, Masahiro Yamada wrote:
> Hi Marek,
>
>
> 2016-12-05 12:44 GMT+09:00 Marek Vasut <[email protected]>:
>> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>>> Hi Dinh,
>>>
>>>
>>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>>>> Hi,
>>>>
>>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>>> Hi Rob,
>>>>>
>>>>> Hi!
>>>>>
>>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> (Plan A)
>>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>>
>>>>>>>> (Plan B)
>>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>>
>>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>>> as it is.
>>>>>>
>>>>>>
>>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>>> (to use it along with NIOS-II?)
>>>>>>
>>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>>> The function is fixed at this point. So, generic compatible would be
>>>>>> useless anyway.)
>>>>>>
>>>>>>
>>>>>> If we are talking about SOCFPGA,
>>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>>> It consists of two parts:
>>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>>> USB, SD, NAND, ...)
>>>>>> [2] FPGA part (User design logic)
>>>>>>
>>>>>> The Denali NAND controller is included in [1].
>>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>>
>>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>>> block. You can make it available to the fabric too, but by default
>>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>>> can forget that the FPGA part exists altogether.
>>>>>
>>>>> I would be in favor of plan B, since it seems to be the more often
>>>>> taken approach. A nice example is ci-hdrc:
>>>>>
>>>>> $ git grep compatible drivers/usb/chipidea/
>>>>>
>>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>>> The fact that it is denali is part of the documentation.
>>>>>>>
>>>>>>
>>>>>> Let me think about this.
>>>>>>
>>>>>> Socionext bought two version of Denali IP,
>>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>>> perhaps wider re-use might happen in the future.
>>>>>>
>>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>>> if such a specific string is good or not.
>>>>>>
>>>>>> Also, comments from Altera engineers are appreciated.
>>>>
>>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>>> that the Intel merge is completed. Please use [email protected] for any future
>>>> communications.
>>>>
>>>> Yes, everything that is said so far for the NAND controller on the
>>>> SoCFPGA is correct. I added the binding for the controller a while
>>>> back, but unfortunately, we never added the NAND interface to the
>>>> devkit, so we did not do much in terms of enabling it.
>>>>
>>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>>> the TRCom board, but I have never seen that board.
>>>>
>>>> I don't have any strong opinions on this matter, just as long as the
>>>> original binding
>>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>>> that binding.
>>>>
>>>
>>> I am proposing to add "altera,denali-nand" for Altera.
>>> For what, do you need the generic compatible?
>>> This IP has no default for it to fallback to.
>>
>> IMO just for compatibility reasons with old DTs .
>
> We generally contribute for
> a "working driver" (at least, should be functional to some extent)
> and "DT binding" bundled together.
>
> However, Altera upstreamed the DT binding first
> (then some parts of the DT binding turned out wrong),
> but they did not upstream needed driver changes in the end.
>
> So, the mainline driver has never worked on SOCFPGA, right?
Most likely it never worked, yes.
> Removing "denali,denali-nand-dt" is not breakage at all,
> so I do not owe anything to them, right?
I don't think I'm really qualified to answer this one. But, there is
drivers/mtd/nand/denali_dt.c , which handles this compatible string
and it's documented in
Documentation/devicetree/bindings/mtd/denali-nand.txt, so doesn't that
make it part of the ABI ? I think we should
at least keep it as a fallback, that should be pretty harmless.
--
Best regards,
Marek Vasut
On Sun, Dec 4, 2016 at 10:22 PM, Marek Vasut <[email protected]> wrote:
> On 12/05/2016 05:10 AM, Masahiro Yamada wrote:
>> Hi Marek,
>>
>>
>> 2016-12-05 12:44 GMT+09:00 Marek Vasut <[email protected]>:
>>> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>>>> Hi Dinh,
>>>>
>>>>
>>>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>>>>> Hi,
>>>>>
>>>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>>>> Hi Rob,
>>>>>>
>>>>>> Hi!
>>>>>>
>>>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> (Plan A)
>>>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>>>
>>>>>>>>> (Plan B)
>>>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>>>
>>>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>>>> as it is.
>>>>>>>
>>>>>>>
>>>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>>>> (to use it along with NIOS-II?)
>>>>>>>
>>>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>>>> The function is fixed at this point. So, generic compatible would be
>>>>>>> useless anyway.)
>>>>>>>
>>>>>>>
>>>>>>> If we are talking about SOCFPGA,
>>>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>>>> It consists of two parts:
>>>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>>>> USB, SD, NAND, ...)
>>>>>>> [2] FPGA part (User design logic)
>>>>>>>
>>>>>>> The Denali NAND controller is included in [1].
>>>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>>>
>>>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>>>> block. You can make it available to the fabric too, but by default
>>>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>>>> can forget that the FPGA part exists altogether.
>>>>>>
>>>>>> I would be in favor of plan B, since it seems to be the more often
>>>>>> taken approach. A nice example is ci-hdrc:
>>>>>>
>>>>>> $ git grep compatible drivers/usb/chipidea/
>>>>>>
>>>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>>>> The fact that it is denali is part of the documentation.
>>>>>>>>
>>>>>>>
>>>>>>> Let me think about this.
>>>>>>>
>>>>>>> Socionext bought two version of Denali IP,
>>>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>>>> perhaps wider re-use might happen in the future.
>>>>>>>
>>>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>>>> if such a specific string is good or not.
>>>>>>>
>>>>>>> Also, comments from Altera engineers are appreciated.
>>>>>
>>>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>>>> that the Intel merge is completed. Please use [email protected] for any future
>>>>> communications.
>>>>>
>>>>> Yes, everything that is said so far for the NAND controller on the
>>>>> SoCFPGA is correct. I added the binding for the controller a while
>>>>> back, but unfortunately, we never added the NAND interface to the
>>>>> devkit, so we did not do much in terms of enabling it.
>>>>>
>>>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>>>> the TRCom board, but I have never seen that board.
>>>>>
>>>>> I don't have any strong opinions on this matter, just as long as the
>>>>> original binding
>>>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>>>> that binding.
>>>>>
>>>>
>>>> I am proposing to add "altera,denali-nand" for Altera.
>>>> For what, do you need the generic compatible?
>>>> This IP has no default for it to fallback to.
>>>
>>> IMO just for compatibility reasons with old DTs .
>>
>> We generally contribute for
>> a "working driver" (at least, should be functional to some extent)
>> and "DT binding" bundled together.
>>
>> However, Altera upstreamed the DT binding first
>> (then some parts of the DT binding turned out wrong),
>> but they did not upstream needed driver changes in the end.
>>
>> So, the mainline driver has never worked on SOCFPGA, right?
>
> Most likely it never worked, yes.
>
Right, looking through our downstream support, we may need to upstream a
few changes to make upstream driver work on SoCFPGA.
>> Removing "denali,denali-nand-dt" is not breakage at all,
>> so I do not owe anything to them, right?
>
> I don't think I'm really qualified to answer this one. But, there is
> drivers/mtd/nand/denali_dt.c , which handles this compatible string
> and it's documented in
> Documentation/devicetree/bindings/mtd/denali-nand.txt, so doesn't that
> make it part of the ABI ? I think we should
> at least keep it as a fallback, that should be pretty harmless.
>
I would like to propose "altr,denali-nand" as the binding we use to support the
driver going forward on SoCFPGA hardware. It's pretty much the same as
"altera,denali-nand", just with the correct vendor prefix.
If we can please keep, "denali,denali-nand-dt" only because SoCFPGA is using
this binding downstream, but I know that is a weak argument.
Dinh
On 12/05/2016 09:51 PM, Dinh Nguyen wrote:
> On Sun, Dec 4, 2016 at 10:22 PM, Marek Vasut <[email protected]> wrote:
>> On 12/05/2016 05:10 AM, Masahiro Yamada wrote:
>>> Hi Marek,
>>>
>>>
>>> 2016-12-05 12:44 GMT+09:00 Marek Vasut <[email protected]>:
>>>> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>>>>> Hi Dinh,
>>>>>
>>>>>
>>>>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>>>>>> Hi,
>>>>>>
>>>>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>>>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>>>>> Hi Rob,
>>>>>>>
>>>>>>> Hi!
>>>>>>>
>>>>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> (Plan A)
>>>>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>>>>
>>>>>>>>>> (Plan B)
>>>>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>>>>
>>>>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>>>>> as it is.
>>>>>>>>
>>>>>>>>
>>>>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>>>>> (to use it along with NIOS-II?)
>>>>>>>>
>>>>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>>>>> The function is fixed at this point. So, generic compatible would be
>>>>>>>> useless anyway.)
>>>>>>>>
>>>>>>>>
>>>>>>>> If we are talking about SOCFPGA,
>>>>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>>>>> It consists of two parts:
>>>>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>>>>> USB, SD, NAND, ...)
>>>>>>>> [2] FPGA part (User design logic)
>>>>>>>>
>>>>>>>> The Denali NAND controller is included in [1].
>>>>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>>>>
>>>>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>>>>> block. You can make it available to the fabric too, but by default
>>>>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>>>>> can forget that the FPGA part exists altogether.
>>>>>>>
>>>>>>> I would be in favor of plan B, since it seems to be the more often
>>>>>>> taken approach. A nice example is ci-hdrc:
>>>>>>>
>>>>>>> $ git grep compatible drivers/usb/chipidea/
>>>>>>>
>>>>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>>>>> The fact that it is denali is part of the documentation.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Let me think about this.
>>>>>>>>
>>>>>>>> Socionext bought two version of Denali IP,
>>>>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>>>>> perhaps wider re-use might happen in the future.
>>>>>>>>
>>>>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>>>>> if such a specific string is good or not.
>>>>>>>>
>>>>>>>> Also, comments from Altera engineers are appreciated.
>>>>>>
>>>>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>>>>> that the Intel merge is completed. Please use [email protected] for any future
>>>>>> communications.
>>>>>>
>>>>>> Yes, everything that is said so far for the NAND controller on the
>>>>>> SoCFPGA is correct. I added the binding for the controller a while
>>>>>> back, but unfortunately, we never added the NAND interface to the
>>>>>> devkit, so we did not do much in terms of enabling it.
>>>>>>
>>>>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>>>>> the TRCom board, but I have never seen that board.
>>>>>>
>>>>>> I don't have any strong opinions on this matter, just as long as the
>>>>>> original binding
>>>>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>>>>> that binding.
>>>>>>
>>>>>
>>>>> I am proposing to add "altera,denali-nand" for Altera.
>>>>> For what, do you need the generic compatible?
>>>>> This IP has no default for it to fallback to.
>>>>
>>>> IMO just for compatibility reasons with old DTs .
>>>
>>> We generally contribute for
>>> a "working driver" (at least, should be functional to some extent)
>>> and "DT binding" bundled together.
>>>
>>> However, Altera upstreamed the DT binding first
>>> (then some parts of the DT binding turned out wrong),
>>> but they did not upstream needed driver changes in the end.
>>>
>>> So, the mainline driver has never worked on SOCFPGA, right?
>>
>> Most likely it never worked, yes.
>>
>
> Right, looking through our downstream support, we may need to upstream a
> few changes to make upstream driver work on SoCFPGA.
>
>>> Removing "denali,denali-nand-dt" is not breakage at all,
>>> so I do not owe anything to them, right?
>>
>> I don't think I'm really qualified to answer this one. But, there is
>> drivers/mtd/nand/denali_dt.c , which handles this compatible string
>> and it's documented in
>> Documentation/devicetree/bindings/mtd/denali-nand.txt, so doesn't that
>> make it part of the ABI ? I think we should
>> at least keep it as a fallback, that should be pretty harmless.
>>
>
> I would like to propose "altr,denali-nand" as the binding we use to support the
> driver going forward on SoCFPGA hardware. It's pretty much the same as
> "altera,denali-nand", just with the correct vendor prefix.
Ah right, altr is the right prefix, thanks for pointing that out.
Still, wouldn't altr,socfpga-denali-nand be better ? I know it's
long, but it encodes the chip type , like ie. fsl,imx6q-usb .
> If we can please keep, "denali,denali-nand-dt" only because SoCFPGA is using
> this binding downstream, but I know that is a weak argument.
--
Best regards,
Marek Vasut
On 12/05/2016 03:29 PM, Marek Vasut wrote:
> On 12/05/2016 09:51 PM, Dinh Nguyen wrote:
>> On Sun, Dec 4, 2016 at 10:22 PM, Marek Vasut <[email protected]> wrote:
>>> On 12/05/2016 05:10 AM, Masahiro Yamada wrote:
>>>> Hi Marek,
>>>>
>>>>
>>>> 2016-12-05 12:44 GMT+09:00 Marek Vasut <[email protected]>:
>>>>> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>>>>>> Hi Dinh,
>>>>>>
>>>>>>
>>>>>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <[email protected]>:
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <[email protected]> wrote:
>>>>>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>>>>>> Hi Rob,
>>>>>>>>
>>>>>>>> Hi!
>>>>>>>>
>>>>>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <[email protected]>:
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> (Plan A)
>>>>>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>>>>>
>>>>>>>>>>> (Plan B)
>>>>>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>>>>>
>>>>>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>>>>>> as it is.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>>>>>> (to use it along with NIOS-II?)
>>>>>>>>>
>>>>>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>>>>>> The function is fixed at this point. So, generic compatible would be
>>>>>>>>> useless anyway.)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> If we are talking about SOCFPGA,
>>>>>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>>>>>> It consists of two parts:
>>>>>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>>>>>> USB, SD, NAND, ...)
>>>>>>>>> [2] FPGA part (User design logic)
>>>>>>>>>
>>>>>>>>> The Denali NAND controller is included in [1].
>>>>>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>>>>>
>>>>>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>>>>>> block. You can make it available to the fabric too, but by default
>>>>>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>>>>>> can forget that the FPGA part exists altogether.
>>>>>>>>
>>>>>>>> I would be in favor of plan B, since it seems to be the more often
>>>>>>>> taken approach. A nice example is ci-hdrc:
>>>>>>>>
>>>>>>>> $ git grep compatible drivers/usb/chipidea/
>>>>>>>>
>>>>>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>>>>>> The fact that it is denali is part of the documentation.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Let me think about this.
>>>>>>>>>
>>>>>>>>> Socionext bought two version of Denali IP,
>>>>>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>>>>>> perhaps wider re-use might happen in the future.
>>>>>>>>>
>>>>>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>>>>>> if such a specific string is good or not.
>>>>>>>>>
>>>>>>>>> Also, comments from Altera engineers are appreciated.
>>>>>>>
>>>>>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>>>>>> that the Intel merge is completed. Please use [email protected] for any future
>>>>>>> communications.
>>>>>>>
>>>>>>> Yes, everything that is said so far for the NAND controller on the
>>>>>>> SoCFPGA is correct. I added the binding for the controller a while
>>>>>>> back, but unfortunately, we never added the NAND interface to the
>>>>>>> devkit, so we did not do much in terms of enabling it.
>>>>>>>
>>>>>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>>>>>> the TRCom board, but I have never seen that board.
>>>>>>>
>>>>>>> I don't have any strong opinions on this matter, just as long as the
>>>>>>> original binding
>>>>>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>>>>>> that binding.
>>>>>>>
>>>>>>
>>>>>> I am proposing to add "altera,denali-nand" for Altera.
>>>>>> For what, do you need the generic compatible?
>>>>>> This IP has no default for it to fallback to.
>>>>>
>>>>> IMO just for compatibility reasons with old DTs .
>>>>
>>>> We generally contribute for
>>>> a "working driver" (at least, should be functional to some extent)
>>>> and "DT binding" bundled together.
>>>>
>>>> However, Altera upstreamed the DT binding first
>>>> (then some parts of the DT binding turned out wrong),
>>>> but they did not upstream needed driver changes in the end.
>>>>
>>>> So, the mainline driver has never worked on SOCFPGA, right?
>>>
>>> Most likely it never worked, yes.
>>>
>>
>> Right, looking through our downstream support, we may need to upstream a
>> few changes to make upstream driver work on SoCFPGA.
>>
>>>> Removing "denali,denali-nand-dt" is not breakage at all,
>>>> so I do not owe anything to them, right?
>>>
>>> I don't think I'm really qualified to answer this one. But, there is
>>> drivers/mtd/nand/denali_dt.c , which handles this compatible string
>>> and it's documented in
>>> Documentation/devicetree/bindings/mtd/denali-nand.txt, so doesn't that
>>> make it part of the ABI ? I think we should
>>> at least keep it as a fallback, that should be pretty harmless.
>>>
>>
>> I would like to propose "altr,denali-nand" as the binding we use to support the
>> driver going forward on SoCFPGA hardware. It's pretty much the same as
>> "altera,denali-nand", just with the correct vendor prefix.
>
> Ah right, altr is the right prefix, thanks for pointing that out.
> Still, wouldn't altr,socfpga-denali-nand be better ? I know it's
> long, but it encodes the chip type , like ie. fsl,imx6q-usb .
>
Yes, that's fine.
Dinh
Hi Boris,
I am almost getting v2 done,
and now I am testing it.
I am having one problem. Please teach me.
2016-11-30 17:17 GMT+09:00 Boris Brezillon <[email protected]>:
>> [2]
>> Remove driver-internal bounce buffer.
>> The current Denali driver allocate DMA_BIDIRECTIONAL buffer
>> to use it as a driver-internal bounce buffer.
>>
>> The hardware transfer page data into the bounce buffer,
>> then CPU copies from the bounce buffer to a given buf (and oob_poi).
>> This is not efficient.
>>
>> So, I want to set NAND_USE_BOUNCE_BUFFER flag
>> and do dma_map_single directly for a given buffer.
>
> Sounds good. Be careful though, when you use the generic bounce buffer
> interface you might have to clear the page cache info (->pagebuf = -1).
Instead of memcpy() of the whole page,
I am trying to use dma_map_single() in ecc->read_page() / ecc->write_page().
This will allow direct transfer between the buffer and the device by DMA.
But, this does not work for Denali if use_bufpoi is set in nand_do_read_ops().
In the following code in nand_scan_tail(),
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);
if (!nbuf)
return -ENOMEM;
nbuf->ecccalc = (uint8_t *)(nbuf + 1);
nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
nbuf->databuf = nbuf->ecccode + mtd->oobsize;
chip->buffers = nbuf;
chip->buffers->databuf has no guarantee for DMA'able alignment.
(actually it has unwanted offset 0xc because sizeof(*nbuf) == 0xc on
32bit systems)
If we could change the code as follows,
nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
GFP_KERNEL);
chip->buffers->databuf would have DMA'able alignment in most cases
without NAND_OWN_BUFFERS. (but, I am not sure if this is a good idea)
So, the idea of NAND_OWN_BUFFERS is that
drivers should allocate own buffers if they need to perform DMA-mapping
in read_page(), write_page(), right?
However, "git grep NAND_OWN_BUFFERS" shows
cafe_nand.c is the only driver that does so.
On the other hand, "git grep dma_map_single" has more hits,
i.e. some drivers perform dma_map_single() for read/write without
NAND_OWN_BUFFERS.
I have no idea how they are working.
--
Best Regards
Masahiro Yamada
Hi Masahiro,
On Fri, 10 Mar 2017 20:00:03 +0900
Masahiro Yamada <[email protected]> wrote:
> Hi Boris,
>
> I am almost getting v2 done,
> and now I am testing it.
>
> I am having one problem. Please teach me.
>
>
> 2016-11-30 17:17 GMT+09:00 Boris Brezillon <[email protected]>:
> >> [2]
> >> Remove driver-internal bounce buffer.
> >> The current Denali driver allocate DMA_BIDIRECTIONAL buffer
> >> to use it as a driver-internal bounce buffer.
> >>
> >> The hardware transfer page data into the bounce buffer,
> >> then CPU copies from the bounce buffer to a given buf (and oob_poi).
> >> This is not efficient.
> >>
> >> So, I want to set NAND_USE_BOUNCE_BUFFER flag
> >> and do dma_map_single directly for a given buffer.
> >
> > Sounds good. Be careful though, when you use the generic bounce buffer
> > interface you might have to clear the page cache info (->pagebuf = -1).
>
>
> Instead of memcpy() of the whole page,
> I am trying to use dma_map_single() in ecc->read_page() / ecc->write_page().
> This will allow direct transfer between the buffer and the device by DMA.
>
> But, this does not work for Denali if use_bufpoi is set in nand_do_read_ops().
>
>
> In the following code in nand_scan_tail(),
>
> if (!(chip->options & NAND_OWN_BUFFERS)) {
> nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
> + mtd->oobsize * 3, GFP_KERNEL);
> if (!nbuf)
> return -ENOMEM;
> nbuf->ecccalc = (uint8_t *)(nbuf + 1);
> nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
> nbuf->databuf = nbuf->ecccode + mtd->oobsize;
>
> chip->buffers = nbuf;
>
>
> chip->buffers->databuf has no guarantee for DMA'able alignment.
> (actually it has unwanted offset 0xc because sizeof(*nbuf) == 0xc on
> 32bit systems)
Well, I think the DMA alignment requirement is a platform/controller
specific (some controllers are fine with this 32bits alignment), but I
get your point.
>
> If we could change the code as follows,
>
> nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
> nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
> nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
> GFP_KERNEL);
>
> chip->buffers->databuf would have DMA'able alignment in most cases
> without NAND_OWN_BUFFERS. (but, I am not sure if this is a good idea)
I'm fine with this change. I don't know what are the guarantees in term
of alignment when you use kmalloc, but I guess the size you're
allocating (writesize + oobsize) kind of guarantees that the alignment
is rather big (because the SLAB caches are organized by power-of-2
chunk sizes, and for allocations >PAGE_SIZE the page allocator will be
used).
>
>
> So, the idea of NAND_OWN_BUFFERS is that
> drivers should allocate own buffers if they need to perform DMA-mapping
> in read_page(), write_page(), right?
Right.
>
>
> However, "git grep NAND_OWN_BUFFERS" shows
> cafe_nand.c is the only driver that does so.
>
> On the other hand, "git grep dma_map_single" has more hits,
> i.e. some drivers perform dma_map_single() for read/write without
> NAND_OWN_BUFFERS.
>
> I have no idea how they are working.
Probably because the controllers and/or DMA engines have no alignment
constraints.
Anyway, the change you're proposing is rather simple, so go ahead.
Regards,
Boris