Hi all,
This series introduces the support for the Marvell Berlin nand
controller. It is based on top of v3.19 and was tested on the
Marvell Berlin BG2Q DMP board.
The support is added into the existing pxa3xx nand controller. Some
additions were done in order to get this controller working:
- Support for a non mandatory ECC clock has been added.
- The Berlin nand controller needs to poll the status register.
- Sequences of commands are quite different in order to perform write
operation.
Changes were done in order to avoid impacting other controllers using
this driver, but I'd like people actually using the pxa3xx nand driver
to test theses patches to ensure no harm was done. A specific Berlin
nand cmd function has been added to deal with most of the Berlin
specific code.
Because of a bug in the Berlin clock driver, this series requires the
fix provided by Jisheng Zhang, which is already in v3.19-rc6
(b71e8ecd57c8aae5b1815782c47b74ffe3efc09a).
Thanks!
Antoine
Changes since v1:
- Added a fallback to NULL when looking for the 'nfc' clock
- Added the clocks in the bindings documentation
- Reworked the DT
- Removed non needed RNDOUT command
- Used the standard RESET command
- Fixed the flash type matching order
- Remove all non tested flash types (only one left)
- Added a check to explicitly not support nand chips with small pages
- Remove useless checks for clocks in the probing function
- Various clean up
Antoine Tenart (10):
mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
mtd: pxa3xx_nand: add a non mandatory ECC clock
Documentation: bindings: document the clocks for pxa3xx-nand
mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
mtd: pxa3xx_nand: add a default chunk size
mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
Documentation: bindings: add the Berlin nand controller compatible
mtd: nand: let Marvell Berlin SoCs select the pxa3xx driver
ARM: berlin: add BG2Q node for the nand
ARM: berlin: enable flash on the BG2Q DMP
.../devicetree/bindings/mtd/pxa3xx-nand.txt | 5 +
arch/arm/boot/dts/berlin2q-marvell-dmp.dts | 25 ++
arch/arm/boot/dts/berlin2q.dtsi | 13 +
drivers/mtd/nand/Kconfig | 2 +-
drivers/mtd/nand/pxa3xx_nand.c | 268 ++++++++++++++++++---
5 files changed, 276 insertions(+), 37 deletions(-)
--
2.3.0
pxa3xx_flash_ids wasn't initialized to 0, which in certain cases could
end up containing corrupted values in its members. Fix this to avoid
possible issues.
Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/mtd/nand/pxa3xx_nand.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 96b0b1d27df1..d00ac392d1c4 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1472,6 +1472,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
return ret;
}
+ memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids));
+
pxa3xx_flash_ids[0].name = f->name;
pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff;
pxa3xx_flash_ids[0].pagesize = f->page_size;
--
2.3.0
Some controllers (as the coming Berlin nand controller) need to enable
an ECC clock. Add support for this clock in the pxa3xx nand driver, and
leave it as non mandatory.
Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/mtd/nand/pxa3xx_nand.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index d00ac392d1c4..55fce9527c2e 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -180,7 +180,7 @@ struct pxa3xx_nand_info {
struct nand_hw_control controller;
struct platform_device *pdev;
- struct clk *clk;
+ struct clk *clk, *ecc_clk;
void __iomem *mmio_base;
unsigned long mmio_phys;
struct completion cmd_complete, dev_ready;
@@ -1608,15 +1608,26 @@ static int alloc_nand_resource(struct platform_device *pdev)
spin_lock_init(&chip->controller->lock);
init_waitqueue_head(&chip->controller->wq);
- info->clk = devm_clk_get(&pdev->dev, NULL);
+ info->clk = devm_clk_get(&pdev->dev, "nfc");
if (IS_ERR(info->clk)) {
- dev_err(&pdev->dev, "failed to get nand clock\n");
- return PTR_ERR(info->clk);
+ info->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (IS_ERR(info->clk)) {
+ dev_err(&pdev->dev, "failed to get nand clock\n");
+ return PTR_ERR(info->clk);
+ }
}
ret = clk_prepare_enable(info->clk);
if (ret < 0)
return ret;
+ info->ecc_clk = devm_clk_get(&pdev->dev, "ecc");
+ if (!IS_ERR(info->ecc_clk)) {
+ ret = clk_prepare_enable(info->ecc_clk);
+ if (ret < 0)
+ goto fail_disable_clk;
+ }
+
if (use_dma) {
/*
* This is a dirty hack to make this driver work from
@@ -1633,7 +1644,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
dev_err(&pdev->dev,
"no resource defined for data DMA\n");
ret = -ENXIO;
- goto fail_disable_clk;
+ goto fail_disable_ecc_clk;
}
info->drcmr_dat = r->start;
@@ -1642,7 +1653,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
dev_err(&pdev->dev,
"no resource defined for cmd DMA\n");
ret = -ENXIO;
- goto fail_disable_clk;
+ goto fail_disable_ecc_clk;
}
info->drcmr_cmd = r->start;
}
@@ -1652,14 +1663,14 @@ static int alloc_nand_resource(struct platform_device *pdev)
if (irq < 0) {
dev_err(&pdev->dev, "no IRQ resource defined\n");
ret = -ENXIO;
- goto fail_disable_clk;
+ goto fail_disable_ecc_clk;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(info->mmio_base)) {
ret = PTR_ERR(info->mmio_base);
- goto fail_disable_clk;
+ goto fail_disable_ecc_clk;
}
info->mmio_phys = r->start;
@@ -1668,7 +1679,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
if (info->data_buff == NULL) {
ret = -ENOMEM;
- goto fail_disable_clk;
+ goto fail_disable_ecc_clk;
}
/* initialize all interrupts to be disabled */
@@ -1687,6 +1698,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
fail_free_buf:
free_irq(irq, info);
kfree(info->data_buff);
+fail_disable_ecc_clk:
+ clk_disable_unprepare(info->ecc_clk);
fail_disable_clk:
clk_disable_unprepare(info->clk);
return ret;
@@ -1709,6 +1722,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
pxa3xx_nand_free_buff(info);
clk_disable_unprepare(info->clk);
+ clk_disable_unprepare(info->ecc_clk);
for (cs = 0; cs < pdata->num_cs; cs++)
nand_release(info->host[cs]->mtd);
--
2.3.0
The pxa3xx nand driver requires at least one clock to probe correctly.
A second one, named 'ecc' can be specified if needed. Add the
corresponding documentation.
Signed-off-by: Antoine Tenart <[email protected]>
---
Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
index de8b517a5521..ecd1fc071f81 100644
--- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
@@ -8,6 +8,8 @@ Required properties:
- reg: The register base for the controller
- interrupts: The interrupt to map
- #address-cells: Set to <1> if the node includes partitions
+ - clocks: A phandle to the clocks
+ - clock-names: 'nfc' and 'ecc'. The 'nfc' clock is mandatory.
Optional properties:
@@ -32,6 +34,8 @@ Example:
compatible = "marvell,pxa3xx-nand";
reg = <0x43100000 90>;
interrupts = <45>;
+ clocks = <&gateclk 11>;
+ clock-names = "nfc";
#address-cells = <1>;
marvell,nand-enable-arbiter;
--
2.3.0
Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/mtd/nand/pxa3xx_nand.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 55fce9527c2e..64628bff3fa5 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1216,7 +1216,8 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
- ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
+ ndcr |= (f->page_per_block == 64 || f->page_per_block == 128) ?
+ NDCR_PG_PER_BLK : 0;
ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
--
2.3.0
Add a default chunk size of 512 in the pxa3xx nand driver.
Signed-off-by: Antoine Tenart <[email protected]>
---
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 64628bff3fa5..8ed045195d31 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1430,6 +1430,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 = 512;
+
ret = pxa3xx_nand_sensing(info);
if (ret) {
dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
--
2.3.0
The nand controller on Marvell Berlin SoC reuse the pxa3xx nand driver
as it quite close. The process of sending commands can be compared to
the one of the Marvell armada 370: read and write commands are done in
chunks.
But the Berlin nand controller has some other specificities which
require some modifications of the pxa3xx nand driver:
- there are no IRQ available so we need to poll the status register: we
have to use our own cmdfunc Berlin function, and early on the probing
function.
- PAGEPROG are very different from the one used in the pxa3xx driver,
so we're using a specific process for this one
- the SEQIN command is equivalent to a READ0 command
Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/mtd/nand/pxa3xx_nand.c | 228 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 202 insertions(+), 26 deletions(-)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 8ed045195d31..a74ce08ea95e 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -109,6 +109,8 @@
#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
#define NDCB0_CMD_TYPE_MASK (0x7 << 21)
#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK)
+#define NDCB0_CMD_XTYPE_MASK (0x7 << 29)
+#define NDCB0_CMD_XTYPE(x) (((x) << 29) & NDCB0_CMD_XTYPE_MASK)
#define NDCB0_NC (0x1 << 20)
#define NDCB0_DBC (0x1 << 19)
#define NDCB0_ADDR_CYC_MASK (0x7 << 16)
@@ -117,13 +119,15 @@
#define NDCB0_CMD1_MASK (0xff)
#define NDCB0_ADDR_CYC_SHIFT (16)
-#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */
-#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */
-#define EXT_CMD_TYPE_READ 4 /* Read */
-#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */
-#define EXT_CMD_TYPE_FINAL 3 /* Final command */
-#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */
-#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
+#define EXT_CMD_TYPE_LAST_PAGEPROG 8
+#define EXT_CMD_TYPE_CHUNK_PAGEPROG 7
+#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */
+#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */
+#define EXT_CMD_TYPE_READ 4 /* Read */
+#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */
+#define EXT_CMD_TYPE_FINAL 3 /* Final command */
+#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */
+#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
/* macros for registers read/write */
#define nand_writel(info, off, val) \
@@ -158,6 +162,7 @@ enum {
enum pxa3xx_nand_variant {
PXA3XX_NAND_VARIANT_PXA,
PXA3XX_NAND_VARIANT_ARMADA370,
+ PXA3XX_NAND_VARIANT_BERLIN2,
};
struct pxa3xx_nand_host {
@@ -244,10 +249,11 @@ module_param(use_dma, bool, 0444);
MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
static struct pxa3xx_nand_timing timing[] = {
- { 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, },
+ { 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, 200000, 120, 10, },
};
static struct pxa3xx_nand_flash builtin_flash_types[] = {
@@ -260,6 +266,12 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
{ "512MiB 8-bit", 0xdc2c, 64, 2048, 8, 8, 4096, &timing[2] },
{ "512MiB 16-bit", 0xcc2c, 64, 2048, 16, 16, 4096, &timing[2] },
{ "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] },
+{ },
+};
+
+static struct pxa3xx_nand_flash berlin_builtin_flash_types[] = {
+{ "4GiB 8-bit", 0xd7ec, 128, 8192, 8, 8, 4096, &timing[4] },
+{ },
};
static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
@@ -320,6 +332,18 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
.oobfree = { }
};
+static struct nand_ecclayout ecc_layout_oob_128 = {
+ .eccbytes = 48,
+ .eccpos = {
+ 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 = { {.offset = 2, .length = 78} }
+};
+
/* Define a default flash type setting serve as flash detecting only */
#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
@@ -346,6 +370,10 @@ static const struct of_device_id pxa3xx_nand_dt_ids[] = {
.compatible = "marvell,armada370-nand",
.data = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
},
+ {
+ .compatible = "marvell,berlin2-nand",
+ .data = (void *)PXA3XX_NAND_VARIANT_BERLIN2,
+ },
{}
};
MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
@@ -645,7 +673,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
nand_writel(info, NDCB0, info->ndcb2);
/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
- if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
+ info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
nand_writel(info, NDCB0, info->ndcb3);
}
@@ -755,6 +784,16 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
if (command == NAND_CMD_SEQIN)
exec_cmd = 0;
+ /* Berlin specific */
+ if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
+ if ((command == NAND_CMD_READ0 && !ext_cmd_type) ||
+ command == NAND_CMD_READOOB)
+ exec_cmd = 0;
+
+ if (command == NAND_CMD_SEQIN)
+ command = NAND_CMD_READ0;
+ }
+
addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
+ host->col_addr_cycles);
@@ -814,6 +853,37 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
break;
}
+ if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
+ if (ext_cmd_type == EXT_CMD_TYPE_LAST_PAGEPROG) {
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+ | NDCB0_CMD_XTYPE(0x3)
+ | NDCB0_ST_ROW_EN
+ | NDCB0_DBC
+ | (NAND_CMD_PAGEPROG << 8);
+ } else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_PAGEPROG) {
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+ | NDCB0_CMD_XTYPE(0x5)
+ | NDCB0_NC
+ | NDCB0_AUTO_RS
+ | NDCB0_LEN_OVRD
+ | (NAND_CMD_PAGEPROG << 8)
+ | NAND_CMD_SEQIN;
+ info->ndcb3 = info->chunk_size;
+ } else {
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+ | NDCB0_CMD_XTYPE(0x4)
+ | NDCB0_NC
+ | NDCB0_AUTO_RS
+ | NDCB0_LEN_OVRD
+ | addr_cycle
+ | (NAND_CMD_PAGEPROG << 8)
+ | NAND_CMD_SEQIN;
+ info->ndcb3 = info->chunk_size;
+ }
+
+ break;
+ }
+
/* Second command setting for large pages */
if (mtd->writesize > PAGE_CHUNK_SIZE) {
/*
@@ -870,6 +940,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
info->data_size = 8;
break;
+
case NAND_CMD_STATUS:
info->buf_count = 1;
info->ndcb0 |= NDCB0_CMD_TYPE(4)
@@ -1078,6 +1149,89 @@ static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
return 0;
}
+static void nand_cmdfunc_berlin(struct mtd_info *mtd, const unsigned command,
+ int column, int page_addr)
+{
+ struct pxa3xx_nand_host *host = mtd->priv;
+ struct pxa3xx_nand_info *info = host->info_data;
+ unsigned long timeout;
+ int exec_cmd, ext_cmd_type = 0;
+ unsigned cmd = command;
+
+ if (info->reg_ndcr & NDCR_DWIDTH_M)
+ column /= 2;
+
+ /*
+ * There may be different NAND chip hooked to
+ * different chip select, so check whether
+ * chip select has been changed, if yes, reset the timing
+ */
+ if (info->cs != host->cs) {
+ info->cs = host->cs;
+ nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+ nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+ }
+
+ prepare_start_command(info, cmd);
+
+ info->need_wait = 1;
+ init_completion(&info->dev_ready);
+
+ pxa3xx_nand_start(info);
+
+ do {
+ init_completion(&info->cmd_complete);
+ info->state = STATE_PREPARED;
+ exec_cmd = prepare_set_command(info, cmd, ext_cmd_type,
+ column, page_addr);
+
+ if (cmd == NAND_CMD_READ0 && !ext_cmd_type) {
+ ext_cmd_type = NDCB0_CMD_XTYPE(0x5);
+ continue;
+ }
+
+ if (!exec_cmd) {
+ info->need_wait = 0;
+ complete(&info->dev_ready);
+ break;
+ }
+
+ /* no IRQ, poll */
+ timeout = jiffies + CHIP_DELAY_TIMEOUT;
+ do {
+ pxa3xx_nand_irq(0, info);
+
+ if (cmd == NAND_CMD_PAGEPROG &&
+ ext_cmd_type != EXT_CMD_TYPE_LAST_PAGEPROG)
+ break;
+
+ if (time_after(jiffies, timeout))
+ goto berlin_timeout;
+ } while (!completion_done(&info->cmd_complete));
+
+ /* sequence completed */
+ if (info->data_size == 0)
+ break;
+
+ if (cmd == NAND_CMD_PAGEPROG &&
+ ext_cmd_type == EXT_CMD_TYPE_LAST_PAGEPROG) {
+ complete(&info->dev_ready);
+ break;
+ }
+
+ if (cmd == NAND_CMD_PAGEPROG) {
+ /* last command */
+ if (info->data_size == info->chunk_size * 2)
+ ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
+ else
+ ext_cmd_type = EXT_CMD_TYPE_CHUNK_PAGEPROG;
+ }
+ } while (1);
+
+berlin_timeout:
+ info->state = STATE_IDLE;
+}
+
static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required,
int page)
@@ -1193,8 +1347,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
struct pxa3xx_nand_host *host = info->host[info->cs];
uint32_t ndcr = 0x0; /* enable all interrupts */
- if (f->page_size != 2048 && f->page_size != 512) {
- dev_err(&pdev->dev, "Current only support 2048 and 512 size\n");
+ if (f->page_size != 8192 && f->page_size != 2048
+ && f->page_size != 512) {
+ dev_err(&pdev->dev,
+ "Current only support 8192, 2048 and 512 size\n");
return -EINVAL;
}
@@ -1401,6 +1557,16 @@ 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 == 48 && ecc_stepsize == 1024 &&
+ page_size == 8192) {
+ info->ecc_bch = 1;
+ info->chunk_size = 2048;
+ info->spare_size = 0;
+ info->ecc_size = 32;
+ ecc->mode = NAND_ECC_HW;
+ ecc->size = info->chunk_size;
+ ecc->layout = &ecc_layout_oob_128;
+ ecc->strength = 48;
} else {
dev_err(&info->pdev->dev,
"ECC strength %d at page size %d is not supported\n",
@@ -1420,11 +1586,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
- const struct pxa3xx_nand_flash *f = NULL;
+ const struct pxa3xx_nand_flash *flash_types = NULL, *f = NULL;
struct nand_chip *chip = mtd->priv;
uint32_t id = -1;
uint64_t chipsize;
- int i, ret, num;
+ int i, ret;
uint16_t ecc_strength, ecc_step;
if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
@@ -1433,6 +1599,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
/* Set a default chunk size */
info->chunk_size = 512;
+ if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
+ chip->cmdfunc = nand_cmdfunc_berlin;
+
ret = pxa3xx_nand_sensing(info);
if (ret) {
dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
@@ -1452,19 +1621,24 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
return -EINVAL;
}
- num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1;
- for (i = 0; i < num; i++) {
- if (i < pdata->num_flash)
- f = pdata->flash + i;
- else
- f = &builtin_flash_types[i - pdata->num_flash + 1];
+ if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
+ flash_types = berlin_builtin_flash_types;
+ else
+ flash_types = builtin_flash_types;
- /* find the chip in default list */
+ for (i = 0; i < pdata->num_flash; i++) {
+ f = pdata->flash + i;
if (f->chip_id == id)
break;
}
- if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
+ if (f == NULL) {
+ for (i = 0; (f = &flash_types[i]); i++)
+ if (f->chip_id == id)
+ break;
+ }
+
+ if (f == NULL) {
dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
return -EINVAL;
@@ -1516,9 +1690,11 @@ KEEP_CONFIG:
* (aka splitted) command handling,
*/
if (mtd->writesize > PAGE_CHUNK_SIZE) {
- if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
chip->cmdfunc = nand_cmdfunc_extended;
- } else {
+
+ if (info->variant != PXA3XX_NAND_VARIANT_ARMADA370 &&
+ info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
dev_err(&info->pdev->dev,
"unsupported page size on this variant\n");
return -ENODEV;
--
2.3.0
The Berlin nand controller support was introduced using the existing
pxa3xx nand driver. Add the Berlin specific compatible into the
documentation.
Signed-off-by: Antoine Tenart <[email protected]>
---
Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
index ecd1fc071f81..f33ee0aa0a2e 100644
--- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
@@ -5,6 +5,7 @@ Required properties:
- compatible: Should be set to one of the following:
marvell,pxa3xx-nand
marvell,armada370-nand
+ marvell,berlin2-nand
- reg: The register base for the controller
- interrupts: The interrupt to map
- #address-cells: Set to <1> if the node includes partitions
--
2.3.0
Marvell Berlin nand controller support has been added in the pxa3xx nand
driver. Let these SoCs select the driver.
Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/mtd/nand/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7d0150d20432..71663027a00e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -332,7 +332,7 @@ config MTD_NAND_ATMEL
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
- depends on PXA3xx || ARCH_MMP || PLAT_ORION
+ depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_BERLIN
help
This enables the driver for the NAND flash device found on
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
--
2.3.0
Add a node describing the nand controller of the Marvell Berlin BG2Q
SoC. It uses the pxa3xx nand driver, with a dedicated compatible.
Also add the corresponding pinmuxing configuration.
Signed-off-by: Antoine Tenart <[email protected]>
---
arch/arm/boot/dts/berlin2q.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index e2f61f27944e..9f5d48b68e16 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -429,6 +429,19 @@
status = "disabled";
};
+ nand0: nand@f00000 {
+ compatible = "marvell,berlin2-nand";
+ reg = <0xf00000 0x10000>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_NFC>,
+ <&chip CLKID_NFC_ECC>;
+ clock-names = "nfc", "ecc";
+
+ #address-cells = <1>;
+
+ status = "disabled";
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
--
2.3.0
The BG2Q DMP has a nand controller. Add the corresponding node, but do
not enable it by default because the nand is only available on some BG2Q
DMP.
Signed-off-by: Antoine Tenart <[email protected]>
---
arch/arm/boot/dts/berlin2q-marvell-dmp.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index a98ac1bd8f65..4157258a6fb0 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -112,3 +112,28 @@
&sata_phy {
status = "okay";
};
+
+&chip {
+ nand_pmux: nand-pmux {
+ groups = "G0", "G1";
+ function = "nand";
+ };
+};
+
+&nand0 {
+ pinctrl-0 = <&nand_pmux>;
+ pinctrl-names = "default";
+
+ marvell,nand-enable-arbiter;
+ nand-ecc-strength = <48>;
+ nand-ecc-step-size = <1024>;
+
+ num-cs = <1>;
+
+ /*
+ * Two kinds of BG2Q DMP are available: one with emmc and
+ * one with a nand. The latter is not widespread. Because
+ * of this, disable the nand by default.
+ */
+ status = "disabled";
+};
--
2.3.0
On Thu, 12 Feb 2015 15:53:30 +0100
Antoine Tenart <[email protected]> wrote:
Hm, still no commit message here ;-)
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> drivers/mtd/nand/pxa3xx_nand.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index 55fce9527c2e..64628bff3fa5 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -1216,7 +1216,8 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>
> ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
> ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
> - ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
> + ndcr |= (f->page_per_block == 64 || f->page_per_block == 128) ?
> + NDCR_PG_PER_BLK : 0;
> ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
> ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
> ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
On Thu, 12 Feb 2015 15:53:31 +0100
Antoine Tenart <[email protected]> wrote:
> Add a default chunk size of 512 in the pxa3xx nand driver.
>
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> 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 64628bff3fa5..8ed045195d31 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -1430,6 +1430,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 */
Ditto => no explanation about why you do that.
> + info->chunk_size = 512;
> +
> ret = pxa3xx_nand_sensing(info);
> if (ret) {
> dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
On Thu, Feb 12, 2015 at 04:16:16PM +0100, Boris Brezillon wrote:
> On Thu, 12 Feb 2015 15:53:30 +0100
> Antoine Tenart <[email protected]> wrote:
>
> Hm, still no commit message here ;-)
I knew I missed something... I'll fix this.
>
> > Signed-off-by: Antoine Tenart <[email protected]>
> > ---
> > drivers/mtd/nand/pxa3xx_nand.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index 55fce9527c2e..64628bff3fa5 100644
> > --- a/drivers/mtd/nand/pxa3xx_nand.c
> > +++ b/drivers/mtd/nand/pxa3xx_nand.c
> > @@ -1216,7 +1216,8 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
> >
> > ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
> > ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
> > - ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
> > + ndcr |= (f->page_per_block == 64 || f->page_per_block == 128) ?
> > + NDCR_PG_PER_BLK : 0;
> > ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
> > ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
> > ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
>
>
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
--
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
On Thu, Feb 12, 2015 at 04:17:32PM +0100, Boris Brezillon wrote:
> On Thu, 12 Feb 2015 15:53:31 +0100
> Antoine Tenart <[email protected]> wrote:
>
> > Add a default chunk size of 512 in the pxa3xx nand driver.
> >
> > Signed-off-by: Antoine Tenart <[email protected]>
> > ---
> > 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 64628bff3fa5..8ed045195d31 100644
> > --- a/drivers/mtd/nand/pxa3xx_nand.c
> > +++ b/drivers/mtd/nand/pxa3xx_nand.c
> > @@ -1430,6 +1430,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 */
>
> Ditto => no explanation about why you do that.
Will do.
>
> > + info->chunk_size = 512;
> > +
> > ret = pxa3xx_nand_sensing(info);
> > if (ret) {
> > dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
>
>
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
--
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
On Thu, Feb 12, 2015 at 03:53:32PM +0100, Antoine Tenart wrote:
> The nand controller on Marvell Berlin SoC reuse the pxa3xx nand driver
> as it quite close. The process of sending commands can be compared to
> the one of the Marvell armada 370: read and write commands are done in
> chunks.
>
> But the Berlin nand controller has some other specificities which
> require some modifications of the pxa3xx nand driver:
> - there are no IRQ available so we need to poll the status register: we
> have to use our own cmdfunc Berlin function, and early on the probing
> function.
> - PAGEPROG are very different from the one used in the pxa3xx driver,
> so we're using a specific process for this one
> - the SEQIN command is equivalent to a READ0 command
>
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> drivers/mtd/nand/pxa3xx_nand.c | 228 ++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 202 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index 8ed045195d31..a74ce08ea95e 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -244,10 +249,11 @@ module_param(use_dma, bool, 0444);
> MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
>
> static struct pxa3xx_nand_timing timing[] = {
> - { 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, },
> + { 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, 200000, 120, 10, },
I thought I already made it clear that I'm not adding more to these
tables. Please rewrite this to use
onfi_async_timing_mode_to_sdr_timings() helpers
http://lists.infradead.org/pipermail/linux-mtd/2015-February/057726.html
> };
>
> static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +266,12 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
> { "512MiB 8-bit", 0xdc2c, 64, 2048, 8, 8, 4096, &timing[2] },
> { "512MiB 16-bit", 0xcc2c, 64, 2048, 16, 16, 4096, &timing[2] },
> { "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] },
> +{ },
> +};
> +
> +static struct pxa3xx_nand_flash berlin_builtin_flash_types[] = {
> +{ "4GiB 8-bit", 0xd7ec, 128, 8192, 8, 8, 4096, &timing[4] },
> +{ },
> };
>
> static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +332,18 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
> .oobfree = { }
> };
>
> +static struct nand_ecclayout ecc_layout_oob_128 = {
> + .eccbytes = 48,
> + .eccpos = {
> + 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 = { {.offset = 2, .length = 78} }
> +};
^^^ The indentation is all wrong in the above. Please use tabs.
> +
> /* Define a default flash type setting serve as flash detecting only */
> #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
>
> @@ -1452,19 +1621,24 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
> return -EINVAL;
> }
>
> - num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1;
> - for (i = 0; i < num; i++) {
> - if (i < pdata->num_flash)
> - f = pdata->flash + i;
> - else
> - f = &builtin_flash_types[i - pdata->num_flash + 1];
> + if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
> + flash_types = berlin_builtin_flash_types;
> + else
> + flash_types = builtin_flash_types;
>
> - /* find the chip in default list */
> + for (i = 0; i < pdata->num_flash; i++) {
> + f = pdata->flash + i;
> if (f->chip_id == id)
> break;
> }
>
> - if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
> + if (f == NULL) {
The style is typically just to do:
if (!f) {
> + for (i = 0; (f = &flash_types[i]); i++)
> + if (f->chip_id == id)
> + break;
> + }
> +
> + if (f == NULL) {
Same.
> dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>
> return -EINVAL;
> @@ -1516,9 +1690,11 @@ KEEP_CONFIG:
> * (aka splitted) command handling,
> */
> if (mtd->writesize > PAGE_CHUNK_SIZE) {
> - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
> + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
> chip->cmdfunc = nand_cmdfunc_extended;
> - } else {
> +
> + if (info->variant != PXA3XX_NAND_VARIANT_ARMADA370 &&
> + info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
Why did this 'else' have to get split into a separate conditional?
Couldn't you have just made it an else-if instead? e.g.:
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
...
} else if (info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
...
}
This could also be a switch/case.
> dev_err(&info->pdev->dev,
> "unsupported page size on this variant\n");
> return -ENODEV;
Brian
On Thu, Feb 12, 2015 at 03:53:27PM +0100, Antoine Tenart wrote:
> pxa3xx_flash_ids wasn't initialized to 0, which in certain cases could
> end up containing corrupted values in its members. Fix this to avoid
> possible issues.
>
> Signed-off-by: Antoine Tenart <[email protected]>
Applied this patch to l2-mtd.git. The others are TBD still. (Haven't
examined all of them too closely.)
Brian