All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] ARM: berlin: add nand support
@ 2015-01-27 14:10 ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

Hi all,

This series introduces the support for the Marvell Berlin nand
controller. It is based on top of v3.19-rc6 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 read and
  write operations.

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


Antoine Tenart (9):
  mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
  mtd: pxa3xx_nand: add a non mandatory ECC clock
  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        |   1 +
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts         |  10 +
 arch/arm/boot/dts/berlin2q.dtsi                    |  21 ++
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/nand/pxa3xx_nand.c                     | 321 ++++++++++++++++++---
 5 files changed, 320 insertions(+), 35 deletions(-)

-- 
2.2.2


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 0/9] ARM: berlin: add nand support
@ 2015-01-27 14:10 ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

Hi all,

This series introduces the support for the Marvell Berlin nand
controller. It is based on top of v3.19-rc6 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 read and
  write operations.

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


Antoine Tenart (9):
  mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
  mtd: pxa3xx_nand: add a non mandatory ECC clock
  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        |   1 +
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts         |  10 +
 arch/arm/boot/dts/berlin2q.dtsi                    |  21 ++
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/nand/pxa3xx_nand.c                     | 321 ++++++++++++++++++---
 5 files changed, 320 insertions(+), 35 deletions(-)

-- 
2.2.2

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 0/9] ARM: berlin: add nand support
@ 2015-01-27 14:10 ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

This series introduces the support for the Marvell Berlin nand
controller. It is based on top of v3.19-rc6 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 read and
  write operations.

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


Antoine Tenart (9):
  mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
  mtd: pxa3xx_nand: add a non mandatory ECC clock
  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        |   1 +
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts         |  10 +
 arch/arm/boot/dts/berlin2q.dtsi                    |  21 ++
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/nand/pxa3xx_nand.c                     | 321 ++++++++++++++++++---
 5 files changed, 320 insertions(+), 35 deletions(-)

-- 
2.2.2

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 1/9] mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

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 <antoine.tenart@free-electrons.com>
---
 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.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 1/9] mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 1/9] mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

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 <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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);
@@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct platform_device *pdev)
 	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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 fail_free_buf:
 	free_irq(irq, info);
 	kfree(info->data_buff);
+fail_disable_ecc_clk:
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 fail_disable_clk:
 	clk_disable_unprepare(info->clk);
 	return ret;
@@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 	pxa3xx_nand_free_buff(info);
 
 	clk_disable_unprepare(info->clk);
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 
 	for (cs = 0; cs < pdata->num_cs; cs++)
 		nand_release(info->host[cs]->mtd);
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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);
@@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct platform_device *pdev)
 	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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 fail_free_buf:
 	free_irq(irq, info);
 	kfree(info->data_buff);
+fail_disable_ecc_clk:
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 fail_disable_clk:
 	clk_disable_unprepare(info->clk);
 	return ret;
@@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 	pxa3xx_nand_free_buff(info);
 
 	clk_disable_unprepare(info->clk);
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 
 	for (cs = 0; cs < pdata->num_cs; cs++)
 		nand_release(info->host[cs]->mtd);
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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);
@@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct platform_device *pdev)
 	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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 fail_free_buf:
 	free_irq(irq, info);
 	kfree(info->data_buff);
+fail_disable_ecc_clk:
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 fail_disable_clk:
 	clk_disable_unprepare(info->clk);
 	return ret;
@@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 	pxa3xx_nand_free_buff(info);
 
 	clk_disable_unprepare(info->clk);
+	if (!IS_ERR(info->ecc_clk))
+		clk_disable_unprepare(info->ecc_clk);
 
 	for (cs = 0; cs < pdata->num_cs; cs++)
 		nand_release(info->host[cs]->mtd);
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 2681ec4abafa..782ae24d6b7d 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.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 2681ec4abafa..782ae24d6b7d 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 2681ec4abafa..782ae24d6b7d 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

Add a default chunk size of 512 in the pxa3xx nand driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 782ae24d6b7d..b2783b1f663c 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.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

Add a default chunk size of 512 in the pxa3xx nand driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 782ae24d6b7d..b2783b1f663c 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

Add a default chunk size of 512 in the pxa3xx nand driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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 782ae24d6b7d..b2783b1f663c 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

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
- the RNDOUT command must be used to perform a read operation, and the
  command is not NAND_CMD_RNDOUT
- the ERASE1 command is specific (0xd060)

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 261 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b2783b1f663c..62ea369dc524 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,20 @@
 #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	10
+#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
+#define EXT_CMD_TYPE_LAST_RNDOUT	8
+#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
+
+#define BERLIN_NAND_CMD_RNDOUT		0x3000
+#define BERLIN_NAND_CMD_ERASE1		0xd060
 
 /* macros for registers read/write */
 #define nand_writel(info, off, val)	\
@@ -158,6 +167,7 @@ enum {
 enum pxa3xx_nand_variant {
 	PXA3XX_NAND_VARIANT_PXA,
 	PXA3XX_NAND_VARIANT_ARMADA370,
+	PXA3XX_NAND_VARIANT_BERLIN2,
 };
 
 struct pxa3xx_nand_host {
@@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
+	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
+	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
 };
 
 static struct pxa3xx_nand_flash builtin_flash_types[] = {
@@ -260,6 +273,20 @@ 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[] = {
+{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
+{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
+{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
+{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
+{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
+{ },
 };
 
 static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
@@ -320,6 +347,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 +385,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);
@@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
 		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 
+	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
+		ndtr0 = 0x84840A12;
+		ndtr1 = 0x00208662;
+	}
+
 	info->ndtr0cs0 = ndtr0;
 	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
@@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 		nand_writel(info, NDCB0, info->ndcb1);
 		nand_writel(info, NDCB0, info->ndcb2);
 
+		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
+				info->ndcb0 & NDCB0_LEN_OVRD)
+			nand_writel(info, NDCB0,
+					info->chunk_size + info->oob_size);
+
 		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
 			nand_writel(info, NDCB0, info->ndcb3);
@@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
+			exec_cmd = 0;
+
+		if (command == NAND_CMD_SEQIN)
+			command = NAND_CMD_READ0;
+		else if (command == NAND_CMD_RNDOUT)
+			command = BERLIN_NAND_CMD_RNDOUT;
+		else if (command == NAND_CMD_ERASE1)
+			command = BERLIN_NAND_CMD_ERASE1;
+	}
+
 	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
 				    + host->col_addr_cycles);
 
@@ -814,6 +880,34 @@ 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
+						| 0xff
+						| (0x1080 & (0xff << 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
+						| (0x1080 & 0xff);
+			} else {
+				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+						| NDCB0_CMD_XTYPE(0x4)
+						| NDCB0_NC
+						| NDCB0_AUTO_RS
+						| NDCB0_LEN_OVRD
+						| addr_cycle
+						| (0x1080 & 0xff);
+			}
+
+			break;
+		}
+
 		/* Second command setting for large pages */
 		if (mtd->writesize > PAGE_CHUNK_SIZE) {
 			/*
@@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 
 		info->data_size = 8;
 		break;
+
+	case BERLIN_NAND_CMD_RNDOUT:
+		info->buf_start = column;
+
+		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD;
+		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD
+					| NDCB0_NC;
+		else
+			info->ndcb0 |= NDCB0_CMD_TYPE(0)
+					| NDCB0_CMD_XTYPE(0x6)
+					| NDCB0_DBC
+					| NDCB0_NC
+					| addr_cycle
+					| command;
+
+		break;
+
 	case NAND_CMD_STATUS:
 		info->buf_count = 1;
 		info->ndcb0 |= NDCB0_CMD_TYPE(4)
@@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 		break;
 
 	case NAND_CMD_ERASE1:
+	case BERLIN_NAND_CMD_ERASE1:
 		info->ndcb0 |= NDCB0_CMD_TYPE(2)
 				| NDCB0_AUTO_RS
 				| NDCB0_ADDR_CYC(3)
 				| NDCB0_DBC
-				| (NAND_CMD_ERASE2 << 8)
-				| NAND_CMD_ERASE1;
+				| command;
 		info->ndcb1 = page_addr;
 		info->ndcb2 = 0;
 
+		if (command == NAND_CMD_ERASE1)
+			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
+
 		break;
 	case NAND_CMD_RESET:
 		info->ndcb0 |= NDCB0_CMD_TYPE(5)
@@ -1078,6 +1196,102 @@ 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;
+	unsigned int oob_size = info->oob_size;
+	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) {
+			cmd = NAND_CMD_RNDOUT;
+			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_RNDOUT) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
+				info->oob_size = oob_size;
+			} else {
+				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
+			}
+		}
+
+		if (cmd == NAND_CMD_PAGEPROG) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
+				info->oob_size = oob_size;
+			} 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 +1407,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 +1617,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 +1646,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 +1659,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 +1681,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; (f = &flash_types[i]); i++)
 		if (f->chip_id == id)
 			break;
+
+	if (f == NULL) {
+		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) {
 		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
 
 		return -EINVAL;
@@ -1515,7 +1749,8 @@ KEEP_CONFIG:
 	 * we are given the right variant and then switch to the extended
 	 * (aka splitted) command handling,
 	 */
-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
+	if (mtd->writesize > PAGE_CHUNK_SIZE &&
+			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
 			chip->cmdfunc = nand_cmdfunc_extended;
 		} else {
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

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
- the RNDOUT command must be used to perform a read operation, and the
  command is not NAND_CMD_RNDOUT
- the ERASE1 command is specific (0xd060)

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 261 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b2783b1f663c..62ea369dc524 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,20 @@
 #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	10
+#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
+#define EXT_CMD_TYPE_LAST_RNDOUT	8
+#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
+
+#define BERLIN_NAND_CMD_RNDOUT		0x3000
+#define BERLIN_NAND_CMD_ERASE1		0xd060
 
 /* macros for registers read/write */
 #define nand_writel(info, off, val)	\
@@ -158,6 +167,7 @@ enum {
 enum pxa3xx_nand_variant {
 	PXA3XX_NAND_VARIANT_PXA,
 	PXA3XX_NAND_VARIANT_ARMADA370,
+	PXA3XX_NAND_VARIANT_BERLIN2,
 };
 
 struct pxa3xx_nand_host {
@@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
+	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
+	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
 };
 
 static struct pxa3xx_nand_flash builtin_flash_types[] = {
@@ -260,6 +273,20 @@ 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[] = {
+{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
+{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
+{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
+{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
+{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
+{ },
 };
 
 static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
@@ -320,6 +347,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 +385,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);
@@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
 		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 
+	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
+		ndtr0 = 0x84840A12;
+		ndtr1 = 0x00208662;
+	}
+
 	info->ndtr0cs0 = ndtr0;
 	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
@@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 		nand_writel(info, NDCB0, info->ndcb1);
 		nand_writel(info, NDCB0, info->ndcb2);
 
+		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
+				info->ndcb0 & NDCB0_LEN_OVRD)
+			nand_writel(info, NDCB0,
+					info->chunk_size + info->oob_size);
+
 		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
 			nand_writel(info, NDCB0, info->ndcb3);
@@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
+			exec_cmd = 0;
+
+		if (command == NAND_CMD_SEQIN)
+			command = NAND_CMD_READ0;
+		else if (command == NAND_CMD_RNDOUT)
+			command = BERLIN_NAND_CMD_RNDOUT;
+		else if (command == NAND_CMD_ERASE1)
+			command = BERLIN_NAND_CMD_ERASE1;
+	}
+
 	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
 				    + host->col_addr_cycles);
 
@@ -814,6 +880,34 @@ 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
+						| 0xff
+						| (0x1080 & (0xff << 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
+						| (0x1080 & 0xff);
+			} else {
+				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+						| NDCB0_CMD_XTYPE(0x4)
+						| NDCB0_NC
+						| NDCB0_AUTO_RS
+						| NDCB0_LEN_OVRD
+						| addr_cycle
+						| (0x1080 & 0xff);
+			}
+
+			break;
+		}
+
 		/* Second command setting for large pages */
 		if (mtd->writesize > PAGE_CHUNK_SIZE) {
 			/*
@@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 
 		info->data_size = 8;
 		break;
+
+	case BERLIN_NAND_CMD_RNDOUT:
+		info->buf_start = column;
+
+		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD;
+		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD
+					| NDCB0_NC;
+		else
+			info->ndcb0 |= NDCB0_CMD_TYPE(0)
+					| NDCB0_CMD_XTYPE(0x6)
+					| NDCB0_DBC
+					| NDCB0_NC
+					| addr_cycle
+					| command;
+
+		break;
+
 	case NAND_CMD_STATUS:
 		info->buf_count = 1;
 		info->ndcb0 |= NDCB0_CMD_TYPE(4)
@@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 		break;
 
 	case NAND_CMD_ERASE1:
+	case BERLIN_NAND_CMD_ERASE1:
 		info->ndcb0 |= NDCB0_CMD_TYPE(2)
 				| NDCB0_AUTO_RS
 				| NDCB0_ADDR_CYC(3)
 				| NDCB0_DBC
-				| (NAND_CMD_ERASE2 << 8)
-				| NAND_CMD_ERASE1;
+				| command;
 		info->ndcb1 = page_addr;
 		info->ndcb2 = 0;
 
+		if (command == NAND_CMD_ERASE1)
+			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
+
 		break;
 	case NAND_CMD_RESET:
 		info->ndcb0 |= NDCB0_CMD_TYPE(5)
@@ -1078,6 +1196,102 @@ 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;
+	unsigned int oob_size = info->oob_size;
+	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) {
+			cmd = NAND_CMD_RNDOUT;
+			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_RNDOUT) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
+				info->oob_size = oob_size;
+			} else {
+				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
+			}
+		}
+
+		if (cmd == NAND_CMD_PAGEPROG) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
+				info->oob_size = oob_size;
+			} 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 +1407,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 +1617,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 +1646,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 +1659,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 +1681,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; (f = &flash_types[i]); i++)
 		if (f->chip_id == id)
 			break;
+
+	if (f == NULL) {
+		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) {
 		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
 
 		return -EINVAL;
@@ -1515,7 +1749,8 @@ KEEP_CONFIG:
 	 * we are given the right variant and then switch to the extended
 	 * (aka splitted) command handling,
 	 */
-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
+	if (mtd->writesize > PAGE_CHUNK_SIZE &&
+			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
 			chip->cmdfunc = nand_cmdfunc_extended;
 		} else {
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

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
- the RNDOUT command must be used to perform a read operation, and the
  command is not NAND_CMD_RNDOUT
- the ERASE1 command is specific (0xd060)

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 261 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b2783b1f663c..62ea369dc524 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,20 @@
 #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	10
+#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
+#define EXT_CMD_TYPE_LAST_RNDOUT	8
+#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
+
+#define BERLIN_NAND_CMD_RNDOUT		0x3000
+#define BERLIN_NAND_CMD_ERASE1		0xd060
 
 /* macros for registers read/write */
 #define nand_writel(info, off, val)	\
@@ -158,6 +167,7 @@ enum {
 enum pxa3xx_nand_variant {
 	PXA3XX_NAND_VARIANT_PXA,
 	PXA3XX_NAND_VARIANT_ARMADA370,
+	PXA3XX_NAND_VARIANT_BERLIN2,
 };
 
 struct pxa3xx_nand_host {
@@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
+	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
+	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
 };
 
 static struct pxa3xx_nand_flash builtin_flash_types[] = {
@@ -260,6 +273,20 @@ 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[] = {
+{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
+{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
+{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
+{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
+{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
+{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
+{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
+{ },
 };
 
 static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
@@ -320,6 +347,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 +385,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);
@@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
 		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 
+	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
+		ndtr0 = 0x84840A12;
+		ndtr1 = 0x00208662;
+	}
+
 	info->ndtr0cs0 = ndtr0;
 	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
@@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 		nand_writel(info, NDCB0, info->ndcb1);
 		nand_writel(info, NDCB0, info->ndcb2);
 
+		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
+				info->ndcb0 & NDCB0_LEN_OVRD)
+			nand_writel(info, NDCB0,
+					info->chunk_size + info->oob_size);
+
 		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
 			nand_writel(info, NDCB0, info->ndcb3);
@@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
+			exec_cmd = 0;
+
+		if (command == NAND_CMD_SEQIN)
+			command = NAND_CMD_READ0;
+		else if (command == NAND_CMD_RNDOUT)
+			command = BERLIN_NAND_CMD_RNDOUT;
+		else if (command == NAND_CMD_ERASE1)
+			command = BERLIN_NAND_CMD_ERASE1;
+	}
+
 	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
 				    + host->col_addr_cycles);
 
@@ -814,6 +880,34 @@ 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
+						| 0xff
+						| (0x1080 & (0xff << 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
+						| (0x1080 & 0xff);
+			} else {
+				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+						| NDCB0_CMD_XTYPE(0x4)
+						| NDCB0_NC
+						| NDCB0_AUTO_RS
+						| NDCB0_LEN_OVRD
+						| addr_cycle
+						| (0x1080 & 0xff);
+			}
+
+			break;
+		}
+
 		/* Second command setting for large pages */
 		if (mtd->writesize > PAGE_CHUNK_SIZE) {
 			/*
@@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 
 		info->data_size = 8;
 		break;
+
+	case BERLIN_NAND_CMD_RNDOUT:
+		info->buf_start = column;
+
+		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD;
+		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
+			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
+					| NDCB0_LEN_OVRD
+					| NDCB0_NC;
+		else
+			info->ndcb0 |= NDCB0_CMD_TYPE(0)
+					| NDCB0_CMD_XTYPE(0x6)
+					| NDCB0_DBC
+					| NDCB0_NC
+					| addr_cycle
+					| command;
+
+		break;
+
 	case NAND_CMD_STATUS:
 		info->buf_count = 1;
 		info->ndcb0 |= NDCB0_CMD_TYPE(4)
@@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
 		break;
 
 	case NAND_CMD_ERASE1:
+	case BERLIN_NAND_CMD_ERASE1:
 		info->ndcb0 |= NDCB0_CMD_TYPE(2)
 				| NDCB0_AUTO_RS
 				| NDCB0_ADDR_CYC(3)
 				| NDCB0_DBC
-				| (NAND_CMD_ERASE2 << 8)
-				| NAND_CMD_ERASE1;
+				| command;
 		info->ndcb1 = page_addr;
 		info->ndcb2 = 0;
 
+		if (command == NAND_CMD_ERASE1)
+			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
+
 		break;
 	case NAND_CMD_RESET:
 		info->ndcb0 |= NDCB0_CMD_TYPE(5)
@@ -1078,6 +1196,102 @@ 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;
+	unsigned int oob_size = info->oob_size;
+	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) {
+			cmd = NAND_CMD_RNDOUT;
+			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_RNDOUT) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
+				info->oob_size = oob_size;
+			} else {
+				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
+			}
+		}
+
+		if (cmd == NAND_CMD_PAGEPROG) {
+			/* last command */
+			if (info->data_size == info->chunk_size * 2) {
+				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
+				info->oob_size = oob_size;
+			} 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 +1407,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 +1617,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 +1646,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 +1659,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 +1681,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; (f = &flash_types[i]); i++)
 		if (f->chip_id == id)
 			break;
+
+	if (f == NULL) {
+		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) {
 		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
 
 		return -EINVAL;
@@ -1515,7 +1749,8 @@ KEEP_CONFIG:
 	 * we are given the right variant and then switch to the extended
 	 * (aka splitted) command handling,
 	 */
-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
+	if (mtd->writesize > PAGE_CHUNK_SIZE &&
+			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
 			chip->cmdfunc = nand_cmdfunc_extended;
 		} else {
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 6/9] Documentation: bindings: add the Berlin nand controller compatible
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

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 <antoine.tenart@free-electrons.com>
---
 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 de8b517a5521..c76281c1f442 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.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 6/9] Documentation: bindings: add the Berlin nand controller compatible
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 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 de8b517a5521..c76281c1f442 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 6/9] Documentation: bindings: add the Berlin nand controller compatible
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 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 de8b517a5521..c76281c1f442 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 7/9] mtd: nand: let Marvell Berlin SoCs select the pxa3xx driver
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

Marvell Berlin nand controller support has been added in the pxa3xx nand
driver. Let these SoCs select the driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 7/9] mtd: nand: let Marvell Berlin SoCs select the pxa3xx driver
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

Marvell Berlin nand controller support has been added in the pxa3xx nand
driver. Let these SoCs select the driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 7/9] mtd: nand: let Marvell Berlin SoCs select the pxa3xx driver
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

Marvell Berlin nand controller support has been added in the pxa3xx nand
driver. Let these SoCs select the driver.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 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.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 8/9] ARM: berlin: add BG2Q node for the nand
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

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 <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index e2f61f27944e..f1bc614f0281 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -359,6 +359,11 @@
 			clocks = <&refclk>;
 			clock-names = "refclk";
 
+			nand_pmux: nand-pmux {
+				groups = "G0", "G1";
+				function = "nand";
+			};
+
 			twsi0_pmux: twsi0-pmux {
 				groups = "G6";
 				function = "twsi0";
@@ -429,6 +434,22 @@
 			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";
+
+			pinctrl-0 = <&nand_pmux>;
+			pinctrl-names = "default";
+
+			#address-cells = <1>;
+
+			status = "disabled";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 8/9] ARM: berlin: add BG2Q node for the nand
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index e2f61f27944e..f1bc614f0281 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -359,6 +359,11 @@
 			clocks = <&refclk>;
 			clock-names = "refclk";
 
+			nand_pmux: nand-pmux {
+				groups = "G0", "G1";
+				function = "nand";
+			};
+
 			twsi0_pmux: twsi0-pmux {
 				groups = "G6";
 				function = "twsi0";
@@ -429,6 +434,22 @@
 			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";
+
+			pinctrl-0 = <&nand_pmux>;
+			pinctrl-names = "default";
+
+			#address-cells = <1>;
+
+			status = "disabled";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 8/9] ARM: berlin: add BG2Q node for the nand
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

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 <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index e2f61f27944e..f1bc614f0281 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -359,6 +359,11 @@
 			clocks = <&refclk>;
 			clock-names = "refclk";
 
+			nand_pmux: nand-pmux {
+				groups = "G0", "G1";
+				function = "nand";
+			};
+
 			twsi0_pmux: twsi0-pmux {
 				groups = "G6";
 				function = "twsi0";
@@ -429,6 +434,22 @@
 			status = "disabled";
 		};
 
+		nand0: nand at 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";
+
+			pinctrl-0 = <&nand_pmux>;
+			pinctrl-names = "default";
+
+			#address-cells = <1>;
+
+			status = "disabled";
+		};
+
 		apb at fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 9/9] ARM: berlin: enable flash on the BG2Q DMP
  2015-01-27 14:10 ` Antoine Tenart
  (?)
@ 2015-01-27 14:10   ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, jszhang,
	linux-arm-kernel, linux-mtd, linux-kernel

The BG2Q DMP has a nand controller. Enable it with the correct
configuration.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index a98ac1bd8f65..0bfdff5ca86f 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -112,3 +112,13 @@
 &sata_phy {
 	status = "okay";
 };
+
+&nand0 {
+	marvell,nand-enable-arbiter;
+	nand-ecc-strength = <48>;
+	nand-ecc-step-size = <1024>;
+
+	num-cs = <1>;
+
+	status = "okay";
+};
-- 
2.2.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 9/9] ARM: berlin: enable flash on the BG2Q DMP
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, linux-arm-kernel

The BG2Q DMP has a nand controller. Enable it with the correct
configuration.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index a98ac1bd8f65..0bfdff5ca86f 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -112,3 +112,13 @@
 &sata_phy {
 	status = "okay";
 };
+
+&nand0 {
+	marvell,nand-enable-arbiter;
+	nand-ecc-strength = <48>;
+	nand-ecc-step-size = <1024>;
+
+	num-cs = <1>;
+
+	status = "okay";
+};
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 9/9] ARM: berlin: enable flash on the BG2Q DMP
@ 2015-01-27 14:10   ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-27 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

The BG2Q DMP has a nand controller. Enable it with the correct
configuration.

Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index a98ac1bd8f65..0bfdff5ca86f 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -112,3 +112,13 @@
 &sata_phy {
 	status = "okay";
 };
+
+&nand0 {
+	marvell,nand-enable-arbiter;
+	nand-ecc-strength = <48>;
+	nand-ecc-step-size = <1024>;
+
+	num-cs = <1>;
+
+	status = "okay";
+};
-- 
2.2.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-01-27 14:42     ` Ezequiel Garcia
  -1 siblings, 0 replies; 84+ messages in thread
From: Ezequiel Garcia @ 2015-01-27 14:42 UTC (permalink / raw)
  To: Antoine Tenart, sebastian.hesselbarth, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, jszhang, linux-arm-kernel, linux-mtd,
	linux-kernel

On 01/27/2015 11:10 AM, 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  

IMO, this sucks. I was hoping to see this old style probing go away,
instead of be augmented.

There are proper ways to set timings.
-- 
Ezequiel García, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-01-27 14:42     ` Ezequiel Garcia
  0 siblings, 0 replies; 84+ messages in thread
From: Ezequiel Garcia @ 2015-01-27 14:42 UTC (permalink / raw)
  To: Antoine Tenart, sebastian.hesselbarth, dwmw2, computersforpeace
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

On 01/27/2015 11:10 AM, 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  

IMO, this sucks. I was hoping to see this old style probing go away,
instead of be augmented.

There are proper ways to set timings.
-- 
Ezequiel García, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-01-27 14:42     ` Ezequiel Garcia
  0 siblings, 0 replies; 84+ messages in thread
From: Ezequiel Garcia @ 2015-01-27 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/27/2015 11:10 AM, 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  

IMO, this sucks. I was hoping to see this old style probing go away,
instead of be augmented.

There are proper ways to set timings.
-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-01-27 15:50     ` Andrew Lunn
  -1 siblings, 0 replies; 84+ messages in thread
From: Andrew Lunn @ 2015-01-27 15:50 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> 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.

Hi Antoine

It would be good to document this clock in the device tree binding.

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");

Does this keep backwards compatibility? Not all the existing users
have there clocks named. What i think happens here is that
of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
name); That returns -EINVAL, and then we ask of_clk_get() to get the
-EINVAL'th clock. I don't think that is going to end well.

I think you need to keep the NULL here, but should use "ecc" for the
second clock and require the use of the clock-names property when an
ecc clock is required.

    Andrew

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-27 15:50     ` Andrew Lunn
  0 siblings, 0 replies; 84+ messages in thread
From: Andrew Lunn @ 2015-01-27 15:50 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, ezequiel.garcia,
	jszhang, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> 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.

Hi Antoine

It would be good to document this clock in the device tree binding.

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");

Does this keep backwards compatibility? Not all the existing users
have there clocks named. What i think happens here is that
of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
name); That returns -EINVAL, and then we ask of_clk_get() to get the
-EINVAL'th clock. I don't think that is going to end well.

I think you need to keep the NULL here, but should use "ecc" for the
second clock and require the use of the clock-names property when an
ecc clock is required.

    Andrew

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-27 15:50     ` Andrew Lunn
  0 siblings, 0 replies; 84+ messages in thread
From: Andrew Lunn @ 2015-01-27 15:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> 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.

Hi Antoine

It would be good to document this clock in the device tree binding.

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");

Does this keep backwards compatibility? Not all the existing users
have there clocks named. What i think happens here is that
of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
name); That returns -EINVAL, and then we ask of_clk_get() to get the
-EINVAL'th clock. I don't think that is going to end well.

I think you need to keep the NULL here, but should use "ecc" for the
second clock and require the use of the clock-names property when an
ecc clock is required.

    Andrew

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-01-28  3:35     ` Jisheng Zhang
  -1 siblings, 0 replies; 84+ messages in thread
From: Jisheng Zhang @ 2015-01-28  3:35 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, Jimmy Xu, linux-arm-kernel, linux-mtd,
	linux-kernel

Dear Antoine,

On Tue, 27 Jan 2015 06:10:09 -0800
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> 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 <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {

Do we need to fall back to unnamed clock here? Otherwise I guess it will break
other platforms.

>  		dev_err(&pdev->dev, "failed to get nand clock\n");
>  		return PTR_ERR(info->clk);
> @@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct
> platform_device *pdev) 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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> *pdev) fail_free_buf:
>  	free_irq(irq, info);
>  	kfree(info->data_buff);
> +fail_disable_ecc_clk:
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check to simplify this error path since commit
63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")

>  fail_disable_clk:
>  	clk_disable_unprepare(info->clk);
>  	return ret;
> @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> *pdev) pxa3xx_nand_free_buff(info);
>  
>  	clk_disable_unprepare(info->clk);
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check too.

>  
>  	for (cs = 0; cs < pdata->num_cs; cs++)
>  		nand_release(info->host[cs]->mtd);


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28  3:35     ` Jisheng Zhang
  0 siblings, 0 replies; 84+ messages in thread
From: Jisheng Zhang @ 2015-01-28  3:35 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, Jimmy Xu, linux-kernel, linux-mtd,
	ezequiel.garcia, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

Dear Antoine,

On Tue, 27 Jan 2015 06:10:09 -0800
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> 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 <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {

Do we need to fall back to unnamed clock here? Otherwise I guess it will break
other platforms.

>  		dev_err(&pdev->dev, "failed to get nand clock\n");
>  		return PTR_ERR(info->clk);
> @@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct
> platform_device *pdev) 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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> *pdev) fail_free_buf:
>  	free_irq(irq, info);
>  	kfree(info->data_buff);
> +fail_disable_ecc_clk:
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check to simplify this error path since commit
63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")

>  fail_disable_clk:
>  	clk_disable_unprepare(info->clk);
>  	return ret;
> @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> *pdev) pxa3xx_nand_free_buff(info);
>  
>  	clk_disable_unprepare(info->clk);
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check too.

>  
>  	for (cs = 0; cs < pdata->num_cs; cs++)
>  		nand_release(info->host[cs]->mtd);

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28  3:35     ` Jisheng Zhang
  0 siblings, 0 replies; 84+ messages in thread
From: Jisheng Zhang @ 2015-01-28  3:35 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Antoine,

On Tue, 27 Jan 2015 06:10:09 -0800
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> 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 <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {

Do we need to fall back to unnamed clock here? Otherwise I guess it will break
other platforms.

>  		dev_err(&pdev->dev, "failed to get nand clock\n");
>  		return PTR_ERR(info->clk);
> @@ -1617,6 +1617,13 @@ static int alloc_nand_resource(struct
> platform_device *pdev) 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 +1640,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 +1649,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 +1659,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 +1675,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 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> *pdev) fail_free_buf:
>  	free_irq(irq, info);
>  	kfree(info->data_buff);
> +fail_disable_ecc_clk:
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check to simplify this error path since commit
63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")

>  fail_disable_clk:
>  	clk_disable_unprepare(info->clk);
>  	return ret;
> @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> *pdev) pxa3xx_nand_free_buff(info);
>  
>  	clk_disable_unprepare(info->clk);
> +	if (!IS_ERR(info->ecc_clk))
> +		clk_disable_unprepare(info->ecc_clk);

we can remove the IS_ERR check too.

>  
>  	for (cs = 0; cs < pdata->num_cs; cs++)
>  		nand_release(info->host[cs]->mtd);

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-27 15:50     ` Andrew Lunn
  (?)
@ 2015-01-28 14:14       ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:14 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Antoine Tenart, sebastian.hesselbarth, ezequiel.garcia, dwmw2,
	computersforpeace, thomas.petazzoni, zmxu, linux-kernel,
	linux-mtd, jszhang, linux-arm-kernel

Hi Andrew,

On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > 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.
> 
> It would be good to document this clock in the device tree binding.

Yes! I'll add the ECC clock into the documentation.

> 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> >  1 file changed, 19 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> 
> Does this keep backwards compatibility? Not all the existing users
> have there clocks named. What i think happens here is that
> of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> name); That returns -EINVAL, and then we ask of_clk_get() to get the
> -EINVAL'th clock. I don't think that is going to end well.
> 
> I think you need to keep the NULL here, but should use "ecc" for the
> second clock and require the use of the clock-names property when an
> ecc clock is required.

I agree, I'll go back to NULL in v2.

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28 14:14       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:14 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Hi Andrew,

On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > 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.
> 
> It would be good to document this clock in the device tree binding.

Yes! I'll add the ECC clock into the documentation.

> 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> >  1 file changed, 19 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> 
> Does this keep backwards compatibility? Not all the existing users
> have there clocks named. What i think happens here is that
> of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> name); That returns -EINVAL, and then we ask of_clk_get() to get the
> -EINVAL'th clock. I don't think that is going to end well.
> 
> I think you need to keep the NULL here, but should use "ecc" for the
> second clock and require the use of the clock-names property when an
> ecc clock is required.

I agree, I'll go back to NULL in v2.

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28 14:14       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andrew,

On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > 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.
> 
> It would be good to document this clock in the device tree binding.

Yes! I'll add the ECC clock into the documentation.

> 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> >  1 file changed, 19 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> 
> Does this keep backwards compatibility? Not all the existing users
> have there clocks named. What i think happens here is that
> of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> name); That returns -EINVAL, and then we ask of_clk_get() to get the
> -EINVAL'th clock. I don't think that is going to end well.
> 
> I think you need to keep the NULL here, but should use "ecc" for the
> second clock and require the use of the clock-names property when an
> ecc clock is required.

I agree, I'll go back to NULL in v2.

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-28  3:35     ` Jisheng Zhang
  (?)
@ 2015-01-28 14:17       ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:17 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Antoine Tenart, sebastian.hesselbarth, ezequiel.garcia, dwmw2,
	computersforpeace, thomas.petazzoni, Jimmy Xu, linux-arm-kernel,
	linux-mtd, linux-kernel

Hi Jisheng!

On Wed, Jan 28, 2015 at 11:35:52AM +0800, Jisheng Zhang wrote:
> On Tue, 27 Jan 2015 06:10:09 -0800
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {
> 
> Do we need to fall back to unnamed clock here? Otherwise I guess it will break
> other platforms.

Yes, as Andrew pointed out we need to keep the NULL here to avoid
breaking other platforms.

> >  
> >  	/* initialize all interrupts to be disabled */
> > @@ -1687,6 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> > *pdev) fail_free_buf:
> >  	free_irq(irq, info);
> >  	kfree(info->data_buff);
> > +fail_disable_ecc_clk:
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check to simplify this error path since commit
> 63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")
> 
> >  fail_disable_clk:
> >  	clk_disable_unprepare(info->clk);
> >  	return ret;
> > @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> > *pdev) pxa3xx_nand_free_buff(info);
> >  
> >  	clk_disable_unprepare(info->clk);
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check too.

Yes! Thanks for the hint, I'll remove these useless checks in v2.

Thanks!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28 14:17       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:17 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: thomas.petazzoni, Jimmy Xu, Antoine Tenart, linux-kernel,
	linux-mtd, ezequiel.garcia, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Hi Jisheng!

On Wed, Jan 28, 2015 at 11:35:52AM +0800, Jisheng Zhang wrote:
> On Tue, 27 Jan 2015 06:10:09 -0800
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {
> 
> Do we need to fall back to unnamed clock here? Otherwise I guess it will break
> other platforms.

Yes, as Andrew pointed out we need to keep the NULL here to avoid
breaking other platforms.

> >  
> >  	/* initialize all interrupts to be disabled */
> > @@ -1687,6 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> > *pdev) fail_free_buf:
> >  	free_irq(irq, info);
> >  	kfree(info->data_buff);
> > +fail_disable_ecc_clk:
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check to simplify this error path since commit
> 63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")
> 
> >  fail_disable_clk:
> >  	clk_disable_unprepare(info->clk);
> >  	return ret;
> > @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> > *pdev) pxa3xx_nand_free_buff(info);
> >  
> >  	clk_disable_unprepare(info->clk);
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check too.

Yes! Thanks for the hint, I'll remove these useless checks in v2.

Thanks!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-01-28 14:17       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-01-28 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jisheng!

On Wed, Jan 28, 2015 at 11:35:52AM +0800, Jisheng Zhang wrote:
> On Tue, 27 Jan 2015 06:10:09 -0800
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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)) {
> 
> Do we need to fall back to unnamed clock here? Otherwise I guess it will break
> other platforms.

Yes, as Andrew pointed out we need to keep the NULL here to avoid
breaking other platforms.

> >  
> >  	/* initialize all interrupts to be disabled */
> > @@ -1687,6 +1694,9 @@ static int alloc_nand_resource(struct platform_device
> > *pdev) fail_free_buf:
> >  	free_irq(irq, info);
> >  	kfree(info->data_buff);
> > +fail_disable_ecc_clk:
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check to simplify this error path since commit
> 63589e92c2d9("clk: Ignore error and NULL pointers passed to clk_{unprepare, disable}()")
> 
> >  fail_disable_clk:
> >  	clk_disable_unprepare(info->clk);
> >  	return ret;
> > @@ -1709,6 +1719,8 @@ static int pxa3xx_nand_remove(struct platform_device
> > *pdev) pxa3xx_nand_free_buff(info);
> >  
> >  	clk_disable_unprepare(info->clk);
> > +	if (!IS_ERR(info->ecc_clk))
> > +		clk_disable_unprepare(info->ecc_clk);
> 
> we can remove the IS_ERR check too.

Yes! Thanks for the hint, I'll remove these useless checks in v2.

Thanks!

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-01-27 14:42     ` Ezequiel Garcia
  (?)
@ 2015-02-06  1:25       ` Brian Norris
  -1 siblings, 0 replies; 84+ messages in thread
From: Brian Norris @ 2015-02-06  1:25 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: Antoine Tenart, sebastian.hesselbarth, dwmw2, thomas.petazzoni,
	zmxu, jszhang, linux-arm-kernel, linux-mtd, linux-kernel

On Tue, Jan 27, 2015 at 11:42:08AM -0300, Ezequiel Garcia wrote:
> On 01/27/2015 11:10 AM, Antoine Tenart wrote:
> > --- a/drivers/mtd/nand/pxa3xx_nand.c
> > +++ b/drivers/mtd/nand/pxa3xx_nand.c
...
> > @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> >  
> 
> IMO, this sucks. I was hoping to see this old style probing go away,
> instead of be augmented.
> 
> There are proper ways to set timings.

Agreed. I'm not taking any additions to this table. Please rewrite the
code to use the onfi_async_timing_mode_to_sdr_timings() helpers.

Brian

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-06  1:25       ` Brian Norris
  0 siblings, 0 replies; 84+ messages in thread
From: Brian Norris @ 2015-02-06  1:25 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	jszhang, dwmw2, linux-arm-kernel, sebastian.hesselbarth

On Tue, Jan 27, 2015 at 11:42:08AM -0300, Ezequiel Garcia wrote:
> On 01/27/2015 11:10 AM, Antoine Tenart wrote:
> > --- a/drivers/mtd/nand/pxa3xx_nand.c
> > +++ b/drivers/mtd/nand/pxa3xx_nand.c
...
> > @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> >  
> 
> IMO, this sucks. I was hoping to see this old style probing go away,
> instead of be augmented.
> 
> There are proper ways to set timings.

Agreed. I'm not taking any additions to this table. Please rewrite the
code to use the onfi_async_timing_mode_to_sdr_timings() helpers.

Brian

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-06  1:25       ` Brian Norris
  0 siblings, 0 replies; 84+ messages in thread
From: Brian Norris @ 2015-02-06  1:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 27, 2015 at 11:42:08AM -0300, Ezequiel Garcia wrote:
> On 01/27/2015 11:10 AM, Antoine Tenart wrote:
> > --- a/drivers/mtd/nand/pxa3xx_nand.c
> > +++ b/drivers/mtd/nand/pxa3xx_nand.c
...
> > @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> >  
> 
> IMO, this sucks. I was hoping to see this old style probing go away,
> instead of be augmented.
> 
> There are proper ways to set timings.

Agreed. I'm not taking any additions to this table. Please rewrite the
code to use the onfi_async_timing_mode_to_sdr_timings() helpers.

Brian

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
  2015-01-28 14:14       ` Antoine Tenart
  (?)
@ 2015-02-08 19:55         ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 19:55 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: Andrew Lunn, thomas.petazzoni, zmxu, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Hi Antoine,

On Wed, 28 Jan 2015 15:14:51 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Hi Andrew,
> 
> On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> > On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > > 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.
> > 
> > It would be good to document this clock in the device tree binding.
> 
> Yes! I'll add the ECC clock into the documentation.
> 
> > 
> > > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > > ---
> > >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> > >  1 file changed, 19 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> > 
> > Does this keep backwards compatibility? Not all the existing users
> > have there clocks named. What i think happens here is that
> > of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> > name); That returns -EINVAL, and then we ask of_clk_get() to get the
> > -EINVAL'th clock. I don't think that is going to end well.
> > 
> > I think you need to keep the NULL here, but should use "ecc" for the
> > second clock and require the use of the clock-names property when an
> > ecc clock is required.
> 
> I agree, I'll go back to NULL in v2.

I'd rather try with "nfc", and if it fails try with NULL as the name
argument, because passing NULL in all cases will enforce the clock
declaration order (which is not something we usually do when naming
clocks).
If you keep the NULL name, please document the clock order in your DT
documentation.

Best Regards,

Boris

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-02-08 19:55         ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 19:55 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, Andrew Lunn, linux-kernel, zmxu, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Hi Antoine,

On Wed, 28 Jan 2015 15:14:51 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Hi Andrew,
> 
> On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> > On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > > 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.
> > 
> > It would be good to document this clock in the device tree binding.
> 
> Yes! I'll add the ECC clock into the documentation.
> 
> > 
> > > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > > ---
> > >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> > >  1 file changed, 19 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> > 
> > Does this keep backwards compatibility? Not all the existing users
> > have there clocks named. What i think happens here is that
> > of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> > name); That returns -EINVAL, and then we ask of_clk_get() to get the
> > -EINVAL'th clock. I don't think that is going to end well.
> > 
> > I think you need to keep the NULL here, but should use "ecc" for the
> > second clock and require the use of the clock-names property when an
> > ecc clock is required.
> 
> I agree, I'll go back to NULL in v2.

I'd rather try with "nfc", and if it fails try with NULL as the name
argument, because passing NULL in all cases will enforce the clock
declaration order (which is not something we usually do when naming
clocks).
If you keep the NULL name, please document the clock order in your DT
documentation.

Best Regards,

Boris

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock
@ 2015-02-08 19:55         ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 19:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Antoine,

On Wed, 28 Jan 2015 15:14:51 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Hi Andrew,
> 
> On Tue, Jan 27, 2015 at 04:50:47PM +0100, Andrew Lunn wrote:
> > On Tue, Jan 27, 2015 at 03:10:09PM +0100, Antoine Tenart wrote:
> > > 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.
> > 
> > It would be good to document this clock in the device tree binding.
> 
> Yes! I'll add the ECC clock into the documentation.
> 
> > 
> > > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > > ---
> > >  drivers/mtd/nand/pxa3xx_nand.c | 26 +++++++++++++++++++-------
> > >  1 file changed, 19 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> > > index d00ac392d1c4..2681ec4abafa 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,7 +1608,7 @@ 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");
> > 
> > Does this keep backwards compatibility? Not all the existing users
> > have there clocks named. What i think happens here is that
> > of_clk_get_by_name() calls of_property_match_string(np, "clock-names",
> > name); That returns -EINVAL, and then we ask of_clk_get() to get the
> > -EINVAL'th clock. I don't think that is going to end well.
> > 
> > I think you need to keep the NULL here, but should use "ecc" for the
> > second clock and require the use of the clock-names property when an
> > ecc clock is required.
> 
> I agree, I'll go back to NULL in v2.

I'd rather try with "nfc", and if it fails try with NULL as the name
argument, because passing NULL in all cases will enforce the clock
declaration order (which is not something we usually do when naming
clocks).
If you keep the NULL name, please document the clock order in your DT
documentation.

Best Regards,

Boris

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-02-08 20:00     ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:00 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

Hi Antoine,

On Tue, 27 Jan 2015 15:10:10 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

I'm not the one who should say that (I'm often sending patches without
any commit message), but a short commit message explaining why you're
doing that would help reviewers ;-).

Best Regards,

Boris

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 2681ec4abafa..782ae24d6b7d 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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
@ 2015-02-08 20:00     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:00 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, ezequiel.garcia,
	jszhang, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

Hi Antoine,

On Tue, 27 Jan 2015 15:10:10 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

I'm not the one who should say that (I'm often sending patches without
any commit message), but a short commit message explaining why you're
doing that would help reviewers ;-).

Best Regards,

Boris

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 2681ec4abafa..782ae24d6b7d 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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128
@ 2015-02-08 20:00     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Antoine,

On Tue, 27 Jan 2015 15:10:10 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

I'm not the one who should say that (I'm often sending patches without
any commit message), but a short commit message explaining why you're
doing that would help reviewers ;-).

Best Regards,

Boris

> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 2681ec4abafa..782ae24d6b7d 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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-02-08 20:15     ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:15 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

On Tue, 27 Jan 2015 15:10:11 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Add a default chunk size of 512 in the pxa3xx nand driver.
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 782ae24d6b7d..b2783b1f663c 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 */

Could you explain why you need to set this default chunk size ?
I guess it's because your NAND is not configured by the bootloader, and
thus you did not specify the keep-config attribute in the DT.
And I guess you need this field to be initialized before pxa_ecc_init is
called (for some NAND operations done in the meantime: READID ?).

Moreover, IMHO this should be place in an 'else' statement, otherwise
you'll overwrite the value set in pxa3xx_nand_detect_config.


> +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-02-08 20:15     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:15 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, ezequiel.garcia,
	jszhang, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

On Tue, 27 Jan 2015 15:10:11 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Add a default chunk size of 512 in the pxa3xx nand driver.
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 782ae24d6b7d..b2783b1f663c 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 */

Could you explain why you need to set this default chunk size ?
I guess it's because your NAND is not configured by the bootloader, and
thus you did not specify the keep-config attribute in the DT.
And I guess you need this field to be initialized before pxa_ecc_init is
called (for some NAND operations done in the meantime: READID ?).

Moreover, IMHO this should be place in an 'else' statement, otherwise
you'll overwrite the value set in pxa3xx_nand_detect_config.


> +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-02-08 20:15     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 27 Jan 2015 15:10:11 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> wrote:

> Add a default chunk size of 512 in the pxa3xx nand driver.
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  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 782ae24d6b7d..b2783b1f663c 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 */

Could you explain why you need to set this default chunk size ?
I guess it's because your NAND is not configured by the bootloader, and
thus you did not specify the keep-config attribute in the DT.
And I guess you need this field to be initialized before pxa_ecc_init is
called (for some NAND operations done in the meantime: READID ?).

Moreover, IMHO this should be place in an 'else' statement, otherwise
you'll overwrite the value set in pxa3xx_nand_detect_config.


> +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
  2015-02-08 20:15     ` Boris Brezillon
  (?)
@ 2015-02-08 20:18       ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:18 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

On Sun, 8 Feb 2015 21:15:08 +0100
Boris Brezillon <boris.brezillon@free-electrons.com> wrote:

> On Tue, 27 Jan 2015 15:10:11 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > Add a default chunk size of 512 in the pxa3xx nand driver.
> > 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  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 782ae24d6b7d..b2783b1f663c 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 */
> 
> Could you explain why you need to set this default chunk size ?
> I guess it's because your NAND is not configured by the bootloader, and
> thus you did not specify the keep-config attribute in the DT.
> And I guess you need this field to be initialized before pxa_ecc_init is
> called (for some NAND operations done in the meantime: READID ?).
> 
> Moreover, IMHO this should be place in an 'else' statement, otherwise
> you'll overwrite the value set in pxa3xx_nand_detect_config.

My bad, I didn't notice the 'goto KEEP_CONFIG' statement.

> 
> 
> > +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-02-08 20:18       ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:18 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

On Sun, 8 Feb 2015 21:15:08 +0100
Boris Brezillon <boris.brezillon@free-electrons.com> wrote:

> On Tue, 27 Jan 2015 15:10:11 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > Add a default chunk size of 512 in the pxa3xx nand driver.
> > 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  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 782ae24d6b7d..b2783b1f663c 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 */
> 
> Could you explain why you need to set this default chunk size ?
> I guess it's because your NAND is not configured by the bootloader, and
> thus you did not specify the keep-config attribute in the DT.
> And I guess you need this field to be initialized before pxa_ecc_init is
> called (for some NAND operations done in the meantime: READID ?).
> 
> Moreover, IMHO this should be place in an 'else' statement, otherwise
> you'll overwrite the value set in pxa3xx_nand_detect_config.

My bad, I didn't notice the 'goto KEEP_CONFIG' statement.

> 
> 
> > +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size
@ 2015-02-08 20:18       ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 20:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 8 Feb 2015 21:15:08 +0100
Boris Brezillon <boris.brezillon@free-electrons.com> wrote:

> On Tue, 27 Jan 2015 15:10:11 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> > Add a default chunk size of 512 in the pxa3xx nand driver.
> > 
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  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 782ae24d6b7d..b2783b1f663c 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 */
> 
> Could you explain why you need to set this default chunk size ?
> I guess it's because your NAND is not configured by the bootloader, and
> thus you did not specify the keep-config attribute in the DT.
> And I guess you need this field to be initialized before pxa_ecc_init is
> called (for some NAND operations done in the meantime: READID ?).
> 
> Moreover, IMHO this should be place in an 'else' statement, otherwise
> you'll overwrite the value set in pxa3xx_nand_detect_config.

My bad, I didn't notice the 'goto KEEP_CONFIG' statement.

> 
> 
> > +	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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-02-08 21:06     ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 21:06 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

Hi Antoine,

I didn't review the whole patch yet, but I'll come back to this review
soon.

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT

Really ?
RNDOUT is only used when you only did a standard page read (READ0 +
READSTART), and you want to move the data pointer inside the currently
loaded page (this command only require 2 address cycles).
I wonder how this can work for a regular read page command (where 5
address cycles are required).
Anyway, I trust you if you say you have to do that, but I'm really
curious (how is the controller hiding this standard read phase).

> - the ERASE1 command is specific (0xd060)

As stated in the following comments, I'm pretty sure it's a standard
erase command.

> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000

Your specific RNDOUT command looks like a regular READ0 (0x0) +
READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
to read your page ;-).

> +#define BERLIN_NAND_CMD_ERASE1		0xd060

Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
(0xd0).



>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };

As already stated by Brian and Ezequiel, this should be handled with
the new API for timing retrieval.
However, IMHO, this should be part of another series reworking the pxa
driver, and I know you plan to do that, so I don't mind if this
table is added to support your IP (as long as you're taking care of
reworking that ;-)).

>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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} }
> +};
> +

Okay, this is only my opinion, but I think all the ECC layouts defined
in this driver should be built dynamically (depending on the requested
ECC strength/block-size).
Take a look at the sunxi driver if you need an example.

Again, these are mid term changes, and I won't ask you to change that
in this series.

>  /* Define a default flash type setting serve as flash detecting only */
>  #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
>  
> @@ -346,6 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +
>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;

As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
READSTART command, are there any differences between a RNDOUT and a
regular READ in your driver ?

> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 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
> +						| (0x1080 & 0xff);
> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);
> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +

I don't see any difference with the old version:
you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
to your definition, is equal to
(NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))

Right ?

Am I missing something obvious ?


That's all for now :-).

Best Regards,

Boris


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-08 21:06     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 21:06 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, ezequiel.garcia,
	jszhang, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

Hi Antoine,

I didn't review the whole patch yet, but I'll come back to this review
soon.

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT

Really ?
RNDOUT is only used when you only did a standard page read (READ0 +
READSTART), and you want to move the data pointer inside the currently
loaded page (this command only require 2 address cycles).
I wonder how this can work for a regular read page command (where 5
address cycles are required).
Anyway, I trust you if you say you have to do that, but I'm really
curious (how is the controller hiding this standard read phase).

> - the ERASE1 command is specific (0xd060)

As stated in the following comments, I'm pretty sure it's a standard
erase command.

> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000

Your specific RNDOUT command looks like a regular READ0 (0x0) +
READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
to read your page ;-).

> +#define BERLIN_NAND_CMD_ERASE1		0xd060

Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
(0xd0).



>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };

As already stated by Brian and Ezequiel, this should be handled with
the new API for timing retrieval.
However, IMHO, this should be part of another series reworking the pxa
driver, and I know you plan to do that, so I don't mind if this
table is added to support your IP (as long as you're taking care of
reworking that ;-)).

>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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} }
> +};
> +

Okay, this is only my opinion, but I think all the ECC layouts defined
in this driver should be built dynamically (depending on the requested
ECC strength/block-size).
Take a look at the sunxi driver if you need an example.

Again, these are mid term changes, and I won't ask you to change that
in this series.

>  /* Define a default flash type setting serve as flash detecting only */
>  #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
>  
> @@ -346,6 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +
>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;

As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
READSTART command, are there any differences between a RNDOUT and a
regular READ in your driver ?

> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 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
> +						| (0x1080 & 0xff);
> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);
> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +

I don't see any difference with the old version:
you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
to your definition, is equal to
(NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))

Right ?

Am I missing something obvious ?


That's all for now :-).

Best Regards,

Boris


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-08 21:06     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 21:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Antoine,

I didn't review the whole patch yet, but I'll come back to this review
soon.

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT

Really ?
RNDOUT is only used when you only did a standard page read (READ0 +
READSTART), and you want to move the data pointer inside the currently
loaded page (this command only require 2 address cycles).
I wonder how this can work for a regular read page command (where 5
address cycles are required).
Anyway, I trust you if you say you have to do that, but I'm really
curious (how is the controller hiding this standard read phase).

> - the ERASE1 command is specific (0xd060)

As stated in the following comments, I'm pretty sure it's a standard
erase command.

> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000

Your specific RNDOUT command looks like a regular READ0 (0x0) +
READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
to read your page ;-).

> +#define BERLIN_NAND_CMD_ERASE1		0xd060

Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
(0xd0).



>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };

As already stated by Brian and Ezequiel, this should be handled with
the new API for timing retrieval.
However, IMHO, this should be part of another series reworking the pxa
driver, and I know you plan to do that, so I don't mind if this
table is added to support your IP (as long as you're taking care of
reworking that ;-)).

>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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} }
> +};
> +

Okay, this is only my opinion, but I think all the ECC layouts defined
in this driver should be built dynamically (depending on the requested
ECC strength/block-size).
Take a look at the sunxi driver if you need an example.

Again, these are mid term changes, and I won't ask you to change that
in this series.

>  /* Define a default flash type setting serve as flash detecting only */
>  #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
>  
> @@ -346,6 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +
>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;

As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
READSTART command, are there any differences between a RNDOUT and a
regular READ in your driver ?

> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 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
> +						| (0x1080 & 0xff);
> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);
> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +

I don't see any difference with the old version:
you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
to your definition, is equal to
(NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))

Right ?

Am I missing something obvious ?


That's all for now :-).

Best Regards,

Boris


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-01-27 14:10   ` Antoine Tenart
  (?)
@ 2015-02-08 23:55     ` Boris Brezillon
  -1 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 23:55 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: sebastian.hesselbarth, ezequiel.garcia, dwmw2, computersforpeace,
	thomas.petazzoni, zmxu, linux-kernel, linux-mtd, jszhang,
	linux-arm-kernel

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +

Why don't you reuse the following if statement (which is doing the
exact same thing, except for the size being stored in ndbc3 when
the command is created).

Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
chunk, but only on the last one.
Doing that will only work for 4K pages (2 * max_chunk_size), and you
add support for 8K pages NANDs in this patch.

>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;
> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 8));

You can replace the last 2 lines by:
                                                | 0x10ff);

But the 0xff is really weird, cause 0xff is the RESET command...



> +			} 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
> +						| (0x1080 & 0xff);

and this line by
                                                | 0x80);

> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);

Ditto.

Anyway, are you sure this shouldn't be:
						| 0x1080);

or even better:

						| (NAND_CMD_PAGEPROG<<8)
						| NAND_CMD_SEQIN);

> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +
>  		break;
>  	case NAND_CMD_RESET:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(5)
> @@ -1078,6 +1196,102 @@ 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;
> +	unsigned int oob_size = info->oob_size;
> +	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) {
> +			cmd = NAND_CMD_RNDOUT;
> +			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_RNDOUT) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
> +				info->oob_size = oob_size;
> +			} else {
> +				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
> +			}
> +		}
> +
> +		if (cmd == NAND_CMD_PAGEPROG) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
> +				info->oob_size = oob_size;
> +			} 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 +1407,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 +1617,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 +1646,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 +1659,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;

Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.

Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
If you're unsure, maybe you should add a check here, and refuse to
probe such NAND chips.

> +
>  	ret = pxa3xx_nand_sensing(info);
>  	if (ret) {
>  		dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
> @@ -1452,19 +1681,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; (f = &flash_types[i]); i++)
>  		if (f->chip_id == id)
>  			break;
> +
> +	if (f == NULL) {
> +		for (i = 0; i < pdata->num_flash; i++) {
> +			f = pdata->flash + i;
> +			if (f->chip_id == id)
> +				break;
> +		}
>  	}

You're changing the matching order here, the initial order was:

1/ pdata definition
2/ builtin types

and you're now doing:

1/ builtin types
2/ pdata definition


>  
> -	if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
> +	if (f == NULL) {
>  		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>  
>  		return -EINVAL;
> @@ -1515,7 +1749,8 @@ KEEP_CONFIG:
>  	 * we are given the right variant and then switch to the extended
>  	 * (aka splitted) command handling,
>  	 */
> -	if (mtd->writesize > PAGE_CHUNK_SIZE) {
> +	if (mtd->writesize > PAGE_CHUNK_SIZE &&
> +			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
>  			chip->cmdfunc = nand_cmdfunc_extended;
>  		} else {



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-08 23:55     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 23:55 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, zmxu, linux-kernel, linux-mtd, ezequiel.garcia,
	jszhang, computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +

Why don't you reuse the following if statement (which is doing the
exact same thing, except for the size being stored in ndbc3 when
the command is created).

Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
chunk, but only on the last one.
Doing that will only work for 4K pages (2 * max_chunk_size), and you
add support for 8K pages NANDs in this patch.

>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;
> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 8));

You can replace the last 2 lines by:
                                                | 0x10ff);

But the 0xff is really weird, cause 0xff is the RESET command...



> +			} 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
> +						| (0x1080 & 0xff);

and this line by
                                                | 0x80);

> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);

Ditto.

Anyway, are you sure this shouldn't be:
						| 0x1080);

or even better:

						| (NAND_CMD_PAGEPROG<<8)
						| NAND_CMD_SEQIN);

> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +
>  		break;
>  	case NAND_CMD_RESET:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(5)
> @@ -1078,6 +1196,102 @@ 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;
> +	unsigned int oob_size = info->oob_size;
> +	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) {
> +			cmd = NAND_CMD_RNDOUT;
> +			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_RNDOUT) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
> +				info->oob_size = oob_size;
> +			} else {
> +				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
> +			}
> +		}
> +
> +		if (cmd == NAND_CMD_PAGEPROG) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
> +				info->oob_size = oob_size;
> +			} 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 +1407,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 +1617,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 +1646,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 +1659,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;

Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.

Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
If you're unsure, maybe you should add a check here, and refuse to
probe such NAND chips.

> +
>  	ret = pxa3xx_nand_sensing(info);
>  	if (ret) {
>  		dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
> @@ -1452,19 +1681,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; (f = &flash_types[i]); i++)
>  		if (f->chip_id == id)
>  			break;
> +
> +	if (f == NULL) {
> +		for (i = 0; i < pdata->num_flash; i++) {
> +			f = pdata->flash + i;
> +			if (f->chip_id == id)
> +				break;
> +		}
>  	}

You're changing the matching order here, the initial order was:

1/ pdata definition
2/ builtin types

and you're now doing:

1/ builtin types
2/ pdata definition


>  
> -	if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
> +	if (f == NULL) {
>  		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>  
>  		return -EINVAL;
> @@ -1515,7 +1749,8 @@ KEEP_CONFIG:
>  	 * we are given the right variant and then switch to the extended
>  	 * (aka splitted) command handling,
>  	 */
> -	if (mtd->writesize > PAGE_CHUNK_SIZE) {
> +	if (mtd->writesize > PAGE_CHUNK_SIZE &&
> +			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
>  			chip->cmdfunc = nand_cmdfunc_extended;
>  		} else {



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-08 23:55     ` Boris Brezillon
  0 siblings, 0 replies; 84+ messages in thread
From: Boris Brezillon @ 2015-02-08 23:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 27 Jan 2015 15:10:12 +0100
Antoine Tenart <antoine.tenart@free-electrons.com> 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
> - the RNDOUT command must be used to perform a read operation, and the
>   command is not NAND_CMD_RNDOUT
> - the ERASE1 command is specific (0xd060)
> 
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c | 287 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 261 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b2783b1f663c..62ea369dc524 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,20 @@
>  #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	10
> +#define EXT_CMD_TYPE_CHUNK_PAGEPROG	9
> +#define EXT_CMD_TYPE_LAST_RNDOUT	8
> +#define EXT_CMD_TYPE_CHUNK_RNDOUT	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 */
> +
> +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> +#define BERLIN_NAND_CMD_ERASE1		0xd060
>  
>  /* macros for registers read/write */
>  #define nand_writel(info, off, val)	\
> @@ -158,6 +167,7 @@ enum {
>  enum pxa3xx_nand_variant {
>  	PXA3XX_NAND_VARIANT_PXA,
>  	PXA3XX_NAND_VARIANT_ARMADA370,
> +	PXA3XX_NAND_VARIANT_BERLIN2,
>  };
>  
>  struct pxa3xx_nand_host {
> @@ -244,10 +254,13 @@ 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,  60000,  60, 10, },
> +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
>  };
>  
>  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> @@ -260,6 +273,20 @@ 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[] = {
> +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> +{ },
>  };
>  
>  static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> @@ -320,6 +347,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 +385,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);
> @@ -378,6 +421,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>  
> +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> +		ndtr0 = 0x84840A12;
> +		ndtr1 = 0x00208662;
> +	}
> +
>  	info->ndtr0cs0 = ndtr0;
>  	info->ndtr1cs0 = ndtr1;
>  	nand_writel(info, NDTR0CS0, ndtr0);
> @@ -644,6 +692,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  		nand_writel(info, NDCB0, info->ndcb1);
>  		nand_writel(info, NDCB0, info->ndcb2);
>  
> +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> +				info->ndcb0 & NDCB0_LEN_OVRD)
> +			nand_writel(info, NDCB0,
> +					info->chunk_size + info->oob_size);
> +

Why don't you reuse the following if statement (which is doing the
exact same thing, except for the size being stored in ndbc3 when
the command is created).

Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
chunk, but only on the last one.
Doing that will only work for 4K pages (2 * max_chunk_size), and you
add support for 8K pages NANDs in this patch.

>  		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
>  			nand_writel(info, NDCB0, info->ndcb3);
> @@ -755,6 +808,19 @@ 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 || command == NAND_CMD_READOOB)
> +			exec_cmd = 0;
> +
> +		if (command == NAND_CMD_SEQIN)
> +			command = NAND_CMD_READ0;
> +		else if (command == NAND_CMD_RNDOUT)
> +			command = BERLIN_NAND_CMD_RNDOUT;
> +		else if (command == NAND_CMD_ERASE1)
> +			command = BERLIN_NAND_CMD_ERASE1;
> +	}
> +
>  	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
>  				    + host->col_addr_cycles);
>  
> @@ -814,6 +880,34 @@ 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
> +						| 0xff
> +						| (0x1080 & (0xff << 8));

You can replace the last 2 lines by:
                                                | 0x10ff);

But the 0xff is really weird, cause 0xff is the RESET command...



> +			} 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
> +						| (0x1080 & 0xff);

and this line by
                                                | 0x80);

> +			} else {
> +				info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +						| NDCB0_CMD_XTYPE(0x4)
> +						| NDCB0_NC
> +						| NDCB0_AUTO_RS
> +						| NDCB0_LEN_OVRD
> +						| addr_cycle
> +						| (0x1080 & 0xff);

Ditto.

Anyway, are you sure this shouldn't be:
						| 0x1080);

or even better:

						| (NAND_CMD_PAGEPROG<<8)
						| NAND_CMD_SEQIN);

> +			}
> +
> +			break;
> +		}
> +
>  		/* Second command setting for large pages */
>  		if (mtd->writesize > PAGE_CHUNK_SIZE) {
>  			/*
> @@ -870,6 +964,27 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  
>  		info->data_size = 8;
>  		break;
> +
> +	case BERLIN_NAND_CMD_RNDOUT:
> +		info->buf_start = column;
> +
> +		if (ext_cmd_type == EXT_CMD_TYPE_LAST_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD;
> +		else if (ext_cmd_type == EXT_CMD_TYPE_CHUNK_RNDOUT)
> +			info->ndcb0 = NDCB0_CMD_XTYPE(0x5)
> +					| NDCB0_LEN_OVRD
> +					| NDCB0_NC;
> +		else
> +			info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +					| NDCB0_CMD_XTYPE(0x6)
> +					| NDCB0_DBC
> +					| NDCB0_NC
> +					| addr_cycle
> +					| command;
> +
> +		break;
> +
>  	case NAND_CMD_STATUS:
>  		info->buf_count = 1;
>  		info->ndcb0 |= NDCB0_CMD_TYPE(4)
> @@ -880,15 +995,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
>  		break;
>  
>  	case NAND_CMD_ERASE1:
> +	case BERLIN_NAND_CMD_ERASE1:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
>  				| NDCB0_AUTO_RS
>  				| NDCB0_ADDR_CYC(3)
>  				| NDCB0_DBC
> -				| (NAND_CMD_ERASE2 << 8)
> -				| NAND_CMD_ERASE1;
> +				| command;
>  		info->ndcb1 = page_addr;
>  		info->ndcb2 = 0;
>  
> +		if (command == NAND_CMD_ERASE1)
> +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> +
>  		break;
>  	case NAND_CMD_RESET:
>  		info->ndcb0 |= NDCB0_CMD_TYPE(5)
> @@ -1078,6 +1196,102 @@ 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;
> +	unsigned int oob_size = info->oob_size;
> +	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) {
> +			cmd = NAND_CMD_RNDOUT;
> +			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_RNDOUT) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_RNDOUT;
> +				info->oob_size = oob_size;
> +			} else {
> +				ext_cmd_type = EXT_CMD_TYPE_CHUNK_RNDOUT;
> +			}
> +		}
> +
> +		if (cmd == NAND_CMD_PAGEPROG) {
> +			/* last command */
> +			if (info->data_size == info->chunk_size * 2) {
> +				ext_cmd_type = EXT_CMD_TYPE_LAST_PAGEPROG;
> +				info->oob_size = oob_size;
> +			} 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 +1407,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 +1617,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 +1646,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 +1659,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;

Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.

Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
If you're unsure, maybe you should add a check here, and refuse to
probe such NAND chips.

> +
>  	ret = pxa3xx_nand_sensing(info);
>  	if (ret) {
>  		dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
> @@ -1452,19 +1681,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; (f = &flash_types[i]); i++)
>  		if (f->chip_id == id)
>  			break;
> +
> +	if (f == NULL) {
> +		for (i = 0; i < pdata->num_flash; i++) {
> +			f = pdata->flash + i;
> +			if (f->chip_id == id)
> +				break;
> +		}
>  	}

You're changing the matching order here, the initial order was:

1/ pdata definition
2/ builtin types

and you're now doing:

1/ builtin types
2/ pdata definition


>  
> -	if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
> +	if (f == NULL) {
>  		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>  
>  		return -EINVAL;
> @@ -1515,7 +1749,8 @@ KEEP_CONFIG:
>  	 * we are given the right variant and then switch to the extended
>  	 * (aka splitted) command handling,
>  	 */
> -	if (mtd->writesize > PAGE_CHUNK_SIZE) {
> +	if (mtd->writesize > PAGE_CHUNK_SIZE &&
> +			info->variant != PXA3XX_NAND_VARIANT_BERLIN2) {
>  		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
>  			chip->cmdfunc = nand_cmdfunc_extended;
>  		} else {



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-08 23:55     ` Boris Brezillon
  (?)
@ 2015-02-10 19:50       ` Robert Jarzmik
  -1 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-10 19:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Antoine Tenart, thomas.petazzoni, zmxu, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> 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
>> - the RNDOUT command must be used to perform a read operation, and the
>>   command is not NAND_CMD_RNDOUT
>> - the ERASE1 command is specific (0xd060)
>> 
>> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>

Given all the differences, the PIO mode instead of the current interrupt model,
and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
 - extract the common functions to mrvl-nand-lib.c
 - the remaining would be in pxa3xx_nand.c
 - the new code will be in berlin_nand.c

All these ifs per variant will add complexity to the current driver, won't they
?

Cheers.

--
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-10 19:50       ` Robert Jarzmik
  0 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-10 19:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> 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
>> - the RNDOUT command must be used to perform a read operation, and the
>>   command is not NAND_CMD_RNDOUT
>> - the ERASE1 command is specific (0xd060)
>> 
>> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>

Given all the differences, the PIO mode instead of the current interrupt model,
and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
 - extract the common functions to mrvl-nand-lib.c
 - the remaining would be in pxa3xx_nand.c
 - the new code will be in berlin_nand.c

All these ifs per variant will add complexity to the current driver, won't they
?

Cheers.

--
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-10 19:50       ` Robert Jarzmik
  0 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-10 19:50 UTC (permalink / raw)
  To: linux-arm-kernel

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> 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
>> - the RNDOUT command must be used to perform a read operation, and the
>>   command is not NAND_CMD_RNDOUT
>> - the ERASE1 command is specific (0xd060)
>> 
>> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>

Given all the differences, the PIO mode instead of the current interrupt model,
and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
 - extract the common functions to mrvl-nand-lib.c
 - the remaining would be in pxa3xx_nand.c
 - the new code will be in berlin_nand.c

All these ifs per variant will add complexity to the current driver, won't they
?

Cheers.

--
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-08 21:06     ` Boris Brezillon
  (?)
@ 2015-02-11 16:27       ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:27 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Antoine Tenart, sebastian.hesselbarth, ezequiel.garcia, dwmw2,
	computersforpeace, thomas.petazzoni, zmxu, linux-kernel,
	linux-mtd, jszhang, linux-arm-kernel

Hi Boris,

On Sun, Feb 08, 2015 at 10:06:33PM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> > +
> > +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> 
> Your specific RNDOUT command looks like a regular READ0 (0x0) +
> READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
> to read your page ;-).

You're right :)

> 
> > +#define BERLIN_NAND_CMD_ERASE1		0xd060
> 
> Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
> (0xd0).

Yep, I'll update.

> >  
> >  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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> 
> As already stated by Brian and Ezequiel, this should be handled with
> the new API for timing retrieval.
> However, IMHO, this should be part of another series reworking the pxa
> driver, and I know you plan to do that, so I don't mind if this
> table is added to support your IP (as long as you're taking care of
> reworking that ;-)).

Yep, that's the plan.

> >  
> > +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} }
> > +};
> > +
> 
> Okay, this is only my opinion, but I think all the ECC layouts defined
> in this driver should be built dynamically (depending on the requested
> ECC strength/block-size).
> Take a look at the sunxi driver if you need an example.
> 
> Again, these are mid term changes, and I won't ask you to change that
> in this series.

Also part of the plan :)

> >  
> > +	/* Berlin specific */
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> > +		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB)
> > +			exec_cmd = 0;
> > +
> > +		if (command == NAND_CMD_SEQIN)
> > +			command = NAND_CMD_READ0;
> > +		else if (command == NAND_CMD_RNDOUT)
> > +			command = BERLIN_NAND_CMD_RNDOUT;
> 
> As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
> READSTART command, are there any differences between a RNDOUT and a
> regular READ in your driver ?

There isn't and I'll update to use the regular READ0 command.

> >  
> >  	case NAND_CMD_ERASE1:
> > +	case BERLIN_NAND_CMD_ERASE1:
> >  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
> >  				| NDCB0_AUTO_RS
> >  				| NDCB0_ADDR_CYC(3)
> >  				| NDCB0_DBC
> > -				| (NAND_CMD_ERASE2 << 8)
> > -				| NAND_CMD_ERASE1;
> > +				| command;
> >  		info->ndcb1 = page_addr;
> >  		info->ndcb2 = 0;
> >  
> > +		if (command == NAND_CMD_ERASE1)
> > +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> > +
> 
> I don't see any difference with the old version:
> you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
> to your definition, is equal to
> (NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))
> 
> Right ?
> 
> Am I missing something obvious ?

Nope, I'll fix this.

> 
> That's all for now :-).

Thanks!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:27       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:27 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Hi Boris,

On Sun, Feb 08, 2015 at 10:06:33PM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> > +
> > +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> 
> Your specific RNDOUT command looks like a regular READ0 (0x0) +
> READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
> to read your page ;-).

You're right :)

> 
> > +#define BERLIN_NAND_CMD_ERASE1		0xd060
> 
> Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
> (0xd0).

Yep, I'll update.

> >  
> >  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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> 
> As already stated by Brian and Ezequiel, this should be handled with
> the new API for timing retrieval.
> However, IMHO, this should be part of another series reworking the pxa
> driver, and I know you plan to do that, so I don't mind if this
> table is added to support your IP (as long as you're taking care of
> reworking that ;-)).

Yep, that's the plan.

> >  
> > +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} }
> > +};
> > +
> 
> Okay, this is only my opinion, but I think all the ECC layouts defined
> in this driver should be built dynamically (depending on the requested
> ECC strength/block-size).
> Take a look at the sunxi driver if you need an example.
> 
> Again, these are mid term changes, and I won't ask you to change that
> in this series.

Also part of the plan :)

> >  
> > +	/* Berlin specific */
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> > +		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB)
> > +			exec_cmd = 0;
> > +
> > +		if (command == NAND_CMD_SEQIN)
> > +			command = NAND_CMD_READ0;
> > +		else if (command == NAND_CMD_RNDOUT)
> > +			command = BERLIN_NAND_CMD_RNDOUT;
> 
> As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
> READSTART command, are there any differences between a RNDOUT and a
> regular READ in your driver ?

There isn't and I'll update to use the regular READ0 command.

> >  
> >  	case NAND_CMD_ERASE1:
> > +	case BERLIN_NAND_CMD_ERASE1:
> >  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
> >  				| NDCB0_AUTO_RS
> >  				| NDCB0_ADDR_CYC(3)
> >  				| NDCB0_DBC
> > -				| (NAND_CMD_ERASE2 << 8)
> > -				| NAND_CMD_ERASE1;
> > +				| command;
> >  		info->ndcb1 = page_addr;
> >  		info->ndcb2 = 0;
> >  
> > +		if (command == NAND_CMD_ERASE1)
> > +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> > +
> 
> I don't see any difference with the old version:
> you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
> to your definition, is equal to
> (NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))
> 
> Right ?
> 
> Am I missing something obvious ?

Nope, I'll fix this.

> 
> That's all for now :-).

Thanks!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:27       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Sun, Feb 08, 2015 at 10:06:33PM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> > +
> > +#define BERLIN_NAND_CMD_RNDOUT		0x3000
> 
> Your specific RNDOUT command looks like a regular READ0 (0x0) +
> READSTART (0x30) sequence, I think this is why you need to do a RNDOUT
> to read your page ;-).

You're right :)

> 
> > +#define BERLIN_NAND_CMD_ERASE1		0xd060
> 
> Ditto, it's a regular ERASE command sequence: ERASE1 (0x60) + ERASE2
> (0xd0).

Yep, I'll update.

> >  
> >  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,  60000,  60, 10, },
> > +	{  5, 20, 10,  12, 10,  12, 200000, 120, 10, },
> > +	{  5, 15, 10,  15, 10,  15,  60000,  60, 10, },
> >  };
> >  
> >  static struct pxa3xx_nand_flash builtin_flash_types[] = {
> > @@ -260,6 +273,20 @@ 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[] = {
> > +{ "2GiB 8-bit",    0xd5ec, 128, 8192,  8,  8, 2048, &timing[4] },
> > +{ "2GiB 8-bit",    0xd598, 128, 8192,  8,  8, 2048, &timing[5] },
> > +{ "2GiB 8-bit",    0x482c, 256, 4096,  8,  8, 2048, &timing[6] },
> > +{ "4GiB 8-bit",    0xd7ec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "8GiB 8-bit",    0xdeec, 128, 8192,  8,  8, 4096, &timing[5] },
> > +{ "4GiB 8-bit",    0xd7ad, 256, 8192,  8,  8, 2048, &timing[5] },
> > +{ "4GiB 8-bit",    0x682c, 256, 4096,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0x882c, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ "8GiB 8-bit",    0xdead, 256, 8192,  8,  8, 4096, &timing[6] },
> > +{ },
> >  };
> 
> As already stated by Brian and Ezequiel, this should be handled with
> the new API for timing retrieval.
> However, IMHO, this should be part of another series reworking the pxa
> driver, and I know you plan to do that, so I don't mind if this
> table is added to support your IP (as long as you're taking care of
> reworking that ;-)).

Yep, that's the plan.

> >  
> > +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} }
> > +};
> > +
> 
> Okay, this is only my opinion, but I think all the ECC layouts defined
> in this driver should be built dynamically (depending on the requested
> ECC strength/block-size).
> Take a look at the sunxi driver if you need an example.
> 
> Again, these are mid term changes, and I won't ask you to change that
> in this series.

Also part of the plan :)

> >  
> > +	/* Berlin specific */
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2) {
> > +		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB)
> > +			exec_cmd = 0;
> > +
> > +		if (command == NAND_CMD_SEQIN)
> > +			command = NAND_CMD_READ0;
> > +		else if (command == NAND_CMD_RNDOUT)
> > +			command = BERLIN_NAND_CMD_RNDOUT;
> 
> As stated above your BERLIN_NAND_CMD_RNDOUT is just a regular READ0 +
> READSTART command, are there any differences between a RNDOUT and a
> regular READ in your driver ?

There isn't and I'll update to use the regular READ0 command.

> >  
> >  	case NAND_CMD_ERASE1:
> > +	case BERLIN_NAND_CMD_ERASE1:
> >  		info->ndcb0 |= NDCB0_CMD_TYPE(2)
> >  				| NDCB0_AUTO_RS
> >  				| NDCB0_ADDR_CYC(3)
> >  				| NDCB0_DBC
> > -				| (NAND_CMD_ERASE2 << 8)
> > -				| NAND_CMD_ERASE1;
> > +				| command;
> >  		info->ndcb1 = page_addr;
> >  		info->ndcb2 = 0;
> >  
> > +		if (command == NAND_CMD_ERASE1)
> > +			info->ndcb0 |= (NAND_CMD_ERASE2 << 8);
> > +
> 
> I don't see any difference with the old version:
> you previously set command to BERLIN_NAND_CMD_ERASE1, which, according
> to your definition, is equal to
> (NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8))
> 
> Right ?
> 
> Am I missing something obvious ?

Nope, I'll fix this.

> 
> That's all for now :-).

Thanks!

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-08 23:55     ` Boris Brezillon
  (?)
@ 2015-02-11 16:31       ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:31 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Antoine Tenart, sebastian.hesselbarth, ezequiel.garcia, dwmw2,
	computersforpeace, thomas.petazzoni, zmxu, linux-kernel,
	linux-mtd, jszhang, linux-arm-kernel

Boris,

On Mon, Feb 09, 2015 at 12:55:03AM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> >  
> > +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> > +				info->ndcb0 & NDCB0_LEN_OVRD)
> > +			nand_writel(info, NDCB0,
> > +					info->chunk_size + info->oob_size);
> > +
> 
> Why don't you reuse the following if statement (which is doing the
> exact same thing, except for the size being stored in ndbc3 when
> the command is created).

I'll update to reuse this!

> Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
> chunk, but only on the last one.
> Doing that will only work for 4K pages (2 * max_chunk_size), and you
> add support for 8K pages NANDs in this patch.

Yep. As a matter of fact, oob_size was equl to 0 in this case because of
some dirty hacks. I'll remove them and will send a v2 with a proper
solution.

> >  
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
> > +		chip->cmdfunc = nand_cmdfunc_berlin;
> 
> Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
> only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.
> 
> Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
> If you're unsure, maybe you should add a check here, and refuse to
> probe such NAND chips.

I currently have no idea, so I'll add a check here.

> >  
> > -	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; (f = &flash_types[i]); i++)
> >  		if (f->chip_id == id)
> >  			break;
> > +
> > +	if (f == NULL) {
> > +		for (i = 0; i < pdata->num_flash; i++) {
> > +			f = pdata->flash + i;
> > +			if (f->chip_id == id)
> > +				break;
> > +		}
> >  	}
> 
> You're changing the matching order here, the initial order was:
> 
> 1/ pdata definition
> 2/ builtin types
> 
> and you're now doing:
> 
> 1/ builtin types
> 2/ pdata definition

Oops...

Thanks for the review!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:31       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:31 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: thomas.petazzoni, zmxu, Antoine Tenart, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Boris,

On Mon, Feb 09, 2015 at 12:55:03AM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> >  
> > +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> > +				info->ndcb0 & NDCB0_LEN_OVRD)
> > +			nand_writel(info, NDCB0,
> > +					info->chunk_size + info->oob_size);
> > +
> 
> Why don't you reuse the following if statement (which is doing the
> exact same thing, except for the size being stored in ndbc3 when
> the command is created).

I'll update to reuse this!

> Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
> chunk, but only on the last one.
> Doing that will only work for 4K pages (2 * max_chunk_size), and you
> add support for 8K pages NANDs in this patch.

Yep. As a matter of fact, oob_size was equl to 0 in this case because of
some dirty hacks. I'll remove them and will send a v2 with a proper
solution.

> >  
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
> > +		chip->cmdfunc = nand_cmdfunc_berlin;
> 
> Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
> only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.
> 
> Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
> If you're unsure, maybe you should add a check here, and refuse to
> probe such NAND chips.

I currently have no idea, so I'll add a check here.

> >  
> > -	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; (f = &flash_types[i]); i++)
> >  		if (f->chip_id == id)
> >  			break;
> > +
> > +	if (f == NULL) {
> > +		for (i = 0; i < pdata->num_flash; i++) {
> > +			f = pdata->flash + i;
> > +			if (f->chip_id == id)
> > +				break;
> > +		}
> >  	}
> 
> You're changing the matching order here, the initial order was:
> 
> 1/ pdata definition
> 2/ builtin types
> 
> and you're now doing:
> 
> 1/ builtin types
> 2/ pdata definition

Oops...

Thanks for the review!

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:31       ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:31 UTC (permalink / raw)
  To: linux-arm-kernel

Boris,

On Mon, Feb 09, 2015 at 12:55:03AM +0100, Boris Brezillon wrote:
> On Tue, 27 Jan 2015 15:10:12 +0100
> Antoine Tenart <antoine.tenart@free-electrons.com> wrote:
> 
> >  
> > +		if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2 &&
> > +				info->ndcb0 & NDCB0_LEN_OVRD)
> > +			nand_writel(info, NDCB0,
> > +					info->chunk_size + info->oob_size);
> > +
> 
> Why don't you reuse the following if statement (which is doing the
> exact same thing, except for the size being stored in ndbc3 when
> the command is created).

I'll update to reuse this!

> Moreover, I'm pretty sure you don't want to add oob_size on the 2nd
> chunk, but only on the last one.
> Doing that will only work for 4K pages (2 * max_chunk_size), and you
> add support for 8K pages NANDs in this patch.

Yep. As a matter of fact, oob_size was equl to 0 in this case because of
some dirty hacks. I'll remove them and will send a v2 with a proper
solution.

> >  
> > +	if (info->variant == PXA3XX_NAND_VARIANT_BERLIN2)
> > +		chip->cmdfunc = nand_cmdfunc_berlin;
> 
> Your cmdfunc looks like the nand_cmdfunc_extended one, and this one is
> only used for NAND chips that have writesize > PAGE_CHUNK_SIZE.
> 
> Is your cmdfunc supporting accesses to NAND chips with smaller pages ?
> If you're unsure, maybe you should add a check here, and refuse to
> probe such NAND chips.

I currently have no idea, so I'll add a check here.

> >  
> > -	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; (f = &flash_types[i]); i++)
> >  		if (f->chip_id == id)
> >  			break;
> > +
> > +	if (f == NULL) {
> > +		for (i = 0; i < pdata->num_flash; i++) {
> > +			f = pdata->flash + i;
> > +			if (f->chip_id == id)
> > +				break;
> > +		}
> >  	}
> 
> You're changing the matching order here, the initial order was:
> 
> 1/ pdata definition
> 2/ builtin types
> 
> and you're now doing:
> 
> 1/ builtin types
> 2/ pdata definition

Oops...

Thanks for the review!

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-10 19:50       ` Robert Jarzmik
  (?)
@ 2015-02-11 16:33         ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:33 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Boris Brezillon, Antoine Tenart, thomas.petazzoni, zmxu,
	linux-kernel, linux-mtd, ezequiel.garcia, jszhang,
	computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

Robert,

On Tue, Feb 10, 2015 at 08:50:41PM +0100, Robert Jarzmik wrote:
> Boris Brezillon <boris.brezillon@free-electrons.com> writes:
> > On Tue, 27 Jan 2015 15:10:12 +0100
> > Antoine Tenart <antoine.tenart@free-electrons.com> 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
> >> - the RNDOUT command must be used to perform a read operation, and the
> >>   command is not NAND_CMD_RNDOUT
> >> - the ERASE1 command is specific (0xd060)
> >> 
> >> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> 
> Given all the differences, the PIO mode instead of the current interrupt model,
> and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
>  - extract the common functions to mrvl-nand-lib.c
>  - the remaining would be in pxa3xx_nand.c
>  - the new code will be in berlin_nand.c
> 
> All these ifs per variant will add complexity to the current driver, won't they
> ?

Given the current state of this driver I believe this would be a better
idea to first rework it to use the nand framework properly. Then it will
be possible to have a look on what we have, to decide whether or not a
mrvl-nand-lib is needed.

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:33         ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:33 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: thomas.petazzoni, Boris Brezillon, Antoine Tenart, linux-kernel,
	zmxu, linux-mtd, ezequiel.garcia, jszhang, computersforpeace,
	dwmw2, linux-arm-kernel, sebastian.hesselbarth

Robert,

On Tue, Feb 10, 2015 at 08:50:41PM +0100, Robert Jarzmik wrote:
> Boris Brezillon <boris.brezillon@free-electrons.com> writes:
> > On Tue, 27 Jan 2015 15:10:12 +0100
> > Antoine Tenart <antoine.tenart@free-electrons.com> 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
> >> - the RNDOUT command must be used to perform a read operation, and the
> >>   command is not NAND_CMD_RNDOUT
> >> - the ERASE1 command is specific (0xd060)
> >> 
> >> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> 
> Given all the differences, the PIO mode instead of the current interrupt model,
> and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
>  - extract the common functions to mrvl-nand-lib.c
>  - the remaining would be in pxa3xx_nand.c
>  - the new code will be in berlin_nand.c
> 
> All these ifs per variant will add complexity to the current driver, won't they
> ?

Given the current state of this driver I believe this would be a better
idea to first rework it to use the nand framework properly. Then it will
be possible to have a look on what we have, to decide whether or not a
mrvl-nand-lib is needed.

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-11 16:33         ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-11 16:33 UTC (permalink / raw)
  To: linux-arm-kernel

Robert,

On Tue, Feb 10, 2015 at 08:50:41PM +0100, Robert Jarzmik wrote:
> Boris Brezillon <boris.brezillon@free-electrons.com> writes:
> > On Tue, 27 Jan 2015 15:10:12 +0100
> > Antoine Tenart <antoine.tenart@free-electrons.com> 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
> >> - the RNDOUT command must be used to perform a read operation, and the
> >>   command is not NAND_CMD_RNDOUT
> >> - the ERASE1 command is specific (0xd060)
> >> 
> >> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> 
> Given all the differences, the PIO mode instead of the current interrupt model,
> and the berlin specific functions (nand_start, ...), wouldn't it be an idea to :
>  - extract the common functions to mrvl-nand-lib.c
>  - the remaining would be in pxa3xx_nand.c
>  - the new code will be in berlin_nand.c
> 
> All these ifs per variant will add complexity to the current driver, won't they
> ?

Given the current state of this driver I believe this would be a better
idea to first rework it to use the nand framework properly. Then it will
be possible to have a look on what we have, to decide whether or not a
mrvl-nand-lib is needed.

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-11 16:33         ` Antoine Tenart
  (?)
@ 2015-02-12 16:26           ` Robert Jarzmik
  -1 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-12 16:26 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: Boris Brezillon, thomas.petazzoni, zmxu, linux-kernel, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Antoine Tenart <antoine.tenart@free-electrons.com> writes:

>> All these ifs per variant will add complexity to the current driver, won't they
>> ?
>
> Given the current state of this driver I believe this would be a better
> idea to first rework it to use the nand framework properly. Then it will
> be possible to have a look on what we have, to decide whether or not a
> mrvl-nand-lib is needed.

I don't fully agree to delay.
You're taking code, making sometimes copy-paste, for the berlin specific
functions, and I think you're taking the bugs as well, which duplicates the fix
effort.

For example, in nand_cmdfunc_berlin():
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;

This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
happens if the command is _not_ a read command, but an ONFI READID command
(ONFI being specified by column=0x20 if memory serves me well).

This is the reason I don't really like this patch. And this is also the reason
why I believe you're in a perfect timing to improve things, by grouping the
common function, and keeping the bugs in only one place, not many.

Cheers.

-- 
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-12 16:26           ` Robert Jarzmik
  0 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-12 16:26 UTC (permalink / raw)
  To: Antoine Tenart
  Cc: thomas.petazzoni, Boris Brezillon, linux-kernel, zmxu, linux-mtd,
	ezequiel.garcia, jszhang, computersforpeace, dwmw2,
	linux-arm-kernel, sebastian.hesselbarth

Antoine Tenart <antoine.tenart@free-electrons.com> writes:

>> All these ifs per variant will add complexity to the current driver, won't they
>> ?
>
> Given the current state of this driver I believe this would be a better
> idea to first rework it to use the nand framework properly. Then it will
> be possible to have a look on what we have, to decide whether or not a
> mrvl-nand-lib is needed.

I don't fully agree to delay.
You're taking code, making sometimes copy-paste, for the berlin specific
functions, and I think you're taking the bugs as well, which duplicates the fix
effort.

For example, in nand_cmdfunc_berlin():
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;

This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
happens if the command is _not_ a read command, but an ONFI READID command
(ONFI being specified by column=0x20 if memory serves me well).

This is the reason I don't really like this patch. And this is also the reason
why I believe you're in a perfect timing to improve things, by grouping the
common function, and keeping the bugs in only one place, not many.

Cheers.

-- 
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-12 16:26           ` Robert Jarzmik
  0 siblings, 0 replies; 84+ messages in thread
From: Robert Jarzmik @ 2015-02-12 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

Antoine Tenart <antoine.tenart@free-electrons.com> writes:

>> All these ifs per variant will add complexity to the current driver, won't they
>> ?
>
> Given the current state of this driver I believe this would be a better
> idea to first rework it to use the nand framework properly. Then it will
> be possible to have a look on what we have, to decide whether or not a
> mrvl-nand-lib is needed.

I don't fully agree to delay.
You're taking code, making sometimes copy-paste, for the berlin specific
functions, and I think you're taking the bugs as well, which duplicates the fix
effort.

For example, in nand_cmdfunc_berlin():
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;

This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
happens if the command is _not_ a read command, but an ONFI READID command
(ONFI being specified by column=0x20 if memory serves me well).

This is the reason I don't really like this patch. And this is also the reason
why I believe you're in a perfect timing to improve things, by grouping the
common function, and keeping the bugs in only one place, not many.

Cheers.

-- 
Robert

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
  2015-02-12 16:26           ` Robert Jarzmik
  (?)
@ 2015-02-17  9:52             ` Antoine Tenart
  -1 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-17  9:52 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Antoine Tenart, Boris Brezillon, thomas.petazzoni, zmxu,
	linux-kernel, linux-mtd, ezequiel.garcia, jszhang,
	computersforpeace, dwmw2, linux-arm-kernel,
	sebastian.hesselbarth

Robert,

On Thu, Feb 12, 2015 at 05:26:20PM +0100, Robert Jarzmik wrote:
> Antoine Tenart <antoine.tenart@free-electrons.com> writes:
> 
> >> All these ifs per variant will add complexity to the current driver, won't they
> >> ?
> >
> > Given the current state of this driver I believe this would be a better
> > idea to first rework it to use the nand framework properly. Then it will
> > be possible to have a look on what we have, to decide whether or not a
> > mrvl-nand-lib is needed.
> 
> I don't fully agree to delay.

And sorry, but I don't think reworking the pxa3xx driver this way is a
good idea. As I was saying, I'd like to rework it and doing this would
be useless once the rework is done.

> You're taking code, making sometimes copy-paste, for the berlin specific
> functions, and I think you're taking the bugs as well, which duplicates the fix
> effort.
> 
> For example, in nand_cmdfunc_berlin():
> +	if (info->reg_ndcr & NDCR_DWIDTH_M)
> +		column /= 2;
> 
> This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
> happens if the command is _not_ a read command, but an ONFI READID command
> (ONFI being specified by column=0x20 if memory serves me well).

In the Berlin specific cmdfunc we have ~10 lines copied from the others
cmd functions. That's not much. The pxa3xx driver is already factorized
and not a lot of functions are SoC-specific, except the cmdfunc which is
not that long. So you would want me to move all the driver to
mrvl-nand-lib and have a berlin_nand.c file with less than 100 lines
(i.e only its cmdfunc)? Thant would introduce small specific probing
functions and driver definitions and increase the code size, wouldn't
it?

> This is the reason I don't really like this patch. And this is also the reason
> why I believe you're in a perfect timing to improve things, by grouping the
> common function, and keeping the bugs in only one place, not many.

Well, I think that would not be the refactoring needed for this driver.

I may have been missing something. If so, please explain me which
code part is not factorized (except for the first 10 lines of the
cmd functions, which I can factorize if you really want it) and how the
driver would benefit from this?

Thanks,

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-17  9:52             ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-17  9:52 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: thomas.petazzoni, Boris Brezillon, Antoine Tenart, linux-kernel,
	zmxu, linux-mtd, ezequiel.garcia, jszhang, computersforpeace,
	dwmw2, linux-arm-kernel, sebastian.hesselbarth

Robert,

On Thu, Feb 12, 2015 at 05:26:20PM +0100, Robert Jarzmik wrote:
> Antoine Tenart <antoine.tenart@free-electrons.com> writes:
> 
> >> All these ifs per variant will add complexity to the current driver, won't they
> >> ?
> >
> > Given the current state of this driver I believe this would be a better
> > idea to first rework it to use the nand framework properly. Then it will
> > be possible to have a look on what we have, to decide whether or not a
> > mrvl-nand-lib is needed.
> 
> I don't fully agree to delay.

And sorry, but I don't think reworking the pxa3xx driver this way is a
good idea. As I was saying, I'd like to rework it and doing this would
be useless once the rework is done.

> You're taking code, making sometimes copy-paste, for the berlin specific
> functions, and I think you're taking the bugs as well, which duplicates the fix
> effort.
> 
> For example, in nand_cmdfunc_berlin():
> +	if (info->reg_ndcr & NDCR_DWIDTH_M)
> +		column /= 2;
> 
> This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
> happens if the command is _not_ a read command, but an ONFI READID command
> (ONFI being specified by column=0x20 if memory serves me well).

In the Berlin specific cmdfunc we have ~10 lines copied from the others
cmd functions. That's not much. The pxa3xx driver is already factorized
and not a lot of functions are SoC-specific, except the cmdfunc which is
not that long. So you would want me to move all the driver to
mrvl-nand-lib and have a berlin_nand.c file with less than 100 lines
(i.e only its cmdfunc)? Thant would introduce small specific probing
functions and driver definitions and increase the code size, wouldn't
it?

> This is the reason I don't really like this patch. And this is also the reason
> why I believe you're in a perfect timing to improve things, by grouping the
> common function, and keeping the bugs in only one place, not many.

Well, I think that would not be the refactoring needed for this driver.

I may have been missing something. If so, please explain me which
code part is not factorized (except for the first 10 lines of the
cmd functions, which I can factorize if you really want it) and how the
driver would benefit from this?

Thanks,

Antoine

-- 
Antoine Ténart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller
@ 2015-02-17  9:52             ` Antoine Tenart
  0 siblings, 0 replies; 84+ messages in thread
From: Antoine Tenart @ 2015-02-17  9:52 UTC (permalink / raw)
  To: linux-arm-kernel

Robert,

On Thu, Feb 12, 2015 at 05:26:20PM +0100, Robert Jarzmik wrote:
> Antoine Tenart <antoine.tenart@free-electrons.com> writes:
> 
> >> All these ifs per variant will add complexity to the current driver, won't they
> >> ?
> >
> > Given the current state of this driver I believe this would be a better
> > idea to first rework it to use the nand framework properly. Then it will
> > be possible to have a look on what we have, to decide whether or not a
> > mrvl-nand-lib is needed.
> 
> I don't fully agree to delay.

And sorry, but I don't think reworking the pxa3xx driver this way is a
good idea. As I was saying, I'd like to rework it and doing this would
be useless once the rework is done.

> You're taking code, making sometimes copy-paste, for the berlin specific
> functions, and I think you're taking the bugs as well, which duplicates the fix
> effort.
> 
> For example, in nand_cmdfunc_berlin():
> +	if (info->reg_ndcr & NDCR_DWIDTH_M)
> +		column /= 2;
> 
> This is I think a copy-paste from its twin nand_cmdfunc(). Now consider what
> happens if the command is _not_ a read command, but an ONFI READID command
> (ONFI being specified by column=0x20 if memory serves me well).

In the Berlin specific cmdfunc we have ~10 lines copied from the others
cmd functions. That's not much. The pxa3xx driver is already factorized
and not a lot of functions are SoC-specific, except the cmdfunc which is
not that long. So you would want me to move all the driver to
mrvl-nand-lib and have a berlin_nand.c file with less than 100 lines
(i.e only its cmdfunc)? Thant would introduce small specific probing
functions and driver definitions and increase the code size, wouldn't
it?

> This is the reason I don't really like this patch. And this is also the reason
> why I believe you're in a perfect timing to improve things, by grouping the
> common function, and keeping the bugs in only one place, not many.

Well, I think that would not be the refactoring needed for this driver.

I may have been missing something. If so, please explain me which
code part is not factorized (except for the first 10 lines of the
cmd functions, which I can factorize if you really want it) and how the
driver would benefit from this?

Thanks,

Antoine

-- 
Antoine T?nart, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2015-02-17  9:52 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-27 14:10 [PATCH 0/9] ARM: berlin: add nand support Antoine Tenart
2015-01-27 14:10 ` Antoine Tenart
2015-01-27 14:10 ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 1/9] mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0 Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 2/9] mtd: pxa3xx_nand: add a non mandatory ECC clock Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 15:50   ` Andrew Lunn
2015-01-27 15:50     ` Andrew Lunn
2015-01-27 15:50     ` Andrew Lunn
2015-01-28 14:14     ` Antoine Tenart
2015-01-28 14:14       ` Antoine Tenart
2015-01-28 14:14       ` Antoine Tenart
2015-02-08 19:55       ` Boris Brezillon
2015-02-08 19:55         ` Boris Brezillon
2015-02-08 19:55         ` Boris Brezillon
2015-01-28  3:35   ` Jisheng Zhang
2015-01-28  3:35     ` Jisheng Zhang
2015-01-28  3:35     ` Jisheng Zhang
2015-01-28 14:17     ` Antoine Tenart
2015-01-28 14:17       ` Antoine Tenart
2015-01-28 14:17       ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 3/9] mtd: pxa3xx_nand: set NDCR_PG_PER_BLK if page per block is 128 Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-02-08 20:00   ` Boris Brezillon
2015-02-08 20:00     ` Boris Brezillon
2015-02-08 20:00     ` Boris Brezillon
2015-01-27 14:10 ` [PATCH 4/9] mtd: pxa3xx_nand: add a default chunk size Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-02-08 20:15   ` Boris Brezillon
2015-02-08 20:15     ` Boris Brezillon
2015-02-08 20:15     ` Boris Brezillon
2015-02-08 20:18     ` Boris Brezillon
2015-02-08 20:18       ` Boris Brezillon
2015-02-08 20:18       ` Boris Brezillon
2015-01-27 14:10 ` [PATCH 5/9] mtd: pxa3xx_nand: add support for the Marvell Berlin nand controller Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:42   ` Ezequiel Garcia
2015-01-27 14:42     ` Ezequiel Garcia
2015-01-27 14:42     ` Ezequiel Garcia
2015-02-06  1:25     ` Brian Norris
2015-02-06  1:25       ` Brian Norris
2015-02-06  1:25       ` Brian Norris
2015-02-08 21:06   ` Boris Brezillon
2015-02-08 21:06     ` Boris Brezillon
2015-02-08 21:06     ` Boris Brezillon
2015-02-11 16:27     ` Antoine Tenart
2015-02-11 16:27       ` Antoine Tenart
2015-02-11 16:27       ` Antoine Tenart
2015-02-08 23:55   ` Boris Brezillon
2015-02-08 23:55     ` Boris Brezillon
2015-02-08 23:55     ` Boris Brezillon
2015-02-10 19:50     ` Robert Jarzmik
2015-02-10 19:50       ` Robert Jarzmik
2015-02-10 19:50       ` Robert Jarzmik
2015-02-11 16:33       ` Antoine Tenart
2015-02-11 16:33         ` Antoine Tenart
2015-02-11 16:33         ` Antoine Tenart
2015-02-12 16:26         ` Robert Jarzmik
2015-02-12 16:26           ` Robert Jarzmik
2015-02-12 16:26           ` Robert Jarzmik
2015-02-17  9:52           ` Antoine Tenart
2015-02-17  9:52             ` Antoine Tenart
2015-02-17  9:52             ` Antoine Tenart
2015-02-11 16:31     ` Antoine Tenart
2015-02-11 16:31       ` Antoine Tenart
2015-02-11 16:31       ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 6/9] Documentation: bindings: add the Berlin nand controller compatible Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 7/9] mtd: nand: let Marvell Berlin SoCs select the pxa3xx driver Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 8/9] ARM: berlin: add BG2Q node for the nand Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10 ` [PATCH 9/9] ARM: berlin: enable flash on the BG2Q DMP Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart
2015-01-27 14:10   ` Antoine Tenart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.