[U-Boot] [PATCH 00/19] Marvell PXA3XX NAND driver fixes and extensions

From: Konstantin Porotchkin kostap@marvell.com
This patch series introduces the PXA3XX NAND driver changes and extensions accumulated in Marvell LSP sources. Beside the bug fixes the driver is extended to support 2K page 8-bit ECC flash devices (tested with Toshiba TC58NVG1S3ETA00 chip) and 8K page 4/8 bit ECC devices (tested with Micron MT29F32G08ABAAAWP chip)
Boris Brezillon (1): mtd: nand: pxa3xx: Fix READOOB implementation
David Sniatkiwicz (1): fix: nand: pxa3xx: Add WA for eliminating flash ready timeout
Igal Liberman (1): fix: nand: pxa3xx: Add SoC-specific enable function
Konstantin Porotchkin (4): mtd: nand: pxa3xx: add support for Toshiba flash fix: nand: Replace hardcoded page chunk size with calculated one nand: pxa3xx: cosmetic: add comments to the timing layout structures nand: pxa3xx: Add support for 8KB page 4 and 8 bit ECC NAND
Ofer Heifetz (10): mtd: nand: pxa3xx_nand: Increase initial buffer size mtd: nand: pxa3xx_nand: use nand_to_mtd() mtd: nand: pxa3xx_nand: sync pxa3xx_nand_set_sdr_timing() mtd: nand: pxa3xx_nand: fix early spurious interrupt mtd: nand: pxa3xx-nand: fix random command timeouts nand: pxa3xx: Increase READ_ID buffer and make the size static mtd: pxa3xx_nand: Increase the initial chunk size mtd: pxa3xx_nand: Fix initial controller configuration mtd: pxa3xx_nand: Simplify pxa3xx_nand_scan mtd: nand: pxa3xx_nand: add support for partial chunks
Victor Axelrod (1): mtd: nand: pxa3xx: add support for 2KB 8-bit flash
zachary zhang (1): a70x0: a80x0: add soc type and revision printing in boot log
arch/arm/dts/armada-cp110-master.dtsi | 7 +- arch/arm/mach-mvebu/armada8k/Makefile | 1 + arch/arm/mach-mvebu/armada8k/cpu.c | 21 +- arch/arm/mach-mvebu/armada8k/soc.c | 160 ++++++++++ arch/arm/mach-mvebu/cpu.c | 12 +- arch/arm/mach-mvebu/include/mach/cpu.h | 3 +- arch/arm/mach-mvebu/include/mach/soc.h | 3 + common/board_f.c | 6 +- drivers/mtd/nand/pxa3xx_nand.c | 521 +++++++++++++++++++++++---------- 9 files changed, 564 insertions(+), 170 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada8k/soc.c

From: Ofer Heifetz oferh@marvell.com
The initial buffer is used for the initial commands used to detect a flash device (STATUS, READID and PARAM).
ONFI param page is 256 bytes, and there are three redundant copies to be read. JEDEC param page is 512 bytes, and there are also three redundant copies to be read. Hence this buffer should be at least 512 x 3. This commits rounds the buffer size to 2048.
This commit is taken from Linux: 'commit c16340973fcb64614' ("nand: pxa3xx: Increase initial buffer size")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 9d02fd8..ead5624 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -28,10 +28,13 @@ DECLARE_GLOBAL_DATA_PTR;
/* * Define a buffer size for the initial command that detects the flash device: - * STATUS, READID and PARAM. The largest of these is the PARAM command, - * needing 256 bytes. + * STATUS, READID and PARAM. + * ONFI param page is 256 bytes, and there are three redundant copies + * to be read. JEDEC param page is 512 bytes, and there are also three + * redundant copies to be read. + * Hence this buffer should be at least 512 x 3. Let's pick 2048. */ -#define INIT_BUFFER_SIZE 256 +#define INIT_BUFFER_SIZE 2048
/* registers and bit definitions */ #define NDCR (0x00) /* Control register */ @@ -842,14 +845,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break;
case NAND_CMD_PARAM: - info->buf_count = 256; + info->buf_count = INIT_BUFFER_SIZE; info->ndcb0 |= NDCB0_CMD_TYPE(0) | NDCB0_ADDR_CYC(1) | NDCB0_LEN_OVRD | command; info->ndcb1 = (column & 0xFF); - info->ndcb3 = 256; - info->data_size = 256; + info->ndcb3 = INIT_BUFFER_SIZE; + info->data_size = INIT_BUFFER_SIZE; break;
case NAND_CMD_READID:

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
The initial buffer is used for the initial commands used to detect a flash device (STATUS, READID and PARAM).
ONFI param page is 256 bytes, and there are three redundant copies to be read. JEDEC param page is 512 bytes, and there are also three redundant copies to be read. Hence this buffer should be at least 512 x 3. This commits rounds the buffer size to 2048.
This commit is taken from Linux: 'commit c16340973fcb64614' ("nand: pxa3xx: Increase initial buffer size")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 9d02fd8..ead5624 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -28,10 +28,13 @@ DECLARE_GLOBAL_DATA_PTR;
/*
- Define a buffer size for the initial command that detects the flash device:
- STATUS, READID and PARAM. The largest of these is the PARAM command,
- needing 256 bytes.
- STATUS, READID and PARAM.
- ONFI param page is 256 bytes, and there are three redundant copies
- to be read. JEDEC param page is 512 bytes, and there are also three
- redundant copies to be read.
*/
- Hence this buffer should be at least 512 x 3. Let's pick 2048.
-#define INIT_BUFFER_SIZE 256 +#define INIT_BUFFER_SIZE 2048
/* registers and bit definitions */ #define NDCR (0x00) /* Control register */ @@ -842,14 +845,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break;
case NAND_CMD_PARAM:
info->buf_count = 256;
info->ndcb0 |= NDCB0_CMD_TYPE(0) | NDCB0_ADDR_CYC(1) | NDCB0_LEN_OVRD | command; info->ndcb1 = (column & 0xFF);info->buf_count = INIT_BUFFER_SIZE;
info->ndcb3 = 256;
info->data_size = 256;
info->ndcb3 = INIT_BUFFER_SIZE;
info->data_size = INIT_BUFFER_SIZE;
break;
case NAND_CMD_READID:
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
Don't store struct mtd_info in struct pxa3xx_nand_host. Instead use the one that is already part of struct nand_chip. This brings us in line with current U-boot and Linux conventions.
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ead5624..6295886 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -149,7 +149,6 @@ enum pxa3xx_nand_variant {
struct pxa3xx_nand_host { struct nand_chip chip; - struct mtd_info *mtd; void *info_data;
/* page size of attached chip */ @@ -384,16 +383,17 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) struct nand_chip *chip = &host->chip; struct pxa3xx_nand_info *info = host->info_data; const struct pxa3xx_nand_flash *f = NULL; + struct mtd_info *mtd = nand_to_mtd(&host->chip); int mode, id, ntypes, i;
mode = onfi_get_async_timing_mode(chip); if (mode == ONFI_TIMING_MODE_UNKNOWN) { ntypes = ARRAY_SIZE(builtin_flash_types);
- chip->cmdfunc(host->mtd, NAND_CMD_READID, 0x00, -1); + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- id = chip->read_byte(host->mtd); - id |= chip->read_byte(host->mtd) << 0x8; + id = chip->read_byte(mtd); + id |= chip->read_byte(mtd) << 0x8;
for (i = 0; i < ntypes; i++) { f = &builtin_flash_types[i]; @@ -686,7 +686,7 @@ static void set_command_address(struct pxa3xx_nand_info *info, static void prepare_start_command(struct pxa3xx_nand_info *info, int command) { struct pxa3xx_nand_host *host = info->host[info->cs]; - struct mtd_info *mtd = host->mtd; + struct mtd_info *mtd = nand_to_mtd(&host->chip);
/* reset data and oob column point to handle data */ info->buf_start = 0; @@ -737,7 +737,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, struct mtd_info *mtd;
host = info->host[info->cs]; - mtd = host->mtd; + mtd = nand_to_mtd(&host->chip); addr_cycle = 0; exec_cmd = 1;
@@ -1224,7 +1224,7 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_host *host = info->host[info->cs]; - struct mtd_info *mtd = host->mtd; + struct mtd_info *mtd = nand_to_mtd(&host->chip); struct nand_chip *chip = mtd_to_nand(mtd);
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; @@ -1276,7 +1276,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) const struct nand_sdr_timings *timings; int ret;
- mtd = info->host[info->cs]->mtd; + mtd = nand_to_mtd(&info->host[info->cs]->chip); chip = mtd_to_nand(mtd);
/* configure default flash values */ @@ -1497,7 +1497,6 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) mtd = nand_to_mtd(chip); host = (struct pxa3xx_nand_host *)chip; info->host[cs] = host; - host->mtd = mtd; host->cs = cs; host->info_data = info; host->read_id_bytes = 4; @@ -1615,7 +1614,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
probe_success = 0; for (cs = 0; cs < pdata->num_cs; cs++) { - struct mtd_info *mtd = info->host[cs]->mtd; + struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
/* * The mtd name matches the one used in 'mtdparts' kernel

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
Don't store struct mtd_info in struct pxa3xx_nand_host. Instead use the one that is already part of struct nand_chip. This brings us in line with current U-boot and Linux conventions.
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ead5624..6295886 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -149,7 +149,6 @@ enum pxa3xx_nand_variant {
struct pxa3xx_nand_host { struct nand_chip chip;
struct mtd_info *mtd; void *info_data;
/* page size of attached chip */
@@ -384,16 +383,17 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) struct nand_chip *chip = &host->chip; struct pxa3xx_nand_info *info = host->info_data; const struct pxa3xx_nand_flash *f = NULL;
struct mtd_info *mtd = nand_to_mtd(&host->chip); int mode, id, ntypes, i;
mode = onfi_get_async_timing_mode(chip); if (mode == ONFI_TIMING_MODE_UNKNOWN) { ntypes = ARRAY_SIZE(builtin_flash_types);
chip->cmdfunc(host->mtd, NAND_CMD_READID, 0x00, -1);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
id = chip->read_byte(host->mtd);
id |= chip->read_byte(host->mtd) << 0x8;
id = chip->read_byte(mtd);
id |= chip->read_byte(mtd) << 0x8;
for (i = 0; i < ntypes; i++) { f = &builtin_flash_types[i];
@@ -686,7 +686,7 @@ static void set_command_address(struct pxa3xx_nand_info *info, static void prepare_start_command(struct pxa3xx_nand_info *info, int command) { struct pxa3xx_nand_host *host = info->host[info->cs];
- struct mtd_info *mtd = host->mtd;
struct mtd_info *mtd = nand_to_mtd(&host->chip);
/* reset data and oob column point to handle data */ info->buf_start = 0;
@@ -737,7 +737,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, struct mtd_info *mtd;
host = info->host[info->cs];
- mtd = host->mtd;
- mtd = nand_to_mtd(&host->chip); addr_cycle = 0; exec_cmd = 1;
@@ -1224,7 +1224,7 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_host *host = info->host[info->cs];
- struct mtd_info *mtd = host->mtd;
struct mtd_info *mtd = nand_to_mtd(&host->chip); struct nand_chip *chip = mtd_to_nand(mtd);
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
@@ -1276,7 +1276,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) const struct nand_sdr_timings *timings; int ret;
- mtd = info->host[info->cs]->mtd;
mtd = nand_to_mtd(&info->host[info->cs]->chip); chip = mtd_to_nand(mtd);
/* configure default flash values */
@@ -1497,7 +1497,6 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) mtd = nand_to_mtd(chip); host = (struct pxa3xx_nand_host *)chip; info->host[cs] = host;
host->cs = cs; host->info_data = info; host->read_id_bytes = 4;host->mtd = mtd;
@@ -1615,7 +1614,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
probe_success = 0; for (cs = 0; cs < pdata->num_cs; cs++) {
struct mtd_info *mtd = info->host[cs]->mtd;
struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
/*
- The mtd name matches the one used in 'mtdparts' kernel
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
Since the pxa3xx_nand driver was added there has been a discrepancy in pxa3xx_nand_set_sdr_timing() around the setting of tWP_min and tRP_min. This brings us into line with the current Linux code.
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 6295886..8e450fb 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -349,9 +349,9 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000); u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000); - u32 tWP_min = DIV_ROUND_UP(t->tWC_min - tWH_min, 1000); + u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000); u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000); - u32 tRP_min = DIV_ROUND_UP(t->tRC_min - tREH_min, 1000); + u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000); u32 tR = chip->chip_delay * 1000; u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
Since the pxa3xx_nand driver was added there has been a discrepancy in pxa3xx_nand_set_sdr_timing() around the setting of tWP_min and tRP_min. This brings us into line with the current Linux code.
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 6295886..8e450fb 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -349,9 +349,9 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000); u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
- u32 tWP_min = DIV_ROUND_UP(t->tWC_min - tWH_min, 1000);
- u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000); u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
- u32 tRP_min = DIV_ROUND_UP(t->tRC_min - tREH_min, 1000);
- u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000); u32 tR = chip->chip_delay * 1000; u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
When the nand is first probe, and upon the first command start, the status bits should be cleared before the interrupts are unmasked.
This commit is taken from Linux: 'commit 0b14392db2e' ("mtd: nand: pxa3xx_nand: fix early spurious interrupt")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 8e450fb..7b1dcb2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -481,8 +481,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) ndcr |= NDCR_ND_RUN;
/* clear status bits and run */ - nand_writel(info, NDCR, 0); nand_writel(info, NDSR, NDSR_MASK); + nand_writel(info, NDCR, 0); nand_writel(info, NDCR, ndcr); }

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
When the nand is first probe, and upon the first command start, the status bits should be cleared before the interrupts are unmasked.
This commit is taken from Linux: 'commit 0b14392db2e' ("mtd: nand: pxa3xx_nand: fix early spurious interrupt")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 8e450fb..7b1dcb2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -481,8 +481,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) ndcr |= NDCR_ND_RUN;
/* clear status bits and run */
- nand_writel(info, NDCR, 0); nand_writel(info, NDSR, NDSR_MASK);
- nand_writel(info, NDCR, 0); nand_writel(info, NDCR, ndcr); }
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
When 2 commands are submitted in a row, and the second is very quick, the completion of the second command might never come. This happens especially if the second command is quick, such as a status read after an erase
This patch is taken from Linux: 'commit 21fc0ef9652f' ("mtd: nand: pxa3xx-nand: fix random command timeouts")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 7b1dcb2..98bb4c6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -623,8 +623,14 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) is_ready = 1; }
+ /* + * Clear all status bit before issuing the next command, which + * can and will alter the status bits and will deserve a new + * interrupt on its own. This lets the controller exit the IRQ + */ + nand_writel(info, NDSR, status); + if (status & NDSR_WRCMDREQ) { - nand_writel(info, NDSR, NDSR_WRCMDREQ); status &= ~NDSR_WRCMDREQ; info->state = STATE_CMD_HANDLE;
@@ -645,8 +651,6 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) nand_writel(info, NDCB0, info->ndcb3); }
- /* clear NDSR to let the controller exit the IRQ */ - nand_writel(info, NDSR, status); if (is_completed) info->cmd_complete = 1; if (is_ready)

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
When 2 commands are submitted in a row, and the second is very quick, the completion of the second command might never come. This happens especially if the second command is quick, such as a status read after an erase
This patch is taken from Linux: 'commit 21fc0ef9652f' ("mtd: nand: pxa3xx-nand: fix random command timeouts")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 7b1dcb2..98bb4c6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -623,8 +623,14 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) is_ready = 1; }
- /*
* Clear all status bit before issuing the next command, which
* can and will alter the status bits and will deserve a new
* interrupt on its own. This lets the controller exit the IRQ
*/
- nand_writel(info, NDSR, status);
- if (status & NDSR_WRCMDREQ) {
status &= ~NDSR_WRCMDREQ; info->state = STATE_CMD_HANDLE;nand_writel(info, NDSR, NDSR_WRCMDREQ);
@@ -645,8 +651,6 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) nand_writel(info, NDCB0, info->ndcb3); }
- /* clear NDSR to let the controller exit the IRQ */
- nand_writel(info, NDSR, status); if (is_completed) info->cmd_complete = 1; if (is_ready)
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
The read ID count should be made as large as the maximum READ_ID size, so there's no need to have dynamic size. This commit sets the hardware maximum read ID count, which should be more than enough on all cases. Also, we get rid of the read_id_bytes, and use a macro instead.
This commit is taken from Linux: 'commit b226eca2088' ("nand: pxa3xx: Increase READ_ID buffer and make the size static")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 98bb4c6..575fdd2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -112,6 +112,13 @@ DECLARE_GLOBAL_DATA_PTR; #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
+/* + * This should be large enough to read 'ONFI' and 'JEDEC'. + * Let's use 7 bytes, which is the maximum ID count supported + * by the controller (see NDCR_RD_ID_CNT_MASK). + */ +#define READ_ID_BYTES 7 + /* macros for registers read/write */ #define nand_writel(info, off, val) \ writel((val), (info)->mmio_base + (off)) @@ -158,8 +165,6 @@ struct pxa3xx_nand_host { /* calculated from pxa3xx_nand_flash data */ unsigned int col_addr_cycles; unsigned int row_addr_cycles; - size_t read_id_bytes; - };
struct pxa3xx_nand_info { @@ -860,7 +865,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break;
case NAND_CMD_READID: - info->buf_count = host->read_id_bytes; + info->buf_count = READ_ID_BYTES; info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) | command; @@ -1240,23 +1245,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { - /* - * We set 0 by hard coding here, for we don't support keep_config - * when there is more than one chip attached to the controller - */ - struct pxa3xx_nand_host *host = info->host[0]; uint32_t ndcr = nand_readl(info, NDCR);
- if (ndcr & NDCR_PAGE_SZ) { - /* Controller's FIFO size */ - info->chunk_size = 2048; - host->read_id_bytes = 4; - } else { - info->chunk_size = 512; - host->read_id_bytes = 2; - } - /* Set an initial chunk size */ + info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); @@ -1286,7 +1278,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) /* configure default flash values */ info->reg_ndcr = 0x0; /* enable all interrupts */ info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - info->reg_ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); + info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */
/* use the common timing to make a try */ @@ -1503,7 +1495,6 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) info->host[cs] = host; host->cs = cs; host->info_data = info; - host->read_id_bytes = 4; mtd->owner = THIS_MODULE;
nand_set_controller_data(chip, host);

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
The read ID count should be made as large as the maximum READ_ID size, so there's no need to have dynamic size. This commit sets the hardware maximum read ID count, which should be more than enough on all cases. Also, we get rid of the read_id_bytes, and use a macro instead.
This commit is taken from Linux: 'commit b226eca2088' ("nand: pxa3xx: Increase READ_ID buffer and make the size static")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 98bb4c6..575fdd2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -112,6 +112,13 @@ DECLARE_GLOBAL_DATA_PTR; #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
+/*
- This should be large enough to read 'ONFI' and 'JEDEC'.
- Let's use 7 bytes, which is the maximum ID count supported
- by the controller (see NDCR_RD_ID_CNT_MASK).
- */
+#define READ_ID_BYTES 7
- /* macros for registers read/write */ #define nand_writel(info, off, val) \ writel((val), (info)->mmio_base + (off))
@@ -158,8 +165,6 @@ struct pxa3xx_nand_host { /* calculated from pxa3xx_nand_flash data */ unsigned int col_addr_cycles; unsigned int row_addr_cycles;
size_t read_id_bytes;
};
struct pxa3xx_nand_info {
@@ -860,7 +865,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break;
case NAND_CMD_READID:
info->buf_count = host->read_id_bytes;
info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) | command;info->buf_count = READ_ID_BYTES;
@@ -1240,23 +1245,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) {
/*
* We set 0 by hard coding here, for we don't support keep_config
* when there is more than one chip attached to the controller
*/
struct pxa3xx_nand_host *host = info->host[0]; uint32_t ndcr = nand_readl(info, NDCR);
if (ndcr & NDCR_PAGE_SZ) {
/* Controller's FIFO size */
info->chunk_size = 2048;
host->read_id_bytes = 4;
} else {
info->chunk_size = 512;
host->read_id_bytes = 2;
}
/* Set an initial chunk size */
- info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
@@ -1286,7 +1278,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) /* configure default flash values */ info->reg_ndcr = 0x0; /* enable all interrupts */ info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
- info->reg_ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */
/* use the common timing to make a try */
@@ -1503,7 +1495,6 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) info->host[cs] = host; host->cs = cs; host->info_data = info;
host->read_id_bytes = 4;
mtd->owner = THIS_MODULE;
nand_set_controller_data(chip, host);
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
The chunk size represents the size of the data chunks, which is used by the controllers that allow to split transferred data.
However, the initial chunk size is used in a non-split way, during device identification. Therefore, it must be large enough for all the NAND commands issued during device identification. This includes NAND_CMD_PARAM which was recently changed to transfer up to 2048 bytes (for the redundant parameter pages).
Thus, the initial chunk size should be 2048 as well.
On Armada 370/XP platforms (NFCv2) booted without the keep-config devicetree property, this commit fixes a timeout on the NAND_CMD_PARAM command:
[..] pxa3xx-nand f10d0000.nand: This platform can't do DMA on this device pxa3xx-nand f10d0000.nand: Wait time out!!! nand: device found, Manufacturer ID: 0x2c, Chip ID: 0x38 nand: Micron MT29F8G08ABABAWP nand: 1024 MiB, SLC, erase size: 512 KiB, page size: 4096, OOB size: 224
This commit is taken from Linux: 'commit c7f00c29aa8' ("mtd: pxa3xx_nand: Increase the initial chunk size")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 575fdd2..835b419 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1376,7 +1376,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG;
/* Set a default chunk size */ - info->chunk_size = 512; + info->chunk_size = PAGE_CHUNK_SIZE;
ret = pxa3xx_nand_sensing(host); if (ret) {

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
The chunk size represents the size of the data chunks, which is used by the controllers that allow to split transferred data.
However, the initial chunk size is used in a non-split way, during device identification. Therefore, it must be large enough for all the NAND commands issued during device identification. This includes NAND_CMD_PARAM which was recently changed to transfer up to 2048 bytes (for the redundant parameter pages).
Thus, the initial chunk size should be 2048 as well.
On Armada 370/XP platforms (NFCv2) booted without the keep-config devicetree property, this commit fixes a timeout on the NAND_CMD_PARAM command:
[..] pxa3xx-nand f10d0000.nand: This platform can't do DMA on this device pxa3xx-nand f10d0000.nand: Wait time out!!! nand: device found, Manufacturer ID: 0x2c, Chip ID: 0x38 nand: Micron MT29F8G08ABABAWP nand: 1024 MiB, SLC, erase size: 512 KiB, page size: 4096, OOB size: 224
This commit is taken from Linux: 'commit c7f00c29aa8' ("mtd: pxa3xx_nand: Increase the initial chunk size")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 575fdd2..835b419 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1376,7 +1376,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG;
/* Set a default chunk size */
- info->chunk_size = 512;
info->chunk_size = PAGE_CHUNK_SIZE;
ret = pxa3xx_nand_sensing(host); if (ret) {
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
The Data Flash Control Register (NDCR) contains two types of parameters: those that are needed for device identification, and those that can only be set after device identification.
Therefore, the driver can't set them all at once and instead needs to configure the first group before nand_scan_ident() and the second group later.
Let's split pxa3xx_nand_config in two halves, and set the parameters that depend on the device geometry once this is known.
This commit is taken from Linux: 'commit 66e8e47eae65' ("mtd: pxa3xx_nand: Fix initial controller configuration")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 835b419..674496d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -61,7 +61,8 @@ DECLARE_GLOBAL_DATA_PTR; #define NDCR_ND_MODE (0x3 << 21) #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) -#define NDCR_STOP_ON_UNCOR (0x1 << 19) +#define NFCV1_NDCR_ARB_CNTL (0x1 << 19) +#define NFCV2_NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK)
@@ -1230,26 +1231,41 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return NAND_STATUS_READY; }
-static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info) +static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata = info->pdata; + + /* Configure default flash values */ + info->chunk_size = PAGE_CHUNK_SIZE; + info->reg_ndcr = 0x0; /* enable all interrupts */ + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; + info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); + info->reg_ndcr |= NDCR_SPARE_EN; + + return 0; +} + +static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_host *host = info->host[info->cs]; - struct mtd_info *mtd = nand_to_mtd(&host->chip); + struct mtd_info *mtd = nand_to_mtd(&info->host[info->cs]->chip); struct nand_chip *chip = mtd_to_nand(mtd);
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0; info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; - - return 0; }
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { + struct pxa3xx_nand_platform_data *pdata = info->pdata; uint32_t ndcr = nand_readl(info, NDCR);
/* Set an initial chunk size */ info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - info->reg_ndcr = ndcr & ~NDCR_INT_MASK; + info->reg_ndcr = ndcr & + ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL); + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; @@ -1375,8 +1391,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) goto KEEP_CONFIG;
- /* Set a default chunk size */ - info->chunk_size = PAGE_CHUNK_SIZE; + ret = pxa3xx_nand_config_ident(info); + if (ret) + return ret;
ret = pxa3xx_nand_sensing(host); if (ret) { @@ -1403,10 +1420,6 @@ KEEP_CONFIG: } }
- ret = pxa3xx_nand_config_flash(info); - if (ret) - return ret; - #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT /* * We'll use a bad block table stored in-flash and don't @@ -1471,6 +1484,10 @@ KEEP_CONFIG: host->row_addr_cycles = 3; else host->row_addr_cycles = 2; + + if (!pdata->keep_config) + pxa3xx_nand_config_tail(info); + return nand_scan_tail(mtd); }

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
The Data Flash Control Register (NDCR) contains two types of parameters: those that are needed for device identification, and those that can only be set after device identification.
Therefore, the driver can't set them all at once and instead needs to configure the first group before nand_scan_ident() and the second group later.
Let's split pxa3xx_nand_config in two halves, and set the parameters that depend on the device geometry once this is known.
This commit is taken from Linux: 'commit 66e8e47eae65' ("mtd: pxa3xx_nand: Fix initial controller configuration")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 835b419..674496d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -61,7 +61,8 @@ DECLARE_GLOBAL_DATA_PTR; #define NDCR_ND_MODE (0x3 << 21) #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) -#define NDCR_STOP_ON_UNCOR (0x1 << 19) +#define NFCV1_NDCR_ARB_CNTL (0x1 << 19) +#define NFCV2_NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK)
@@ -1230,26 +1231,41 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return NAND_STATUS_READY; }
-static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info) +static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) +{
- struct pxa3xx_nand_platform_data *pdata = info->pdata;
- /* Configure default flash values */
- info->chunk_size = PAGE_CHUNK_SIZE;
- info->reg_ndcr = 0x0; /* enable all interrupts */
- info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
- info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
- info->reg_ndcr |= NDCR_SPARE_EN;
- return 0;
+}
+static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_host *host = info->host[info->cs];
- struct mtd_info *mtd = nand_to_mtd(&host->chip);
struct mtd_info *mtd = nand_to_mtd(&info->host[info->cs]->chip); struct nand_chip *chip = mtd_to_nand(mtd);
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0; info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
return 0; }
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) {
struct pxa3xx_nand_platform_data *pdata = info->pdata; uint32_t ndcr = nand_readl(info, NDCR);
/* Set an initial chunk size */ info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
- info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
- info->reg_ndcr = ndcr &
~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
- info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0;
@@ -1375,8 +1391,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) goto KEEP_CONFIG;
- /* Set a default chunk size */
- info->chunk_size = PAGE_CHUNK_SIZE;
ret = pxa3xx_nand_config_ident(info);
if (ret)
return ret;
ret = pxa3xx_nand_sensing(host); if (ret) {
@@ -1403,10 +1420,6 @@ KEEP_CONFIG: } }
- ret = pxa3xx_nand_config_flash(info);
- if (ret)
return ret;
- #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT /*
- We'll use a bad block table stored in-flash and don't
@@ -1471,6 +1484,10 @@ KEEP_CONFIG: host->row_addr_cycles = 3; else host->row_addr_cycles = 2;
- if (!pdata->keep_config)
pxa3xx_nand_config_tail(info);
- return nand_scan_tail(mtd); }
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
This commit simplifies the initial configuration performed by pxa3xx_nand_scan. No functionality change is intended.
This commit is taken from Linux: 'commit 154f50fbde53' ("mtd: pxa3xx_nand: Simplify pxa3xx_nand_scan")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 674496d..4faf787 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1256,7 +1256,7 @@ static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; }
-static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) +static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_platform_data *pdata = info->pdata; uint32_t ndcr = nand_readl(info, NDCR); @@ -1268,7 +1268,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); - return 0; }
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) @@ -1388,22 +1387,21 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) int ret; uint16_t ecc_strength, ecc_step;
- if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) - goto KEEP_CONFIG; - - ret = pxa3xx_nand_config_ident(info); - if (ret) - return ret; - - ret = pxa3xx_nand_sensing(host); - if (ret) { - dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", - info->cs); - - return ret; + if (pdata->keep_config) { + pxa3xx_nand_detect_config(info); + } else { + ret = pxa3xx_nand_config_ident(info); + if (ret) + return ret; + ret = pxa3xx_nand_sensing(host); + if (ret) { + dev_info(&info->pdev->dev, + "There is no chip on cs %d!\n", + info->cs); + return ret; + } }
-KEEP_CONFIG: /* Device detection must be done with ECC disabled */ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) nand_writel(info, NDECCCTRL, 0x0);

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
This commit simplifies the initial configuration performed by pxa3xx_nand_scan. No functionality change is intended.
This commit is taken from Linux: 'commit 154f50fbde53' ("mtd: pxa3xx_nand: Simplify pxa3xx_nand_scan")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 674496d..4faf787 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1256,7 +1256,7 @@ static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; }
-static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) +static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_platform_data *pdata = info->pdata; uint32_t ndcr = nand_readl(info, NDCR); @@ -1268,7 +1268,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
return 0; }
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
@@ -1388,22 +1387,21 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) int ret; uint16_t ecc_strength, ecc_step;
- if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
goto KEEP_CONFIG;
- ret = pxa3xx_nand_config_ident(info);
- if (ret)
return ret;
- ret = pxa3xx_nand_sensing(host);
- if (ret) {
dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
info->cs);
return ret;
- if (pdata->keep_config) {
pxa3xx_nand_detect_config(info);
- } else {
ret = pxa3xx_nand_config_ident(info);
if (ret)
return ret;
ret = pxa3xx_nand_sensing(host);
if (ret) {
dev_info(&info->pdev->dev,
"There is no chip on cs %d!\n",
info->cs);
return ret;
}}
-KEEP_CONFIG: /* Device detection must be done with ECC disabled */ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) nand_writel(info, NDECCCTRL, 0x0);
Applied to u-boot-marvell/master
Thanks, Stefan

From: Ofer Heifetz oferh@marvell.com
This commit is needed to properly support the 8-bits ECC configuration with 4KB pages.
When pages larger than 2 KB are used on platforms using the PXA3xx NAND controller, the reading/programming operations need to be split in chunks of 2 KBs or less because the controller FIFO is limited to about 2 KB (i.e a bit more than 2 KB to accommodate OOB data). Due to this requirement, the data layout on NAND is a bit strange, with ECC interleaved with data, at the end of each chunk.
When a 4-bits ECC configuration is used with 4 KB pages, the physical data layout on the NAND looks like this:
| 2048 data | 32 spare | 30 ECC | 2048 data | 32 spare | 30 ECC |
So the data chunks have an equal size, 2080 bytes for each chunk, which the driver supports properly.
When a 8-bits ECC configuration is used with 4KB pages, the physical data layout on the NAND looks like this:
| 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 64 spare | 30 ECC |
So, the spare area is stored in its own chunk, which has a different size than the other chunks. Since OOB is not used by UBIFS, the initial implementation of the driver has chosen to not support reading this additional "spare" chunk of data.
Unfortunately, Marvell has chosen to store the BBT signature in the OOB area. Therefore, if the driver doesn't read this spare area, Linux has no way of finding the BBT. It thinks there is no BBT, and rewrites one, which U-Boot does not recognize, causing compatibility problems between the bootloader and the kernel in terms of NAND usage.
To fix this, this commit implements the support for reading a partial last chunk. This support is currently only useful for the case of 8 bits ECC with 4 KB pages, but it will be useful in the future to enable other configurations such as 12 bits and 16 bits ECC with 4 KB pages, or 8 bits ECC with 8 KB pages, etc. All those configurations have a "last" chunk that doesn't have the same size as the other chunks.
In order to implement reading of the last chunk, this commit:
- Adds a number of new fields to the pxa3xx_nand_info to describe how many full chunks and how many chunks we have, the size of full chunks and partial chunks, both in terms of data area and spare area.
- Fills in the step_chunk_size and step_spare_size variables to describe how much data and spare should be read/written for the current read/program step.
- Reworks the state machine to accommodate doing the additional read or program step when a last partial chunk is used.
This commit is taken from Linux: 'commit c2cdace755b' ("mtd: nand: pxa3xx_nand: add support for partial chunks")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 154 ++++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 55 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4faf787..5cc75de 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -201,15 +201,44 @@ struct pxa3xx_nand_info { int use_spare; /* use spare ? */ int need_wait;
- unsigned int data_size; /* data to be read from FIFO */ - unsigned int chunk_size; /* split commands chunk size */ - unsigned int oob_size; + /* Amount of real data per full chunk */ + unsigned int chunk_size; + + /* Amount of spare data per full chunk */ unsigned int spare_size; + + /* Number of full chunks (i.e chunk_size + spare_size) */ + unsigned int nfullchunks; + + /* + * Total number of chunks. If equal to nfullchunks, then there + * are only full chunks. Otherwise, there is one last chunk of + * size (last_chunk_size + last_spare_size) + */ + unsigned int ntotalchunks; + + /* Amount of real data in the last chunk */ + unsigned int last_chunk_size; + + /* Amount of spare data in the last chunk */ + unsigned int last_spare_size; + unsigned int ecc_size; unsigned int ecc_err_cnt; unsigned int max_bitflips; int retcode;
+ /* + * Variables only valid during command + * execution. step_chunk_size and step_spare_size is the + * amount of real data and spare data in the current + * chunk. cur_chunk is the current chunk being + * read/programmed. + */ + unsigned int step_chunk_size; + unsigned int step_spare_size; + unsigned int cur_chunk; + /* cached register value */ uint32_t reg_ndcr; uint32_t ndtr0cs0; @@ -436,25 +465,6 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) return 0; }
-/* - * Set the data and OOB size, depending on the selected - * spare and ECC configuration. - * Only applicable to READ0, READOOB and PAGEPROG commands. - */ -static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info, - struct mtd_info *mtd) -{ - int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - - info->data_size = mtd->writesize; - if (!oob_enable) - return; - - info->oob_size = info->spare_size; - if (!info->use_ecc) - info->oob_size += info->ecc_size; -} - /** * NOTE: it is a must to set ND_RUN first, then write * command buffer, otherwise, it does not work. @@ -535,39 +545,38 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
static void handle_data_pio(struct pxa3xx_nand_info *info) { - unsigned int do_bytes = min(info->data_size, info->chunk_size); - switch (info->state) { case STATE_PIO_WRITING: - writesl(info->mmio_base + NDDB, - info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(do_bytes, 4)); + if (info->step_chunk_size) + writesl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(info->step_chunk_size, 4));
- if (info->oob_size > 0) + if (info->step_spare_size) writesl(info->mmio_base + NDDB, info->oob_buff + info->oob_buff_pos, - DIV_ROUND_UP(info->oob_size, 4)); + DIV_ROUND_UP(info->step_spare_size, 4)); break; case STATE_PIO_READING: - drain_fifo(info, - info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(do_bytes, 4)); + if (info->step_chunk_size) + drain_fifo(info, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(info->step_chunk_size, 4));
- if (info->oob_size > 0) + if (info->step_spare_size) drain_fifo(info, info->oob_buff + info->oob_buff_pos, - DIV_ROUND_UP(info->oob_size, 4)); + DIV_ROUND_UP(info->step_spare_size, 4)); break; default: dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, - info->state); + info->state); BUG(); }
/* Update buffer pointers for multi-page read/write */ - info->data_buff_pos += do_bytes; - info->oob_buff_pos += info->oob_size; - info->data_size -= do_bytes; + info->data_buff_pos += info->step_chunk_size; + info->oob_buff_pos += info->step_spare_size; }
static void pxa3xx_nand_irq_thread(struct pxa3xx_nand_info *info) @@ -701,9 +710,11 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) /* reset data and oob column point to handle data */ info->buf_start = 0; info->buf_count = 0; - info->oob_size = 0; info->data_buff_pos = 0; info->oob_buff_pos = 0; + info->step_chunk_size = 0; + info->step_spare_size = 0; + info->cur_chunk = 0; info->use_ecc = 0; info->use_spare = 1; info->retcode = ERR_NONE; @@ -715,8 +726,6 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) case NAND_CMD_READ0: case NAND_CMD_PAGEPROG: info->use_ecc = 1; - case NAND_CMD_READOOB: - pxa3xx_set_datasize(info, mtd); break; case NAND_CMD_PARAM: info->use_spare = 0; @@ -773,6 +782,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, if (command == NAND_CMD_READOOB) info->buf_start += mtd->writesize;
+ if (info->cur_chunk < info->nfullchunks) { + info->step_chunk_size = info->chunk_size; + info->step_spare_size = info->spare_size; + } else { + info->step_chunk_size = info->last_chunk_size; + info->step_spare_size = info->last_spare_size; + } + /* * Multiple page read needs an 'extended command type' field, * which is either naked-read or last-read according to the @@ -784,8 +801,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type); - info->ndcb3 = info->chunk_size + - info->oob_size; + info->ndcb3 = info->step_chunk_size + + info->step_spare_size; }
set_command_address(info, mtd->writesize, column, page_addr); @@ -805,8 +822,6 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | addr_cycle | command; - /* No data transfer in this case */ - info->data_size = 0; exec_cmd = 1; } break; @@ -818,6 +833,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break; }
+ if (info->cur_chunk < info->nfullchunks) { + info->step_chunk_size = info->chunk_size; + info->step_spare_size = info->spare_size; + } else { + info->step_chunk_size = info->last_chunk_size; + info->step_spare_size = info->last_spare_size; + } + /* Second command setting for large pages */ if (mtd->writesize > PAGE_CHUNK_SIZE) { /* @@ -828,14 +851,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type); - info->ndcb3 = info->chunk_size + - info->oob_size; + info->ndcb3 = info->step_chunk_size + + info->step_spare_size;
/* * This is the command dispatch that completes a chunked * page program operation. */ - if (info->data_size == 0) { + if (info->cur_chunk == info->ntotalchunks) { info->ndcb0 = NDCB0_CMD_TYPE(0x1) | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | command; @@ -862,7 +885,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | command; info->ndcb1 = (column & 0xFF); info->ndcb3 = INIT_BUFFER_SIZE; - info->data_size = INIT_BUFFER_SIZE; + info->step_chunk_size = INIT_BUFFER_SIZE; break;
case NAND_CMD_READID: @@ -872,7 +895,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | command; info->ndcb1 = (column & 0xFF);
- info->data_size = 8; + info->step_chunk_size = 8; break; case NAND_CMD_STATUS: info->buf_count = 1; @@ -880,7 +903,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | NDCB0_ADDR_CYC(1) | command;
- info->data_size = 8; + info->step_chunk_size = 8; break;
case NAND_CMD_ERASE1: @@ -1064,22 +1087,31 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, } }
+ /* Only a few commands need several steps */ + if (command != NAND_CMD_PAGEPROG && + command != NAND_CMD_READ0 && + command != NAND_CMD_READOOB) + break; + + info->cur_chunk++; + /* Check if the sequence is complete */ - if (info->data_size == 0 && command != NAND_CMD_PAGEPROG) + if (info->cur_chunk == info->ntotalchunks && + command != NAND_CMD_PAGEPROG) break;
/* * After a splitted program command sequence has issued * the command dispatch, the command sequence is complete. */ - if (info->data_size == 0 && + if (info->cur_chunk == (info->ntotalchunks + 1) && command == NAND_CMD_PAGEPROG && ext_cmd_type == EXT_CMD_TYPE_DISPATCH) break;
if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { /* Last read: issue a 'last naked read' */ - if (info->data_size == info->chunk_size) + if (info->cur_chunk == info->ntotalchunks - 1) ext_cmd_type = EXT_CMD_TYPE_LAST_RW; else ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; @@ -1089,7 +1121,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, * the command dispatch must be issued to complete. */ } else if (command == NAND_CMD_PAGEPROG && - info->data_size == 0) { + info->cur_chunk == info->ntotalchunks) { ext_cmd_type = EXT_CMD_TYPE_DISPATCH; } } while (1); @@ -1316,6 +1348,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, int strength, int ecc_stepsize, int page_size) { if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) { + info->nfullchunks = 1; + info->ntotalchunks = 1; info->chunk_size = 2048; info->spare_size = 40; info->ecc_size = 24; @@ -1324,6 +1358,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->strength = 1;
} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) { + info->nfullchunks = 1; + info->ntotalchunks = 1; info->chunk_size = 512; info->spare_size = 8; info->ecc_size = 8; @@ -1337,6 +1373,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, */ } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { info->ecc_bch = 1; + info->nfullchunks = 1; + info->ntotalchunks = 1; info->chunk_size = 2048; info->spare_size = 32; info->ecc_size = 32; @@ -1347,6 +1385,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; + info->nfullchunks = 2; + info->ntotalchunks = 2; info->chunk_size = 2048; info->spare_size = 32; info->ecc_size = 32; @@ -1361,8 +1401,12 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, */ } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; + info->nfullchunks = 4; + info->ntotalchunks = 5; info->chunk_size = 1024; info->spare_size = 0; + info->last_chunk_size = 0; + info->last_spare_size = 64; info->ecc_size = 32; ecc->mode = NAND_ECC_HW; ecc->size = info->chunk_size;

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Ofer Heifetz oferh@marvell.com
This commit is needed to properly support the 8-bits ECC configuration with 4KB pages.
When pages larger than 2 KB are used on platforms using the PXA3xx NAND controller, the reading/programming operations need to be split in chunks of 2 KBs or less because the controller FIFO is limited to about 2 KB (i.e a bit more than 2 KB to accommodate OOB data). Due to this requirement, the data layout on NAND is a bit strange, with ECC interleaved with data, at the end of each chunk.
When a 4-bits ECC configuration is used with 4 KB pages, the physical data layout on the NAND looks like this:
| 2048 data | 32 spare | 30 ECC | 2048 data | 32 spare | 30 ECC |
So the data chunks have an equal size, 2080 bytes for each chunk, which the driver supports properly.
When a 8-bits ECC configuration is used with 4KB pages, the physical data layout on the NAND looks like this:
| 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 64 spare | 30 ECC |
So, the spare area is stored in its own chunk, which has a different size than the other chunks. Since OOB is not used by UBIFS, the initial implementation of the driver has chosen to not support reading this additional "spare" chunk of data.
Unfortunately, Marvell has chosen to store the BBT signature in the OOB area. Therefore, if the driver doesn't read this spare area, Linux has no way of finding the BBT. It thinks there is no BBT, and rewrites one, which U-Boot does not recognize, causing compatibility problems between the bootloader and the kernel in terms of NAND usage.
To fix this, this commit implements the support for reading a partial last chunk. This support is currently only useful for the case of 8 bits ECC with 4 KB pages, but it will be useful in the future to enable other configurations such as 12 bits and 16 bits ECC with 4 KB pages, or 8 bits ECC with 8 KB pages, etc. All those configurations have a "last" chunk that doesn't have the same size as the other chunks.
In order to implement reading of the last chunk, this commit:
Adds a number of new fields to the pxa3xx_nand_info to describe how many full chunks and how many chunks we have, the size of full chunks and partial chunks, both in terms of data area and spare area.
Fills in the step_chunk_size and step_spare_size variables to describe how much data and spare should be read/written for the current read/program step.
Reworks the state machine to accommodate doing the additional read or program step when a last partial chunk is used.
This commit is taken from Linux: 'commit c2cdace755b' ("mtd: nand: pxa3xx_nand: add support for partial chunks")
Signed-off-by: Chris Packham judge.packham@gmail.com Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 154 ++++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 55 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4faf787..5cc75de 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -201,15 +201,44 @@ struct pxa3xx_nand_info { int use_spare; /* use spare ? */ int need_wait;
- unsigned int data_size; /* data to be read from FIFO */
- unsigned int chunk_size; /* split commands chunk size */
- unsigned int oob_size;
/* Amount of real data per full chunk */
unsigned int chunk_size;
/* Amount of spare data per full chunk */ unsigned int spare_size;
/* Number of full chunks (i.e chunk_size + spare_size) */
unsigned int nfullchunks;
/*
* Total number of chunks. If equal to nfullchunks, then there
* are only full chunks. Otherwise, there is one last chunk of
* size (last_chunk_size + last_spare_size)
*/
unsigned int ntotalchunks;
/* Amount of real data in the last chunk */
unsigned int last_chunk_size;
/* Amount of spare data in the last chunk */
unsigned int last_spare_size;
unsigned int ecc_size; unsigned int ecc_err_cnt; unsigned int max_bitflips; int retcode;
/*
* Variables only valid during command
* execution. step_chunk_size and step_spare_size is the
* amount of real data and spare data in the current
* chunk. cur_chunk is the current chunk being
* read/programmed.
*/
unsigned int step_chunk_size;
unsigned int step_spare_size;
unsigned int cur_chunk;
/* cached register value */ uint32_t reg_ndcr; uint32_t ndtr0cs0;
@@ -436,25 +465,6 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) return 0; }
-/*
- Set the data and OOB size, depending on the selected
- spare and ECC configuration.
- Only applicable to READ0, READOOB and PAGEPROG commands.
- */
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
struct mtd_info *mtd)
-{
- int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
- info->data_size = mtd->writesize;
- if (!oob_enable)
return;
- info->oob_size = info->spare_size;
- if (!info->use_ecc)
info->oob_size += info->ecc_size;
-}
- /**
- NOTE: it is a must to set ND_RUN first, then write
- command buffer, otherwise, it does not work.
@@ -535,39 +545,38 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
static void handle_data_pio(struct pxa3xx_nand_info *info) {
- unsigned int do_bytes = min(info->data_size, info->chunk_size);
- switch (info->state) { case STATE_PIO_WRITING:
writesl(info->mmio_base + NDDB,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(do_bytes, 4));
if (info->step_chunk_size)
writesl(info->mmio_base + NDDB,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(info->step_chunk_size, 4));
if (info->oob_size > 0)
if (info->step_spare_size) writesl(info->mmio_base + NDDB, info->oob_buff + info->oob_buff_pos,
DIV_ROUND_UP(info->oob_size, 4));
break; case STATE_PIO_READING:DIV_ROUND_UP(info->step_spare_size, 4));
drain_fifo(info,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(do_bytes, 4));
if (info->step_chunk_size)
drain_fifo(info,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(info->step_chunk_size, 4));
if (info->oob_size > 0)
if (info->step_spare_size) drain_fifo(info, info->oob_buff + info->oob_buff_pos,
DIV_ROUND_UP(info->oob_size, 4));
break; default: dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,DIV_ROUND_UP(info->step_spare_size, 4));
info->state);
info->state);
BUG(); }
/* Update buffer pointers for multi-page read/write */
- info->data_buff_pos += do_bytes;
- info->oob_buff_pos += info->oob_size;
- info->data_size -= do_bytes;
info->data_buff_pos += info->step_chunk_size;
info->oob_buff_pos += info->step_spare_size; }
static void pxa3xx_nand_irq_thread(struct pxa3xx_nand_info *info)
@@ -701,9 +710,11 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) /* reset data and oob column point to handle data */ info->buf_start = 0; info->buf_count = 0;
- info->oob_size = 0; info->data_buff_pos = 0; info->oob_buff_pos = 0;
- info->step_chunk_size = 0;
- info->step_spare_size = 0;
- info->cur_chunk = 0; info->use_ecc = 0; info->use_spare = 1; info->retcode = ERR_NONE;
@@ -715,8 +726,6 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) case NAND_CMD_READ0: case NAND_CMD_PAGEPROG: info->use_ecc = 1;
- case NAND_CMD_READOOB:
break; case NAND_CMD_PARAM: info->use_spare = 0;pxa3xx_set_datasize(info, mtd);
@@ -773,6 +782,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, if (command == NAND_CMD_READOOB) info->buf_start += mtd->writesize;
if (info->cur_chunk < info->nfullchunks) {
info->step_chunk_size = info->chunk_size;
info->step_spare_size = info->spare_size;
} else {
info->step_chunk_size = info->last_chunk_size;
info->step_spare_size = info->last_spare_size;
}
- /*
- Multiple page read needs an 'extended command type' field,
- which is either naked-read or last-read according to the
@@ -784,8 +801,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
info->ndcb3 = info->chunk_size +
info->oob_size;
info->ndcb3 = info->step_chunk_size +
info->step_spare_size;
}
set_command_address(info, mtd->writesize, column, page_addr);
@@ -805,8 +822,6 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | addr_cycle | command;
/* No data transfer in this case */
} break;info->data_size = 0; exec_cmd = 1;
@@ -818,6 +833,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break; }
if (info->cur_chunk < info->nfullchunks) {
info->step_chunk_size = info->chunk_size;
info->step_spare_size = info->spare_size;
} else {
info->step_chunk_size = info->last_chunk_size;
info->step_spare_size = info->last_spare_size;
}
- /* Second command setting for large pages */ if (mtd->writesize > PAGE_CHUNK_SIZE) { /*
@@ -828,14 +851,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
info->ndcb3 = info->chunk_size +
info->oob_size;
info->ndcb3 = info->step_chunk_size +
info->step_spare_size; /* * This is the command dispatch that completes a chunked * page program operation. */
if (info->data_size == 0) {
if (info->cur_chunk == info->ntotalchunks) { info->ndcb0 = NDCB0_CMD_TYPE(0x1) | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | command;
@@ -862,7 +885,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | command; info->ndcb1 = (column & 0xFF); info->ndcb3 = INIT_BUFFER_SIZE;
info->data_size = INIT_BUFFER_SIZE;
info->step_chunk_size = INIT_BUFFER_SIZE;
break;
case NAND_CMD_READID:
@@ -872,7 +895,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | command; info->ndcb1 = (column & 0xFF);
info->data_size = 8;
break; case NAND_CMD_STATUS: info->buf_count = 1;info->step_chunk_size = 8;
@@ -880,7 +903,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | NDCB0_ADDR_CYC(1) | command;
info->data_size = 8;
info->step_chunk_size = 8;
break;
case NAND_CMD_ERASE1:
@@ -1064,22 +1087,31 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, } }
/* Only a few commands need several steps */
if (command != NAND_CMD_PAGEPROG &&
command != NAND_CMD_READ0 &&
command != NAND_CMD_READOOB)
break;
info->cur_chunk++;
- /* Check if the sequence is complete */
if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
if (info->cur_chunk == info->ntotalchunks &&
command != NAND_CMD_PAGEPROG) break;
/*
- After a splitted program command sequence has issued
- the command dispatch, the command sequence is complete.
*/
if (info->data_size == 0 &&
if (info->cur_chunk == (info->ntotalchunks + 1) &&
command == NAND_CMD_PAGEPROG && ext_cmd_type == EXT_CMD_TYPE_DISPATCH) break;
if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { /* Last read: issue a 'last naked read' */
if (info->data_size == info->chunk_size)
if (info->cur_chunk == info->ntotalchunks - 1) ext_cmd_type = EXT_CMD_TYPE_LAST_RW; else ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
@@ -1089,7 +1121,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, * the command dispatch must be issued to complete. */ } else if (command == NAND_CMD_PAGEPROG &&
info->data_size == 0) {
} } while (1);info->cur_chunk == info->ntotalchunks) { ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
@@ -1316,6 +1348,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, int strength, int ecc_stepsize, int page_size) { if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
info->nfullchunks = 1;
info->chunk_size = 2048; info->spare_size = 40; info->ecc_size = 24;info->ntotalchunks = 1;
@@ -1324,6 +1358,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->strength = 1;
} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
info->nfullchunks = 1;
info->chunk_size = 512; info->spare_size = 8; info->ecc_size = 8;info->ntotalchunks = 1;
@@ -1337,6 +1373,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, */ } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { info->ecc_bch = 1;
info->nfullchunks = 1;
info->chunk_size = 2048; info->spare_size = 32; info->ecc_size = 32;info->ntotalchunks = 1;
@@ -1347,6 +1385,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1;
info->nfullchunks = 2;
info->chunk_size = 2048; info->spare_size = 32; info->ecc_size = 32;info->ntotalchunks = 2;
@@ -1361,8 +1401,12 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, */ } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1;
info->nfullchunks = 4;
info->chunk_size = 1024; info->spare_size = 0;info->ntotalchunks = 5;
info->last_chunk_size = 0;
info->ecc_size = 32; ecc->mode = NAND_ECC_HW; ecc->size = info->chunk_size;info->last_spare_size = 64;
Applied to u-boot-marvell/master
Thanks, Stefan

From: zachary zhang zhangzg@marvell.com
This patch adds SoC type and revision and each module's type and revision printing for a7k and a8k boards.
Signed-off-by: zachary zhang zhangzg@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- arch/arm/mach-mvebu/armada8k/Makefile | 1 + arch/arm/mach-mvebu/armada8k/cpu.c | 9 +++ arch/arm/mach-mvebu/armada8k/soc.c | 130 +++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/soc.h | 3 + common/board_f.c | 6 +- 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada8k/soc.c
diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile index 82cb25b..19503f7 100644 --- a/arch/arm/mach-mvebu/armada8k/Makefile +++ b/arch/arm/mach-mvebu/armada8k/Makefile @@ -3,4 +3,5 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-y += soc.o obj-y += cache_llc.o diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index f8e8e73..dd028e5 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -12,6 +12,7 @@ #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <asm/armv8/mmu.h> +#include <mach/soc.h>
/* Armada 7k/8k */ #define MVEBU_RFU_BASE (MVEBU_REGISTER(0x6f0000)) @@ -125,3 +126,11 @@ u32 mvebu_get_nand_clock(void) else return 250 * 1000000; } + +#if defined(CONFIG_DISPLAY_BOARDINFO) +int print_cpuinfo(void) +{ + soc_print_device_info(); + return 0; +} +#endif diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c new file mode 100644 index 0000000..511c734 --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + * https://spdx.org/licenses + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/soc.h> + +#define CP_DEV_ID_STATUS_REG (MVEBU_REGISTER(0x2400240)) +#define DEVICE_ID_STATUS_MASK 0xffff +#define SW_REV_STATUS_OFFSET 16 +#define SW_REV_STATUS_MASK 0xf + +struct mochi_module { + u32 module_type; + u32 module_rev; +}; + +struct soc_info { + struct mochi_module soc; + char *soc_name; + struct mochi_module ap; + struct mochi_module cp; + u32 ap_num; + u32 cp_num; +}; + +static struct soc_info soc_info_table[] = { + { {0x7040, 1}, "Armada7040-A1", {0x806, 1}, {0x110, 1}, 1, 1 }, + { {0x7040, 2}, "Armada7040-A2", {0x806, 1}, {0x110, 2}, 1, 1 }, + { {0x8040, 1}, "Armada8040-A1", {0x806, 1}, {0x110, 1}, 1, 2 }, + { {0x8040, 2}, "Armada8040-A2", {0x806, 1}, {0x110, 2}, 1, 2 }, +}; + +static int get_soc_type_rev(u32 *type, u32 *rev) +{ + *type = readl(CP_DEV_ID_STATUS_REG) & DEVICE_ID_STATUS_MASK; + *rev = (readl(CP_DEV_ID_STATUS_REG) >> SW_REV_STATUS_OFFSET) & + SW_REV_STATUS_MASK; + + return 0; +} + +static int get_soc_table_index(u32 *index) +{ + u32 soc_type; + u32 rev, i, ret = 1; + + *index = 0; + get_soc_type_rev(&soc_type, &rev); + + for (i = 0; i < sizeof(soc_info_table) / sizeof(struct soc_info); i++) { + if ((soc_type == + soc_info_table[i].soc.module_type) && + (rev == soc_info_table[i].soc.module_rev)) { + *index = i; + ret = 0; + } + } + + return ret; +} + +static int get_soc_name(char **soc_name) +{ + u32 index; + + get_soc_table_index(&index); + *soc_name = soc_info_table[index].soc_name; + + return 0; +} + +static int get_ap_cp_num(u32 *ap_num, u32 *cp_num) +{ + u32 index; + + get_soc_table_index(&index); + *ap_num = soc_info_table[index].ap_num; + *cp_num = soc_info_table[index].cp_num; + + return 0; +} + +/* Get SoC's Application Processor (AP) module type and revision */ +static int get_ap_type_rev(u32 *type, u32 *rev) +{ + u32 index; + + get_soc_table_index(&index); + *type = soc_info_table[index].ap.module_type; + *rev = soc_info_table[index].ap.module_rev; + + return 0; +} + +/* Get SoC's Communication Processor (CP) module type and revision */ +static int get_cp_type_rev(u32 *type, u32 *rev) +{ + u32 index; + + get_soc_table_index(&index); + *type = soc_info_table[index].cp.module_type; + *rev = soc_info_table[index].cp.module_rev; + + return 0; +} + +/* Print device's SoC name and AP & CP information */ +void soc_print_device_info(void) +{ + u32 ap_num, cp_num, ap_type, ap_rev, cp_type, cp_rev; + char *soc_name = NULL; + + get_ap_cp_num(&ap_num, &cp_num); + + get_soc_name(&soc_name); + get_ap_type_rev(&ap_type, &ap_rev); + get_cp_type_rev(&cp_type, &cp_rev); + + printf("SoC: %s; AP%x-A%d; ", soc_name, ap_type, ap_rev); + /* more than one cp module */ + if (cp_num > 1) + printf("%dx CP%x-A%d\n", cp_num, cp_type, cp_rev); + else + printf("CP%x-A%d\n", cp_type, cp_rev); +} diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 623ab4e..3192772 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -173,4 +173,7 @@ #define BOOT_FROM_SPI 0x3 #endif
+#ifndef __ASSEMBLY__ +void soc_print_device_info(void); +#endif /* __ASSEMBLY__ */ #endif /* _MVEBU_SOC_H */ diff --git a/common/board_f.c b/common/board_f.c index 88d7700..cf9cfdf 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -790,15 +790,15 @@ static const init_fnc_t init_sequence_f[] = { #if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86) checkcpu, #endif -#if defined(CONFIG_DISPLAY_CPUINFO) - print_cpuinfo, /* display cpu info (and speed) */ -#endif #if defined(CONFIG_DTB_RESELECT) embedded_dtb_select, #endif #if defined(CONFIG_DISPLAY_BOARDINFO) show_board_info, #endif +#if defined(CONFIG_DISPLAY_BOARDINFO) + print_cpuinfo, /* display cpu info (and speed) */ +#endif INIT_FUNC_WATCHDOG_INIT #if defined(CONFIG_MISC_INIT_F) misc_init_f,

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: zachary zhang zhangzg@marvell.com
This patch adds SoC type and revision and each module's type and revision printing for a7k and a8k boards.
Signed-off-by: zachary zhang zhangzg@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
arch/arm/mach-mvebu/armada8k/Makefile | 1 + arch/arm/mach-mvebu/armada8k/cpu.c | 9 +++ arch/arm/mach-mvebu/armada8k/soc.c | 130 +++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/soc.h | 3 + common/board_f.c | 6 +- 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada8k/soc.c
diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile index 82cb25b..19503f7 100644 --- a/arch/arm/mach-mvebu/armada8k/Makefile +++ b/arch/arm/mach-mvebu/armada8k/Makefile @@ -3,4 +3,5 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-y += soc.o obj-y += cache_llc.o diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index f8e8e73..dd028e5 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -12,6 +12,7 @@ #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <asm/armv8/mmu.h> +#include <mach/soc.h>
/* Armada 7k/8k */ #define MVEBU_RFU_BASE (MVEBU_REGISTER(0x6f0000)) @@ -125,3 +126,11 @@ u32 mvebu_get_nand_clock(void) else return 250 * 1000000; }
+#if defined(CONFIG_DISPLAY_BOARDINFO) +int print_cpuinfo(void) +{
- soc_print_device_info();
- return 0;
+} +#endif diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c new file mode 100644 index 0000000..511c734 --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -0,0 +1,130 @@ +/*
- Copyright (C) 2018 Marvell International Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/io.h> +#include <asm/arch/soc.h>
+#define CP_DEV_ID_STATUS_REG (MVEBU_REGISTER(0x2400240)) +#define DEVICE_ID_STATUS_MASK 0xffff +#define SW_REV_STATUS_OFFSET 16 +#define SW_REV_STATUS_MASK 0xf
+struct mochi_module {
- u32 module_type;
- u32 module_rev;
+};
+struct soc_info {
- struct mochi_module soc;
- char *soc_name;
- struct mochi_module ap;
- struct mochi_module cp;
- u32 ap_num;
- u32 cp_num;
+};
+static struct soc_info soc_info_table[] = {
- { {0x7040, 1}, "Armada7040-A1", {0x806, 1}, {0x110, 1}, 1, 1 },
- { {0x7040, 2}, "Armada7040-A2", {0x806, 1}, {0x110, 2}, 1, 1 },
- { {0x8040, 1}, "Armada8040-A1", {0x806, 1}, {0x110, 1}, 1, 2 },
- { {0x8040, 2}, "Armada8040-A2", {0x806, 1}, {0x110, 2}, 1, 2 },
+};
+static int get_soc_type_rev(u32 *type, u32 *rev) +{
- *type = readl(CP_DEV_ID_STATUS_REG) & DEVICE_ID_STATUS_MASK;
- *rev = (readl(CP_DEV_ID_STATUS_REG) >> SW_REV_STATUS_OFFSET) &
SW_REV_STATUS_MASK;
- return 0;
+}
+static int get_soc_table_index(u32 *index) +{
- u32 soc_type;
- u32 rev, i, ret = 1;
- *index = 0;
- get_soc_type_rev(&soc_type, &rev);
- for (i = 0; i < sizeof(soc_info_table) / sizeof(struct soc_info); i++) {
if ((soc_type ==
soc_info_table[i].soc.module_type) &&
(rev == soc_info_table[i].soc.module_rev)) {
*index = i;
ret = 0;
}
- }
- return ret;
+}
+static int get_soc_name(char **soc_name) +{
- u32 index;
- get_soc_table_index(&index);
- *soc_name = soc_info_table[index].soc_name;
- return 0;
+}
+static int get_ap_cp_num(u32 *ap_num, u32 *cp_num) +{
- u32 index;
- get_soc_table_index(&index);
- *ap_num = soc_info_table[index].ap_num;
- *cp_num = soc_info_table[index].cp_num;
- return 0;
+}
+/* Get SoC's Application Processor (AP) module type and revision */ +static int get_ap_type_rev(u32 *type, u32 *rev) +{
- u32 index;
- get_soc_table_index(&index);
- *type = soc_info_table[index].ap.module_type;
- *rev = soc_info_table[index].ap.module_rev;
- return 0;
+}
+/* Get SoC's Communication Processor (CP) module type and revision */ +static int get_cp_type_rev(u32 *type, u32 *rev) +{
- u32 index;
- get_soc_table_index(&index);
- *type = soc_info_table[index].cp.module_type;
- *rev = soc_info_table[index].cp.module_rev;
- return 0;
+}
+/* Print device's SoC name and AP & CP information */ +void soc_print_device_info(void) +{
- u32 ap_num, cp_num, ap_type, ap_rev, cp_type, cp_rev;
- char *soc_name = NULL;
- get_ap_cp_num(&ap_num, &cp_num);
- get_soc_name(&soc_name);
- get_ap_type_rev(&ap_type, &ap_rev);
- get_cp_type_rev(&cp_type, &cp_rev);
- printf("SoC: %s; AP%x-A%d; ", soc_name, ap_type, ap_rev);
- /* more than one cp module */
- if (cp_num > 1)
printf("%dx CP%x-A%d\n", cp_num, cp_type, cp_rev);
- else
printf("CP%x-A%d\n", cp_type, cp_rev);
+} diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 623ab4e..3192772 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -173,4 +173,7 @@ #define BOOT_FROM_SPI 0x3 #endif
+#ifndef __ASSEMBLY__ +void soc_print_device_info(void); +#endif /* __ASSEMBLY__ */ #endif /* _MVEBU_SOC_H */ diff --git a/common/board_f.c b/common/board_f.c index 88d7700..cf9cfdf 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -790,15 +790,15 @@ static const init_fnc_t init_sequence_f[] = { #if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86) checkcpu, #endif -#if defined(CONFIG_DISPLAY_CPUINFO)
- print_cpuinfo, /* display cpu info (and speed) */
-#endif #if defined(CONFIG_DTB_RESELECT) embedded_dtb_select, #endif #if defined(CONFIG_DISPLAY_BOARDINFO) show_board_info, #endif +#if defined(CONFIG_DISPLAY_BOARDINFO)
- print_cpuinfo, /* display cpu info (and speed) */
+#endif INIT_FUNC_WATCHDOG_INIT #if defined(CONFIG_MISC_INIT_F) misc_init_f,
This patch does not apply currently. I'm skipping it from this series for now. I'm currently pushing my Marvell branch upstream and would like to get the first batch of patches accepted. After Tom has pulled these patches, please rebase on top of this new master.
Thanks, Stefan

Hi Kosta,
On 29.08.18 10:56, kostap@marvell.com wrote:
From: zachary zhang zhangzg@marvell.com
This patch adds SoC type and revision and each module's type and revision printing for a7k and a8k boards.
Signed-off-by: zachary zhang zhangzg@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
arch/arm/mach-mvebu/armada8k/Makefile | 1 + arch/arm/mach-mvebu/armada8k/cpu.c | 9 +++ arch/arm/mach-mvebu/armada8k/soc.c | 130 +++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/soc.h | 3 + common/board_f.c | 6 +- 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada8k/soc.c
Such CPU / SoC info collection and printing should be done nowadays in a DM CPU driver instead. Please take a look at this driver for example:
drivers/cpu/mpc83xx_cpu.c
Thanks, Stefan
diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile index 82cb25b..19503f7 100644 --- a/arch/arm/mach-mvebu/armada8k/Makefile +++ b/arch/arm/mach-mvebu/armada8k/Makefile @@ -3,4 +3,5 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-y += soc.o obj-y += cache_llc.o diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index f8e8e73..dd028e5 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -12,6 +12,7 @@ #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <asm/armv8/mmu.h> +#include <mach/soc.h>
/* Armada 7k/8k */ #define MVEBU_RFU_BASE (MVEBU_REGISTER(0x6f0000)) @@ -125,3 +126,11 @@ u32 mvebu_get_nand_clock(void) else return 250 * 1000000; }
+#if defined(CONFIG_DISPLAY_BOARDINFO) +int print_cpuinfo(void) +{
- soc_print_device_info();
- return 0;
+} +#endif diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c new file mode 100644 index 0000000..511c734 --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -0,0 +1,130 @@ +/*
- Copyright (C) 2018 Marvell International Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/io.h> +#include <asm/arch/soc.h>
+#define CP_DEV_ID_STATUS_REG (MVEBU_REGISTER(0x2400240)) +#define DEVICE_ID_STATUS_MASK 0xffff +#define SW_REV_STATUS_OFFSET 16 +#define SW_REV_STATUS_MASK 0xf
+struct mochi_module {
- u32 module_type;
- u32 module_rev;
+};
+struct soc_info {
- struct mochi_module soc;
- char *soc_name;
- struct mochi_module ap;
- struct mochi_module cp;
- u32 ap_num;
- u32 cp_num;
+};
+static struct soc_info soc_info_table[] = {
- { {0x7040, 1}, "Armada7040-A1", {0x806, 1}, {0x110, 1}, 1, 1 },
- { {0x7040, 2}, "Armada7040-A2", {0x806, 1}, {0x110, 2}, 1, 1 },
- { {0x8040, 1}, "Armada8040-A1", {0x806, 1}, {0x110, 1}, 1, 2 },
- { {0x8040, 2}, "Armada8040-A2", {0x806, 1}, {0x110, 2}, 1, 2 },
+};
+static int get_soc_type_rev(u32 *type, u32 *rev) +{
- *type = readl(CP_DEV_ID_STATUS_REG) & DEVICE_ID_STATUS_MASK;
- *rev = (readl(CP_DEV_ID_STATUS_REG) >> SW_REV_STATUS_OFFSET) &
SW_REV_STATUS_MASK;
- return 0;
+}
+static int get_soc_table_index(u32 *index) +{
- u32 soc_type;
- u32 rev, i, ret = 1;
- *index = 0;
- get_soc_type_rev(&soc_type, &rev);
- for (i = 0; i < sizeof(soc_info_table) / sizeof(struct soc_info); i++) {
if ((soc_type ==
soc_info_table[i].soc.module_type) &&
(rev == soc_info_table[i].soc.module_rev)) {
*index = i;
ret = 0;
}
- }
- return ret;
+}
+static int get_soc_name(char **soc_name) +{
- u32 index;
- get_soc_table_index(&index);
- *soc_name = soc_info_table[index].soc_name;
- return 0;
+}
+static int get_ap_cp_num(u32 *ap_num, u32 *cp_num) +{
- u32 index;
- get_soc_table_index(&index);
- *ap_num = soc_info_table[index].ap_num;
- *cp_num = soc_info_table[index].cp_num;
- return 0;
+}
+/* Get SoC's Application Processor (AP) module type and revision */ +static int get_ap_type_rev(u32 *type, u32 *rev) +{
- u32 index;
- get_soc_table_index(&index);
- *type = soc_info_table[index].ap.module_type;
- *rev = soc_info_table[index].ap.module_rev;
- return 0;
+}
+/* Get SoC's Communication Processor (CP) module type and revision */ +static int get_cp_type_rev(u32 *type, u32 *rev) +{
- u32 index;
- get_soc_table_index(&index);
- *type = soc_info_table[index].cp.module_type;
- *rev = soc_info_table[index].cp.module_rev;
- return 0;
+}
+/* Print device's SoC name and AP & CP information */ +void soc_print_device_info(void) +{
- u32 ap_num, cp_num, ap_type, ap_rev, cp_type, cp_rev;
- char *soc_name = NULL;
- get_ap_cp_num(&ap_num, &cp_num);
- get_soc_name(&soc_name);
- get_ap_type_rev(&ap_type, &ap_rev);
- get_cp_type_rev(&cp_type, &cp_rev);
- printf("SoC: %s; AP%x-A%d; ", soc_name, ap_type, ap_rev);
- /* more than one cp module */
- if (cp_num > 1)
printf("%dx CP%x-A%d\n", cp_num, cp_type, cp_rev);
- else
printf("CP%x-A%d\n", cp_type, cp_rev);
+} diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 623ab4e..3192772 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -173,4 +173,7 @@ #define BOOT_FROM_SPI 0x3 #endif
+#ifndef __ASSEMBLY__ +void soc_print_device_info(void); +#endif /* __ASSEMBLY__ */ #endif /* _MVEBU_SOC_H */ diff --git a/common/board_f.c b/common/board_f.c index 88d7700..cf9cfdf 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -790,15 +790,15 @@ static const init_fnc_t init_sequence_f[] = { #if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86) checkcpu, #endif -#if defined(CONFIG_DISPLAY_CPUINFO)
- print_cpuinfo, /* display cpu info (and speed) */
-#endif #if defined(CONFIG_DTB_RESELECT) embedded_dtb_select, #endif #if defined(CONFIG_DISPLAY_BOARDINFO) show_board_info, #endif +#if defined(CONFIG_DISPLAY_BOARDINFO)
- print_cpuinfo, /* display cpu info (and speed) */
+#endif INIT_FUNC_WATCHDOG_INIT #if defined(CONFIG_MISC_INIT_F) misc_init_f,
Viele Grüße, Stefan

From: Igal Liberman igall@marvell.com
Add SoC-dependent function to the NAND driver for selecting NAND interface in DEVBUS MUX register. This selection is done in the BootROM if the boot device is NAND, but may be missing othervise. The NAND is selected only if it is enabled in the DT file. This patch is fixing NAND access problems for configurations that use non-NAND devices for boot (like SPI).
Signed-off-by: Igal Liberman igall@marvell.com Signed-off-by: Konstantin Porotchkin kostap@marvell.com Signed-off-by: David Sniatkiwicz davidsn@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- arch/arm/dts/armada-cp110-master.dtsi | 7 +++- arch/arm/mach-mvebu/armada8k/cpu.c | 18 --------- arch/arm/mach-mvebu/armada8k/soc.c | 30 ++++++++++++++ arch/arm/mach-mvebu/cpu.c | 12 +++++- arch/arm/mach-mvebu/include/mach/cpu.h | 3 +- drivers/mtd/nand/pxa3xx_nand.c | 74 +++++++++++++++++++++++++++++----- 6 files changed, 114 insertions(+), 30 deletions(-)
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index 551d00d..02cee94 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -276,7 +276,12 @@
cpm_nand: nand@720000 { compatible = "marvell,mvebu-pxa3xx-nand"; - reg = <0x720000 0x100>; + reg = <0x720000 0x100>, + <0x440700 0x20>, + <0x440208 0x20>; + reg-names = "ctrl_base", + "flash_clock", + "dev_mux"; #address-cells = <1>;
clocks = <&cpm_syscon0 1 2>; diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index dd028e5..77e9400 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -109,24 +109,6 @@ void reset_cpu(ulong ignored) writel(reg, RFU_GLOBAL_SW_RST); }
-/* - * TODO - implement this functionality using platform - * clock driver once it gets available - * Return NAND clock in Hz - */ -u32 mvebu_get_nand_clock(void) -{ - unsigned long NAND_FLASH_CLK_CTRL = 0xF2440700UL; - unsigned long NF_CLOCK_SEL_MASK = 0x1; - u32 reg; - - reg = readl(NAND_FLASH_CLK_CTRL); - if (reg & NF_CLOCK_SEL_MASK) - return 400 * 1000000; - else - return 250 * 1000000; -} - #if defined(CONFIG_DISPLAY_BOARDINFO) int print_cpuinfo(void) { diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c index 511c734..faf1405 100644 --- a/arch/arm/mach-mvebu/armada8k/soc.c +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -14,6 +14,10 @@ #define SW_REV_STATUS_OFFSET 16 #define SW_REV_STATUS_MASK 0xf
+#define NF_CLOCK_SEL_MASK 0x1 +#define SOC_MUX_NAND_EN_MASK 0x1 +#define CLOCK_1Mhz 1000000 + struct mochi_module { u32 module_type; u32 module_rev; @@ -128,3 +132,29 @@ void soc_print_device_info(void) else printf("CP%x-A%d\n", cp_type, cp_rev); } +#ifdef CONFIG_NAND_PXA3XX +/* Return NAND clock in Hz */ +u32 mvebu_get_nand_clock(void __iomem *nand_flash_clk_ctrl_reg) +{ + u32 reg; + + if (!nand_flash_clk_ctrl_reg) + return 0; + + reg = readl(nand_flash_clk_ctrl_reg); + if (reg & NF_CLOCK_SEL_MASK) + return 400 * CLOCK_1Mhz; + else + return 250 * CLOCK_1Mhz; +} + +/* Select NAND in the device bus multiplexer */ +void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{ + if (!soc_dev_multiplex_reg) + return; + + setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK); +} +#endif + diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 0d2d398..b1d1b1d 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -15,6 +15,8 @@ #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
+#define SOC_MUX_NAND_EN_MASK 0x1 + static struct mbus_win windows[] = { /* SPI */ { MBUS_SPI_BASE, MBUS_SPI_SIZE, @@ -465,7 +467,7 @@ int arch_cpu_init(void) } #endif /* CONFIG_ARCH_CPU_INIT */
-u32 mvebu_get_nand_clock(void) +u32 mvebu_get_nand_clock(void __iomem *unused) { u32 reg;
@@ -479,6 +481,14 @@ u32 mvebu_get_nand_clock(void) NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS); }
+void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{ + if (!soc_dev_multiplex_reg) + return; + + setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK); +} + /* * SOC specific misc init */ diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index d104210..e892715 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -135,7 +135,8 @@ unsigned int mvebu_sdram_bs(enum memory_bank bank); void mvebu_sdram_size_adjust(enum memory_bank bank); int mvebu_mbus_probe(struct mbus_win windows[], int count); int mvebu_soc_family(void); -u32 mvebu_get_nand_clock(void); +u32 mvebu_get_nand_clock(void __iomem *maybe_unused); +void mvebu_nand_select(void __iomem *maybe_unused);
void return_to_bootrom(void);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5cc75de..b64dd0d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -249,6 +249,10 @@ struct pxa3xx_nand_info { uint32_t ndcb1; uint32_t ndcb2; uint32_t ndcb3; + + /* SOC related registers for nand */ + void __iomem *nand_flash_clk_ctrl_reg; + void __iomem *soc_dev_multiplex_reg; };
static struct pxa3xx_nand_timing timing[] = { @@ -349,13 +353,20 @@ static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) return PXA3XX_NAND_VARIANT_ARMADA370; }
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, - const struct pxa3xx_nand_timing *t) +static int pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, + const struct pxa3xx_nand_timing *t) { struct pxa3xx_nand_info *info = host->info_data; - unsigned long nand_clk = mvebu_get_nand_clock(); + unsigned long nand_clk; uint32_t ndtr0, ndtr1;
+ nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg); + if (!nand_clk) { + dev_err(&host->info->pdev->dev, + "Missinig flash clock register\n"); + return -EINVAL; + } + ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) | @@ -371,14 +382,16 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); + + return 0; }
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, - const struct nand_sdr_timings *t) +static int pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, + const struct nand_sdr_timings *t) { struct pxa3xx_nand_info *info = host->info_data; struct nand_chip *chip = &host->chip; - unsigned long nand_clk = mvebu_get_nand_clock(); + unsigned long nand_clk; uint32_t ndtr0, ndtr1;
u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); @@ -391,6 +404,13 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
+ nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg); + if (!nand_clk) { + dev_err(&host->info->pdev->dev, + "Missinig flash clock register\n"); + return -EINVAL; + } + /* fallback to a default value if tR = 0 */ if (!tR) tR = 20000; @@ -410,6 +430,8 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); + + return 0; }
static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) @@ -419,7 +441,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) struct pxa3xx_nand_info *info = host->info_data; const struct pxa3xx_nand_flash *f = NULL; struct mtd_info *mtd = nand_to_mtd(&host->chip); - int mode, id, ntypes, i; + int mode, id, ntypes, i, ret;
mode = onfi_get_async_timing_mode(chip); if (mode == ONFI_TIMING_MODE_UNKNOWN) { @@ -442,7 +464,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) return -EINVAL; }
- pxa3xx_nand_set_timing(host, f->timing); + ret = pxa3xx_nand_set_timing(host, f->timing); + if (ret) + return ret;
if (f->flash_width == 16) { info->reg_ndcr |= NDCR_DWIDTH_M; @@ -459,7 +483,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) if (IS_ERR(timings)) return PTR_ERR(timings);
- pxa3xx_nand_set_sdr_timing(host, timings); + ret = pxa3xx_nand_set_sdr_timing(host, timings); + if (ret) + return ret; }
return 0; @@ -1593,6 +1619,8 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) struct pxa3xx_nand_platform_data *pdata; const void *blob = gd->fdt_blob; int node = -1; + int index; + fdt_addr_t addr;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1614,6 +1642,26 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) (void __iomem *)fdtdec_get_addr_size_auto_noparent( blob, node, "reg", 0, NULL, true);
+ index = fdt_stringlist_search(blob, node, "reg-names", + "flash_clock"); + if (index > 0) { + addr = fdtdec_get_addr_size_auto_noparent( + blob, node, "reg", index, NULL, true); + if (addr != FDT_ADDR_T_NONE) + info->nand_flash_clk_ctrl_reg = + (void __iomem *)addr; + } + + index = fdt_stringlist_search(blob, node, "reg-names", + "dev_mux"); + if (index > 0) { + addr = fdtdec_get_addr_size_auto_noparent( + blob, node, "reg", index, NULL, true); + if (addr != FDT_ADDR_T_NONE) + info->soc_dev_multiplex_reg = + (void __iomem *)addr; + } + pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); if (pdata->num_cs != 1) { pr_err("pxa3xx driver supports single CS only\n"); @@ -1660,6 +1708,14 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
pdata = info->pdata;
+ /* If the NAND flash is enabled in DT, but the boot image is not + * running from NAND, it may be needed to enable NAND on SOC + * DEVBUS MUX level. + * When the boot device is NAND, such configuration is done + * in the BootROM. + */ + mvebu_nand_select(info->soc_dev_multiplex_reg); + ret = alloc_nand_resource(info); if (ret) { dev_err(&pdev->dev, "alloc nand resource failed\n");

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Igal Liberman igall@marvell.com
Add SoC-dependent function to the NAND driver for selecting NAND interface in DEVBUS MUX register. This selection is done in the BootROM if the boot device is NAND, but may be missing othervise. The NAND is selected only if it is enabled in the DT file. This patch is fixing NAND access problems for configurations that use non-NAND devices for boot (like SPI).
Signed-off-by: Igal Liberman igall@marvell.com Signed-off-by: Konstantin Porotchkin kostap@marvell.com Signed-off-by: David Sniatkiwicz davidsn@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
arch/arm/dts/armada-cp110-master.dtsi | 7 +++- arch/arm/mach-mvebu/armada8k/cpu.c | 18 --------- arch/arm/mach-mvebu/armada8k/soc.c | 30 ++++++++++++++ arch/arm/mach-mvebu/cpu.c | 12 +++++- arch/arm/mach-mvebu/include/mach/cpu.h | 3 +- drivers/mtd/nand/pxa3xx_nand.c | 74 +++++++++++++++++++++++++++++----- 6 files changed, 114 insertions(+), 30 deletions(-)
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index 551d00d..02cee94 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -276,7 +276,12 @@
cpm_nand: nand@720000 { compatible = "marvell,mvebu-pxa3xx-nand";
reg = <0x720000 0x100>;
reg = <0x720000 0x100>,
<0x440700 0x20>,
<0x440208 0x20>;
reg-names = "ctrl_base",
"flash_clock",
"dev_mux"; #address-cells = <1>; clocks = <&cpm_syscon0 1 2>;
diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index dd028e5..77e9400 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -109,24 +109,6 @@ void reset_cpu(ulong ignored) writel(reg, RFU_GLOBAL_SW_RST); }
-/*
- TODO - implement this functionality using platform
clock driver once it gets available
- Return NAND clock in Hz
- */
-u32 mvebu_get_nand_clock(void) -{
- unsigned long NAND_FLASH_CLK_CTRL = 0xF2440700UL;
- unsigned long NF_CLOCK_SEL_MASK = 0x1;
- u32 reg;
- reg = readl(NAND_FLASH_CLK_CTRL);
- if (reg & NF_CLOCK_SEL_MASK)
return 400 * 1000000;
- else
return 250 * 1000000;
-}
- #if defined(CONFIG_DISPLAY_BOARDINFO) int print_cpuinfo(void) {
diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c index 511c734..faf1405 100644 --- a/arch/arm/mach-mvebu/armada8k/soc.c +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -14,6 +14,10 @@ #define SW_REV_STATUS_OFFSET 16 #define SW_REV_STATUS_MASK 0xf
+#define NF_CLOCK_SEL_MASK 0x1 +#define SOC_MUX_NAND_EN_MASK 0x1 +#define CLOCK_1Mhz 1000000
- struct mochi_module { u32 module_type; u32 module_rev;
@@ -128,3 +132,29 @@ void soc_print_device_info(void) else printf("CP%x-A%d\n", cp_type, cp_rev); } +#ifdef CONFIG_NAND_PXA3XX +/* Return NAND clock in Hz */ +u32 mvebu_get_nand_clock(void __iomem *nand_flash_clk_ctrl_reg) +{
- u32 reg;
- if (!nand_flash_clk_ctrl_reg)
return 0;
- reg = readl(nand_flash_clk_ctrl_reg);
- if (reg & NF_CLOCK_SEL_MASK)
return 400 * CLOCK_1Mhz;
- else
return 250 * CLOCK_1Mhz;
+}
+/* Select NAND in the device bus multiplexer */ +void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{
- if (!soc_dev_multiplex_reg)
return;
- setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+} +#endif
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 0d2d398..b1d1b1d 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -15,6 +15,8 @@ #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
+#define SOC_MUX_NAND_EN_MASK 0x1
- static struct mbus_win windows[] = { /* SPI */ { MBUS_SPI_BASE, MBUS_SPI_SIZE,
@@ -465,7 +467,7 @@ int arch_cpu_init(void) } #endif /* CONFIG_ARCH_CPU_INIT */
-u32 mvebu_get_nand_clock(void) +u32 mvebu_get_nand_clock(void __iomem *unused) { u32 reg;
@@ -479,6 +481,14 @@ u32 mvebu_get_nand_clock(void) NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS); }
+void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{
- if (!soc_dev_multiplex_reg)
return;
- setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+}
- /*
*/
- SOC specific misc init
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index d104210..e892715 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -135,7 +135,8 @@ unsigned int mvebu_sdram_bs(enum memory_bank bank); void mvebu_sdram_size_adjust(enum memory_bank bank); int mvebu_mbus_probe(struct mbus_win windows[], int count); int mvebu_soc_family(void); -u32 mvebu_get_nand_clock(void); +u32 mvebu_get_nand_clock(void __iomem *maybe_unused); +void mvebu_nand_select(void __iomem *maybe_unused);
void return_to_bootrom(void);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5cc75de..b64dd0d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -249,6 +249,10 @@ struct pxa3xx_nand_info { uint32_t ndcb1; uint32_t ndcb2; uint32_t ndcb3;
/* SOC related registers for nand */
void __iomem *nand_flash_clk_ctrl_reg;
void __iomem *soc_dev_multiplex_reg; };
static struct pxa3xx_nand_timing timing[] = {
@@ -349,13 +353,20 @@ static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) return PXA3XX_NAND_VARIANT_ARMADA370; }
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
const struct pxa3xx_nand_timing *t)
+static int pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
{ struct pxa3xx_nand_info *info = host->info_data;const struct pxa3xx_nand_timing *t)
- unsigned long nand_clk = mvebu_get_nand_clock();
unsigned long nand_clk; uint32_t ndtr0, ndtr1;
nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
if (!nand_clk) {
dev_err(&host->info->pdev->dev,
"Missinig flash clock register\n");
return -EINVAL;
}
ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
@@ -371,14 +382,16 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1);
- return 0; }
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
const struct nand_sdr_timings *t)
+static int pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
{ struct pxa3xx_nand_info *info = host->info_data; struct nand_chip *chip = &host->chip;const struct nand_sdr_timings *t)
- unsigned long nand_clk = mvebu_get_nand_clock();
unsigned long nand_clk; uint32_t ndtr0, ndtr1;
u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
@@ -391,6 +404,13 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
- nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
- if (!nand_clk) {
dev_err(&host->info->pdev->dev,
"Missinig flash clock register\n");
return -EINVAL;
- }
- /* fallback to a default value if tR = 0 */ if (!tR) tR = 20000;
@@ -410,6 +430,8 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1);
return 0; }
static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
@@ -419,7 +441,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) struct pxa3xx_nand_info *info = host->info_data; const struct pxa3xx_nand_flash *f = NULL; struct mtd_info *mtd = nand_to_mtd(&host->chip);
- int mode, id, ntypes, i;
int mode, id, ntypes, i, ret;
mode = onfi_get_async_timing_mode(chip); if (mode == ONFI_TIMING_MODE_UNKNOWN) {
@@ -442,7 +464,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) return -EINVAL; }
pxa3xx_nand_set_timing(host, f->timing);
ret = pxa3xx_nand_set_timing(host, f->timing);
if (ret)
return ret;
if (f->flash_width == 16) { info->reg_ndcr |= NDCR_DWIDTH_M;
@@ -459,7 +483,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) if (IS_ERR(timings)) return PTR_ERR(timings);
pxa3xx_nand_set_sdr_timing(host, timings);
ret = pxa3xx_nand_set_sdr_timing(host, timings);
if (ret)
return ret;
}
return 0;
@@ -1593,6 +1619,8 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) struct pxa3xx_nand_platform_data *pdata; const void *blob = gd->fdt_blob; int node = -1;
int index;
fdt_addr_t addr;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata)
@@ -1614,6 +1642,26 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) (void __iomem *)fdtdec_get_addr_size_auto_noparent( blob, node, "reg", 0, NULL, true);
index = fdt_stringlist_search(blob, node, "reg-names",
"flash_clock");
if (index > 0) {
addr = fdtdec_get_addr_size_auto_noparent(
blob, node, "reg", index, NULL, true);
if (addr != FDT_ADDR_T_NONE)
info->nand_flash_clk_ctrl_reg =
(void __iomem *)addr;
}
index = fdt_stringlist_search(blob, node, "reg-names",
"dev_mux");
if (index > 0) {
addr = fdtdec_get_addr_size_auto_noparent(
blob, node, "reg", index, NULL, true);
if (addr != FDT_ADDR_T_NONE)
info->soc_dev_multiplex_reg =
(void __iomem *)addr;
}
- pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); if (pdata->num_cs != 1) { pr_err("pxa3xx driver supports single CS only\n");
@@ -1660,6 +1708,14 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
pdata = info->pdata;
- /* If the NAND flash is enabled in DT, but the boot image is not
* running from NAND, it may be needed to enable NAND on SOC
* DEVBUS MUX level.
* When the boot device is NAND, such configuration is done
* in the BootROM.
*/
- mvebu_nand_select(info->soc_dev_multiplex_reg);
- ret = alloc_nand_resource(info); if (ret) { dev_err(&pdev->dev, "alloc nand resource failed\n");
This patch does not apply currently. I'm skipping it from this series for now. I'm currently pushing my Marvell branch upstream and would like to get the first batch of patches accepted. After Tom has pulled these patches, please rebase on top of this new master.
Thanks, Stefan

Hi Kosta,
On 19.09.18 14:34, Stefan Roese wrote:
On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Igal Liberman igall@marvell.com
Add SoC-dependent function to the NAND driver for selecting NAND interface in DEVBUS MUX register. This selection is done in the BootROM if the boot device is NAND, but may be missing othervise. The NAND is selected only if it is enabled in the DT file. This patch is fixing NAND access problems for configurations that use non-NAND devices for boot (like SPI).
Signed-off-by: Igal Liberman igall@marvell.com Signed-off-by: Konstantin Porotchkin kostap@marvell.com Signed-off-by: David Sniatkiwicz davidsn@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
arch/arm/dts/armada-cp110-master.dtsi | 7 +++- arch/arm/mach-mvebu/armada8k/cpu.c | 18 --------- arch/arm/mach-mvebu/armada8k/soc.c | 30 ++++++++++++++ arch/arm/mach-mvebu/cpu.c | 12 +++++- arch/arm/mach-mvebu/include/mach/cpu.h | 3 +- drivers/mtd/nand/pxa3xx_nand.c | 74 +++++++++++++++++++++++++++++----- 6 files changed, 114 insertions(+), 30 deletions(-)
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index 551d00d..02cee94 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -276,7 +276,12 @@
cpm_nand: nand@720000 { compatible = "marvell,mvebu-pxa3xx-nand";
reg = <0x720000 0x100>;
reg = <0x720000 0x100>,
<0x440700 0x20>,
<0x440208 0x20>;
reg-names = "ctrl_base",
"flash_clock",
"dev_mux"; #address-cells = <1>; clocks = <&cpm_syscon0 1 2>;
diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index dd028e5..77e9400 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -109,24 +109,6 @@ void reset_cpu(ulong ignored) writel(reg, RFU_GLOBAL_SW_RST); }
-/*
- TODO - implement this functionality using platform
clock driver once it gets available
- Return NAND clock in Hz
- */
-u32 mvebu_get_nand_clock(void) -{
- unsigned long NAND_FLASH_CLK_CTRL = 0xF2440700UL;
- unsigned long NF_CLOCK_SEL_MASK = 0x1;
- u32 reg;
- reg = readl(NAND_FLASH_CLK_CTRL);
- if (reg & NF_CLOCK_SEL_MASK)
return 400 * 1000000;
- else
return 250 * 1000000;
-}
- #if defined(CONFIG_DISPLAY_BOARDINFO) int print_cpuinfo(void) {
diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c index 511c734..faf1405 100644 --- a/arch/arm/mach-mvebu/armada8k/soc.c +++ b/arch/arm/mach-mvebu/armada8k/soc.c @@ -14,6 +14,10 @@ #define SW_REV_STATUS_OFFSET 16 #define SW_REV_STATUS_MASK 0xf
+#define NF_CLOCK_SEL_MASK 0x1 +#define SOC_MUX_NAND_EN_MASK 0x1 +#define CLOCK_1Mhz 1000000
- struct mochi_module { u32 module_type; u32 module_rev;
@@ -128,3 +132,29 @@ void soc_print_device_info(void) else printf("CP%x-A%d\n", cp_type, cp_rev); } +#ifdef CONFIG_NAND_PXA3XX +/* Return NAND clock in Hz */ +u32 mvebu_get_nand_clock(void __iomem *nand_flash_clk_ctrl_reg) +{
- u32 reg;
- if (!nand_flash_clk_ctrl_reg)
return 0;
- reg = readl(nand_flash_clk_ctrl_reg);
- if (reg & NF_CLOCK_SEL_MASK)
return 400 * CLOCK_1Mhz;
- else
return 250 * CLOCK_1Mhz;
+}
+/* Select NAND in the device bus multiplexer */ +void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{
- if (!soc_dev_multiplex_reg)
return;
- setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+} +#endif
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 0d2d398..b1d1b1d 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -15,6 +15,8 @@ #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
+#define SOC_MUX_NAND_EN_MASK 0x1
- static struct mbus_win windows[] = { /* SPI */ { MBUS_SPI_BASE, MBUS_SPI_SIZE,
@@ -465,7 +467,7 @@ int arch_cpu_init(void) } #endif /* CONFIG_ARCH_CPU_INIT */
-u32 mvebu_get_nand_clock(void) +u32 mvebu_get_nand_clock(void __iomem *unused) { u32 reg;
@@ -479,6 +481,14 @@ u32 mvebu_get_nand_clock(void) NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS); }
+void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg) +{
- if (!soc_dev_multiplex_reg)
return;
- setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+}
- /*
*/
- SOC specific misc init
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index d104210..e892715 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -135,7 +135,8 @@ unsigned int mvebu_sdram_bs(enum memory_bank bank); void mvebu_sdram_size_adjust(enum memory_bank bank); int mvebu_mbus_probe(struct mbus_win windows[], int count); int mvebu_soc_family(void); -u32 mvebu_get_nand_clock(void); +u32 mvebu_get_nand_clock(void __iomem *maybe_unused); +void mvebu_nand_select(void __iomem *maybe_unused);
void return_to_bootrom(void);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5cc75de..b64dd0d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -249,6 +249,10 @@ struct pxa3xx_nand_info { uint32_t ndcb1; uint32_t ndcb2; uint32_t ndcb3;
/* SOC related registers for nand */
void __iomem *nand_flash_clk_ctrl_reg;
void __iomem *soc_dev_multiplex_reg; };
static struct pxa3xx_nand_timing timing[] = {
@@ -349,13 +353,20 @@ static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) return PXA3XX_NAND_VARIANT_ARMADA370; }
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
const struct pxa3xx_nand_timing *t)
+static int pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
{ struct pxa3xx_nand_info *info = host->info_data;const struct pxa3xx_nand_timing *t)
- unsigned long nand_clk = mvebu_get_nand_clock();
unsigned long nand_clk; uint32_t ndtr0, ndtr1;
nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
if (!nand_clk) {
dev_err(&host->info->pdev->dev,
"Missinig flash clock register\n");
return -EINVAL;
}
ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
@@ -371,14 +382,16 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1);
- return 0; }
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
const struct nand_sdr_timings *t)
+static int pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
{ struct pxa3xx_nand_info *info = host->info_data; struct nand_chip *chip = &host->chip;const struct nand_sdr_timings *t)
- unsigned long nand_clk = mvebu_get_nand_clock();
unsigned long nand_clk; uint32_t ndtr0, ndtr1;
u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
@@ -391,6 +404,13 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
- nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
- if (!nand_clk) {
dev_err(&host->info->pdev->dev,
"Missinig flash clock register\n");
return -EINVAL;
- }
- /* fallback to a default value if tR = 0 */ if (!tR) tR = 20000;
@@ -410,6 +430,8 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1);
return 0; }
static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
@@ -419,7 +441,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) struct pxa3xx_nand_info *info = host->info_data; const struct pxa3xx_nand_flash *f = NULL; struct mtd_info *mtd = nand_to_mtd(&host->chip);
- int mode, id, ntypes, i;
int mode, id, ntypes, i, ret;
mode = onfi_get_async_timing_mode(chip); if (mode == ONFI_TIMING_MODE_UNKNOWN) {
@@ -442,7 +464,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) return -EINVAL; }
pxa3xx_nand_set_timing(host, f->timing);
ret = pxa3xx_nand_set_timing(host, f->timing);
if (ret)
return ret; if (f->flash_width == 16) { info->reg_ndcr |= NDCR_DWIDTH_M;
@@ -459,7 +483,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) if (IS_ERR(timings)) return PTR_ERR(timings);
pxa3xx_nand_set_sdr_timing(host, timings);
ret = pxa3xx_nand_set_sdr_timing(host, timings);
if (ret)
return ret;
}
return 0;
@@ -1593,6 +1619,8 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) struct pxa3xx_nand_platform_data *pdata; const void *blob = gd->fdt_blob; int node = -1;
int index;
fdt_addr_t addr;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata)
@@ -1614,6 +1642,26 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) (void __iomem *)fdtdec_get_addr_size_auto_noparent( blob, node, "reg", 0, NULL, true);
index = fdt_stringlist_search(blob, node, "reg-names",
"flash_clock");
if (index > 0) {
addr = fdtdec_get_addr_size_auto_noparent(
blob, node, "reg", index, NULL, true);
if (addr != FDT_ADDR_T_NONE)
info->nand_flash_clk_ctrl_reg =
(void __iomem *)addr;
}
index = fdt_stringlist_search(blob, node, "reg-names",
"dev_mux");
if (index > 0) {
addr = fdtdec_get_addr_size_auto_noparent(
blob, node, "reg", index, NULL, true);
if (addr != FDT_ADDR_T_NONE)
info->soc_dev_multiplex_reg =
(void __iomem *)addr;
}
pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); if (pdata->num_cs != 1) { pr_err("pxa3xx driver supports single CS only\n");
@@ -1660,6 +1708,14 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
pdata = info->pdata;
- /* If the NAND flash is enabled in DT, but the boot image is not
* running from NAND, it may be needed to enable NAND on SOC
* DEVBUS MUX level.
* When the boot device is NAND, such configuration is done
* in the BootROM.
*/
- mvebu_nand_select(info->soc_dev_multiplex_reg);
- ret = alloc_nand_resource(info); if (ret) { dev_err(&pdev->dev, "alloc nand resource failed\n");
This patch does not apply currently. I'm skipping it from this series for now. I'm currently pushing my Marvell branch upstream and would like to get the first batch of patches accepted. After Tom has pulled these patches, please rebase on top of this new master.
I'm skipping this patch again as it still does not apply anymore. Please rebase and resend.
Thanks, Stefan

From: Boris Brezillon boris.brezillon@free-electrons.com
In the current driver, OOB bytes are accessed in raw mode, and when a page access is done with NDCR_SPARE_EN set and NDCR_ECC_EN cleared, the driver must read the whole spare area (64 bytes in case of a 2k page, 16 bytes for a 512 page). The driver was only reading the free OOB bytes, which was leaving some unread data in the FIFO and was somehow leading to a timeout.
We could patch the driver to read ->spare_size + ->ecc_size instead of just ->spare_size when READOOB is requested, but we'd better make in-band and OOB accesses consistent. Since the driver is always accessing in-band data in non-raw mode (with the ECC engine enabled), we should also access OOB data in this mode. That's particularly useful when using the BCH engine because in this mode the free OOB bytes are also ECC protected.
Fixes: 43bcfd2bb24a ("mtd: nand: pxa3xx: Add driver-specific ECC BCH support") Cc: stable@vger.kernel.org Reported-by: Sean Nyekjær sean.nyekjaer@prevas.dk Tested-by: Willy Tarreau w@1wt.eu Signed-off-by: Boris Brezillon boris.brezillon@free-electrons.com Acked-by: Ezequiel Garcia ezequiel@vanguardiasur.com.ar Tested-by: Sean Nyekjaer sean.nyekjaer@prevas.dk Acked-by: Robert Jarzmik robert.jarzmik@free.fr Signed-off-by: Richard Weinberger richard@nod.at Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b64dd0d..c1f7d61 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -750,6 +750,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
switch (command) { case NAND_CMD_READ0: + case NAND_CMD_READOOB: case NAND_CMD_PAGEPROG: info->use_ecc = 1; break;

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Boris Brezillon boris.brezillon@free-electrons.com
In the current driver, OOB bytes are accessed in raw mode, and when a page access is done with NDCR_SPARE_EN set and NDCR_ECC_EN cleared, the driver must read the whole spare area (64 bytes in case of a 2k page, 16 bytes for a 512 page). The driver was only reading the free OOB bytes, which was leaving some unread data in the FIFO and was somehow leading to a timeout.
We could patch the driver to read ->spare_size + ->ecc_size instead of just ->spare_size when READOOB is requested, but we'd better make in-band and OOB accesses consistent. Since the driver is always accessing in-band data in non-raw mode (with the ECC engine enabled), we should also access OOB data in this mode. That's particularly useful when using the BCH engine because in this mode the free OOB bytes are also ECC protected.
Fixes: 43bcfd2bb24a ("mtd: nand: pxa3xx: Add driver-specific ECC BCH support") Cc: stable@vger.kernel.org Reported-by: Sean Nyekjær sean.nyekjaer@prevas.dk Tested-by: Willy Tarreau w@1wt.eu Signed-off-by: Boris Brezillon boris.brezillon@free-electrons.com Acked-by: Ezequiel Garcia ezequiel@vanguardiasur.com.ar Tested-by: Sean Nyekjaer sean.nyekjaer@prevas.dk Acked-by: Robert Jarzmik robert.jarzmik@free.fr Signed-off-by: Richard Weinberger richard@nod.at Signed-off-by: Ofer Heifetz oferh@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b64dd0d..c1f7d61 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -750,6 +750,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
switch (command) { case NAND_CMD_READ0:
- case NAND_CMD_READOOB: case NAND_CMD_PAGEPROG: info->use_ecc = 1; break;
Applied to u-boot-marvell/master
Thanks, Stefan

From: Victor Axelrod victora@marvell.com
Add support for 2KB page 8-bit ECC strength flash layout
Signed-off-by: Victor Axelrod victora@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index c1f7d61..81e75f2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -308,6 +308,20 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = { .oobfree = { {2, 30} } };
+static struct nand_ecclayout ecc_layout_2KB_bch8bit = { + .eccbytes = 64, + .eccpos = { + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { {1, 4}, {6, 26} } +}; + static struct nand_ecclayout ecc_layout_4KB_bch4bit = { .eccbytes = 64, .eccpos = { @@ -1439,6 +1453,19 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16; + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->nfullchunks = 1; + info->ntotalchunks = 2; + info->chunk_size = 1024; + info->spare_size = 0; + info->last_chunk_size = 1024; + info->last_spare_size = 64; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch8bit; + ecc->strength = 16; } else { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n",

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Victor Axelrod victora@marvell.com
Add support for 2KB page 8-bit ECC strength flash layout
Signed-off-by: Victor Axelrod victora@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index c1f7d61..81e75f2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -308,6 +308,20 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = { .oobfree = { {2, 30} } };
+static struct nand_ecclayout ecc_layout_2KB_bch8bit = {
- .eccbytes = 64,
- .eccpos = {
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127},
- .oobfree = { {1, 4}, {6, 26} }
+};
- static struct nand_ecclayout ecc_layout_4KB_bch4bit = { .eccbytes = 64, .eccpos = {
@@ -1439,6 +1453,19 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16;
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) {
info->ecc_bch = 1;
info->nfullchunks = 1;
info->ntotalchunks = 2;
info->chunk_size = 1024;
info->spare_size = 0;
info->last_chunk_size = 1024;
info->last_spare_size = 64;
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
ecc->layout = &ecc_layout_2KB_bch8bit;
} else { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n",ecc->strength = 16;
Applied to u-boot-marvell/master
Thanks, Stefan

From: Konstantin Porotchkin kostap@marvell.com
Add timings and device ID for Toshiba TC58NVG1S3HTA00 flash
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 81e75f2..a7b9864 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -256,10 +256,12 @@ struct pxa3xx_nand_info { };
static struct pxa3xx_nand_timing timing[] = { + /*ch cs wh wp rh rp r whr ar */ { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, + { 5, 20, 10, 12, 10, 12, 25000, 60, 10, }, };
static struct pxa3xx_nand_flash builtin_flash_types[] = { @@ -271,6 +273,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { 0xdc2c, 8, 8, &timing[2] }, { 0xcc2c, 16, 16, &timing[2] }, { 0xba20, 16, 16, &timing[3] }, + { 0xda98, 8, 8, &timing[4] }, };
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Konstantin Porotchkin kostap@marvell.com
Add timings and device ID for Toshiba TC58NVG1S3HTA00 flash
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 81e75f2..a7b9864 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -256,10 +256,12 @@ struct pxa3xx_nand_info { };
static struct pxa3xx_nand_timing timing[] = {
/*ch cs wh wp rh rp r whr ar */ { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, { 10, 35, 15, 25, 15, 25, 25000, 60, 10, },
{ 5, 20, 10, 12, 10, 12, 25000, 60, 10, }, };
static struct pxa3xx_nand_flash builtin_flash_types[] = {
@@ -271,6 +273,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { 0xdc2c, 8, 8, &timing[2] }, { 0xcc2c, 16, 16, &timing[2] }, { 0xba20, 16, 16, &timing[3] },
{ 0xda98, 8, 8, &timing[4] }, };
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
Applied to u-boot-marvell/master
Thanks, Stefan

From: Konstantin Porotchkin kostap@marvell.com
Replace the hardcoded value of page chink with value that depends on flash page size and ECC strength. This fixes nand access errors for 2K page flashes with 8-bit ECC. Move the initial flash commannd function assignment past the ECC structures initialization for eliminating usage of hardcoded page chunk size value.
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a7b9864..a7ca28c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -24,7 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; #define TIMEOUT_DRAIN_FIFO 5 /* in ms */ #define CHIP_DELAY_TIMEOUT 200 #define NAND_STOP_DELAY 40 -#define PAGE_CHUNK_SIZE (2048)
/* * Define a buffer size for the initial command that detects the flash device: @@ -729,7 +728,7 @@ static void set_command_address(struct pxa3xx_nand_info *info, unsigned int page_size, uint16_t column, int page_addr) { /* small page addr setting */ - if (page_size < PAGE_CHUNK_SIZE) { + if (page_size < info->chunk_size) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF);
@@ -839,9 +838,9 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, * which is either naked-read or last-read according to the * state. */ - if (mtd->writesize == PAGE_CHUNK_SIZE) { + if (mtd->writesize == info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); - } else if (mtd->writesize > PAGE_CHUNK_SIZE) { + } else if (mtd->writesize > info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type); @@ -861,7 +860,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, * Multiple page programming needs to execute the initial * SEQIN command that sets the page address. */ - if (mtd->writesize > PAGE_CHUNK_SIZE) { + if (mtd->writesize > info->chunk_size) { info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | addr_cycle @@ -886,7 +885,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, }
/* Second command setting for large pages */ - if (mtd->writesize > PAGE_CHUNK_SIZE) { + if (mtd->writesize > info->chunk_size) { /* * Multiple page write uses the 'extended command' * field. This can be used to issue a command dispatch @@ -1312,7 +1311,6 @@ static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) struct pxa3xx_nand_platform_data *pdata = info->pdata;
/* Configure default flash values */ - info->chunk_size = PAGE_CHUNK_SIZE; info->reg_ndcr = 0x0; /* enable all interrupts */ info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); @@ -1529,21 +1527,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->bbt_md = &bbt_mirror_descr; #endif
- /* - * If the page size is bigger than the FIFO size, let's check - * we are given the right variant and then switch to the extended - * (aka splitted) command handling, - */ - if (mtd->writesize > PAGE_CHUNK_SIZE) { - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { - chip->cmdfunc = nand_cmdfunc_extended; - } else { - dev_err(&info->pdev->dev, - "unsupported page size on this variant\n"); - return -ENODEV; - } - } - if (pdata->ecc_strength && pdata->ecc_step_size) { ecc_strength = pdata->ecc_strength; ecc_step = pdata->ecc_step_size; @@ -1563,6 +1546,21 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (ret) return ret;
+ /* + * If the page size is bigger than the FIFO size, let's check + * we are given the right variant and then switch to the extended + * (aka split) command handling, + */ + if (mtd->writesize > info->chunk_size) { + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { + chip->cmdfunc = nand_cmdfunc_extended; + } else { + dev_err(&info->pdev->dev, + "unsupported page size on this variant\n"); + return -ENODEV; + } + } + /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2;

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Konstantin Porotchkin kostap@marvell.com
Replace the hardcoded value of page chink with value that depends on flash page size and ECC strength. This fixes nand access errors for 2K page flashes with 8-bit ECC. Move the initial flash commannd function assignment past the ECC structures initialization for eliminating usage of hardcoded page chunk size value.
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a7b9864..a7ca28c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -24,7 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; #define TIMEOUT_DRAIN_FIFO 5 /* in ms */ #define CHIP_DELAY_TIMEOUT 200 #define NAND_STOP_DELAY 40 -#define PAGE_CHUNK_SIZE (2048)
/*
- Define a buffer size for the initial command that detects the flash device:
@@ -729,7 +728,7 @@ static void set_command_address(struct pxa3xx_nand_info *info, unsigned int page_size, uint16_t column, int page_addr) { /* small page addr setting */
- if (page_size < PAGE_CHUNK_SIZE) {
- if (page_size < info->chunk_size) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF);
@@ -839,9 +838,9 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, * which is either naked-read or last-read according to the * state. */
if (mtd->writesize == PAGE_CHUNK_SIZE) {
if (mtd->writesize == info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
} else if (mtd->writesize > info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | NDCB0_LEN_OVRD | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
@@ -861,7 +860,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, * Multiple page programming needs to execute the initial * SEQIN command that sets the page address. */
if (mtd->writesize > PAGE_CHUNK_SIZE) {
if (mtd->writesize > info->chunk_size) { info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_EXT_CMD_TYPE(ext_cmd_type) | addr_cycle
@@ -886,7 +885,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, }
/* Second command setting for large pages */
if (mtd->writesize > PAGE_CHUNK_SIZE) {
if (mtd->writesize > info->chunk_size) { /* * Multiple page write uses the 'extended command' * field. This can be used to issue a command dispatch
@@ -1312,7 +1311,6 @@ static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) struct pxa3xx_nand_platform_data *pdata = info->pdata;
/* Configure default flash values */
- info->chunk_size = PAGE_CHUNK_SIZE; info->reg_ndcr = 0x0; /* enable all interrupts */ info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
@@ -1529,21 +1527,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->bbt_md = &bbt_mirror_descr; #endif
- /*
* If the page size is bigger than the FIFO size, let's check
* we are given the right variant and then switch to the extended
* (aka splitted) command handling,
*/
- if (mtd->writesize > PAGE_CHUNK_SIZE) {
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
chip->cmdfunc = nand_cmdfunc_extended;
} else {
dev_err(&info->pdev->dev,
"unsupported page size on this variant\n");
return -ENODEV;
}
- }
- if (pdata->ecc_strength && pdata->ecc_step_size) { ecc_strength = pdata->ecc_strength; ecc_step = pdata->ecc_step_size;
@@ -1563,6 +1546,21 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (ret) return ret;
- /*
* If the page size is bigger than the FIFO size, let's check
* we are given the right variant and then switch to the extended
* (aka split) command handling,
*/
- if (mtd->writesize > info->chunk_size) {
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
chip->cmdfunc = nand_cmdfunc_extended;
} else {
dev_err(&info->pdev->dev,
"unsupported page size on this variant\n");
return -ENODEV;
}
- }
- /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2;
Applied to u-boot-marvell/master
Thanks, Stefan

From: Konstantin Porotchkin kostap@marvell.com
Add comments with timing parameter names and some details about nand layout fileds. Remove unneeded definition.
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a7ca28c..e08ad00 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -61,7 +61,6 @@ DECLARE_GLOBAL_DATA_PTR; #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) #define NFCV1_NDCR_ARB_CNTL (0x1 << 19) -#define NFCV2_NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK)
@@ -255,6 +254,17 @@ struct pxa3xx_nand_info { };
static struct pxa3xx_nand_timing timing[] = { + /* + * tCH Enable signal hold time + * tCS Enable signal setup time + * tWH ND_nWE high duration + * tWP ND_nWE pulse time + * tRH ND_nRE high duration + * tRP ND_nRE pulse width + * tR ND_nWE high to ND_nRE low for read + * tWHR ND_nWE high to ND_nRE low for status read + * tAR ND_ALE low to ND_nRE low delay + */ /*ch cs wh wp rh rp r whr ar */ { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, @@ -264,6 +274,13 @@ static struct pxa3xx_nand_timing timing[] = { };
static struct pxa3xx_nand_flash builtin_flash_types[] = { + /* + * chip_id + * flash_width Width of Flash memory (DWIDTH_M) + * dfc_width Width of flash controller(DWIDTH_C) + * *timing + * http://www.linux-mtd.infradead.org/nand-data/nanddata.html + */ { 0x46ec, 16, 16, &timing[1] }, { 0xdaec, 8, 8, &timing[1] }, { 0xd7ec, 8, 8, &timing[1] }, @@ -1454,6 +1471,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16; + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { info->ecc_bch = 1; info->nfullchunks = 1; @@ -1467,6 +1485,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_2KB_bch8bit; ecc->strength = 16; + } else { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n",

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Konstantin Porotchkin kostap@marvell.com
Add comments with timing parameter names and some details about nand layout fileds. Remove unneeded definition.
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a7ca28c..e08ad00 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -61,7 +61,6 @@ DECLARE_GLOBAL_DATA_PTR; #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) #define NFCV1_NDCR_ARB_CNTL (0x1 << 19) -#define NFCV2_NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK)
@@ -255,6 +254,17 @@ struct pxa3xx_nand_info { };
static struct pxa3xx_nand_timing timing[] = {
- /*
* tCH Enable signal hold time
* tCS Enable signal setup time
* tWH ND_nWE high duration
* tWP ND_nWE pulse time
* tRH ND_nRE high duration
* tRP ND_nRE pulse width
* tR ND_nWE high to ND_nRE low for read
* tWHR ND_nWE high to ND_nRE low for status read
* tAR ND_ALE low to ND_nRE low delay
/*ch cs wh wp rh rp r whr ar */ { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, },*/
@@ -264,6 +274,13 @@ static struct pxa3xx_nand_timing timing[] = { };
static struct pxa3xx_nand_flash builtin_flash_types[] = {
- /*
* chip_id
* flash_width Width of Flash memory (DWIDTH_M)
* dfc_width Width of flash controller(DWIDTH_C)
* *timing
* http://www.linux-mtd.infradead.org/nand-data/nanddata.html
{ 0x46ec, 16, 16, &timing[1] }, { 0xdaec, 8, 8, &timing[1] }, { 0xd7ec, 8, 8, &timing[1] },*/
@@ -1454,6 +1471,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16;
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { info->ecc_bch = 1; info->nfullchunks = 1;
@@ -1467,6 +1485,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = info->chunk_size; ecc->layout = &ecc_layout_2KB_bch8bit; ecc->strength = 16;
- } else { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n",
Applied to u-boot-marvell/master
Thanks, Stefan

From: Konstantin Porotchkin kostap@marvell.com
Add support for NAND chips with 8KB page, 4 and 8 bit ECC (ONFI).
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Ofer Heifetz oferh@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 72 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e08ad00..b1bd430 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -356,6 +356,33 @@ static struct nand_ecclayout ecc_layout_4KB_bch4bit = { .oobfree = { {6, 26}, { 64, 32} } };
+static struct nand_ecclayout ecc_layout_8KB_bch4bit = { + .eccbytes = 128, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255}, + + /* Bootrom looks in bytes 0 & 5 for bad blocks */ + .oobfree = { {1, 4}, {6, 26}, { 64, 32}, {128, 32}, {192, 32} } +}; + static struct nand_ecclayout ecc_layout_4KB_bch8bit = { .eccbytes = 128, .eccpos = { @@ -366,6 +393,13 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = { .oobfree = { } };
+static struct nand_ecclayout ecc_layout_8KB_bch8bit = { + .eccbytes = 256, + .eccpos = {}, + /* HW ECC handles all ECC data and all spare area is free for OOB */ + .oobfree = {{0, 160} } +}; + #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) #define NDTR0_tWH(c) (min((c), 7) << 11) @@ -1454,10 +1488,36 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->layout = &ecc_layout_4KB_bch4bit; ecc->strength = 16;
+ } else if (strength == 4 && ecc_stepsize == 512 && page_size == 8192) { + info->ecc_bch = 1; + info->nfullchunks = 4; + info->ntotalchunks = 4; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_8KB_bch4bit; + ecc->strength = 16; + /* * Required ECC: 8-bit correction per 512 bytes * Select: 16-bit correction per 1024 bytes */ + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->nfullchunks = 1; + info->ntotalchunks = 2; + info->chunk_size = 1024; + info->spare_size = 0; + info->last_chunk_size = 1024; + info->last_spare_size = 64; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch8bit; + ecc->strength = 16; + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->nfullchunks = 4; @@ -1472,18 +1532,18 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16;
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 8192) { info->ecc_bch = 1; - info->nfullchunks = 1; - info->ntotalchunks = 2; + info->nfullchunks = 8; + info->ntotalchunks = 9; info->chunk_size = 1024; info->spare_size = 0; - info->last_chunk_size = 1024; - info->last_spare_size = 64; + info->last_chunk_size = 0; + info->last_spare_size = 160; info->ecc_size = 32; ecc->mode = NAND_ECC_HW; ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_2KB_bch8bit; + ecc->layout = &ecc_layout_8KB_bch8bit; ecc->strength = 16;
} else {

On 29.08.2018 10:56, kostap@marvell.com wrote:
From: Konstantin Porotchkin kostap@marvell.com
Add support for NAND chips with 8KB page, 4 and 8 bit ECC (ONFI).
Signed-off-by: Konstantin Porotchkin kostap@marvell.com Reviewed-by: Ofer Heifetz oferh@marvell.com Cc: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org
drivers/mtd/nand/pxa3xx_nand.c | 72 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e08ad00..b1bd430 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -356,6 +356,33 @@ static struct nand_ecclayout ecc_layout_4KB_bch4bit = { .oobfree = { {6, 26}, { 64, 32} } };
+static struct nand_ecclayout ecc_layout_8KB_bch4bit = {
- .eccbytes = 128,
- .eccpos = {
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127,
160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255},
- /* Bootrom looks in bytes 0 & 5 for bad blocks */
- .oobfree = { {1, 4}, {6, 26}, { 64, 32}, {128, 32}, {192, 32} }
+};
- static struct nand_ecclayout ecc_layout_4KB_bch8bit = { .eccbytes = 128, .eccpos = {
@@ -366,6 +393,13 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = { .oobfree = { } };
+static struct nand_ecclayout ecc_layout_8KB_bch8bit = {
- .eccbytes = 256,
- .eccpos = {},
- /* HW ECC handles all ECC data and all spare area is free for OOB */
- .oobfree = {{0, 160} }
+};
- #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) #define NDTR0_tWH(c) (min((c), 7) << 11)
@@ -1454,10 +1488,36 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->layout = &ecc_layout_4KB_bch4bit; ecc->strength = 16;
- } else if (strength == 4 && ecc_stepsize == 512 && page_size == 8192) {
info->ecc_bch = 1;
info->nfullchunks = 4;
info->ntotalchunks = 4;
info->chunk_size = 2048;
info->spare_size = 32;
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
ecc->layout = &ecc_layout_8KB_bch4bit;
ecc->strength = 16;
- /*
*/
- Required ECC: 8-bit correction per 512 bytes
- Select: 16-bit correction per 1024 bytes
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) {
info->ecc_bch = 1;
info->nfullchunks = 1;
info->ntotalchunks = 2;
info->chunk_size = 1024;
info->spare_size = 0;
info->last_chunk_size = 1024;
info->last_spare_size = 64;
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
ecc->layout = &ecc_layout_2KB_bch8bit;
ecc->strength = 16;
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->nfullchunks = 4;
@@ -1472,18 +1532,18 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->layout = &ecc_layout_4KB_bch8bit; ecc->strength = 16;
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) {
- } else if (strength == 8 && ecc_stepsize == 512 && page_size == 8192) { info->ecc_bch = 1;
info->nfullchunks = 1;
info->ntotalchunks = 2;
info->nfullchunks = 8;
info->chunk_size = 1024; info->spare_size = 0;info->ntotalchunks = 9;
info->last_chunk_size = 1024;
info->last_spare_size = 64;
info->last_chunk_size = 0;
info->ecc_size = 32; ecc->mode = NAND_ECC_HW; ecc->size = info->chunk_size;info->last_spare_size = 160;
ecc->layout = &ecc_layout_2KB_bch8bit;
ecc->layout = &ecc_layout_8KB_bch8bit;
ecc->strength = 16;
} else {
Applied to u-boot-marvell/master
Thanks, Stefan

From: David Sniatkiwicz davidsn@marvell.com
add delay before processing the status flags in pxa3xx_nand_irq().
Signed-off-by: David Sniatkiwicz davidsn@marvell.com Reviewed-by: Igal Liberman igall@marvell.com Reviewed-by: Kostya Porotchkin kostap@marvell.com c: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org --- drivers/mtd/nand/pxa3xx_nand.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b1bd430..05fd2df 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -694,6 +694,9 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) cmd_done = NDSR_CS1_CMDD; }
+ /* TODO - find out why we need the delay during write operation. */ + ndelay(1); + status = nand_readl(info, NDSR);
if (status & NDSR_UNCORERR)
participants (2)
-
kostap@marvell.com
-
Stefan Roese