lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Connecting external raw nand using GPIO - RPI3b

Thu Jul 12, 2018 12:10 pm

Hi.

I'm trying to define a device tree for connecting an external raw NAND using GPIO on RPI3. I found that there are available drivers, and I found an example in the sources' "Documentation" directory (Documentation/devicetree/bindings/mtd/gpio-control-nand.txt) Yet, while using this example, I couldn't find how to define the banka label that appears there, and although DTB compilation doesn't fail, when trying to load the device tree (using dtoverlay command) it fails to load with issue on this banka component. I found a banka declaration on pichochip dts file, but it when trying to copy it to my dts, it doesn't compile. Moreover, I couldn't find how am I suppose to connect the RAW NAND to the GPIO connectors, which pins to use (specifically the data/address pins, which are supposed to be "address mapped").

Can any one point to a solution for that? I am struggling this issue for a couple of days now...

Thanks.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1914
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Connecting external raw nand using GPIO - RPI3b

Thu Jul 12, 2018 2:02 pm

The exact form of a gpio declaration is system-specific. But the first term is a reference to a label in the Device Tree, where the label is meant to be attached to a GPIO controller. On Raspberry Pi devices the main user-accessible GPIOs (the ones on the 40-pin header) are provided by a DT node with the label "gpio" and a compatible string of "brcm,bcm2835-gpio". The file "Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt" says:
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify optional parameters:
- bit 0 specifies polarity (0 for normal, 1 for inverted)
This means that unless you want an active-low output then your gpio reference should look like "<&gpio gpio-number 0>", where "gpio-number" is replaced with the number of the GPIO in the Broadcom numbering scheme (not the header pin number, or any other pseudo-helpful scheme). "<0>" is used to indicate an absent signal - some of them are optional.

Unfortunately I'm not sure how you would be able to provide the "address mapped" I/O port to read from and write to the NAND. I think the idea is that a small (byte wide?) register in your device reads/writes the state of 8/16 pins that can be wired to the device. By configuring the address of that register in Device Tree you can avoid writing a device-specific driver. However, I don't think there is such a port in the Raspberry Pi. In a sense the GPIO controller could be thought of in that way, but it would need some configuration beforehand and a read/modify/write sequence to write less than 32-bits at once.

Are there no I2C- or SPI-addressable devices that would do what you want?

lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Re: Connecting external raw nand using GPIO - RPI3b

Sun Jul 15, 2018 8:20 am

Thanks Phil for you reply.
Reading deeper into BCM2835 datasheet shows that some of the GPIO pins may be configured to Secondary Module Interface, and the example in "Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt" specifically mentions the use for NAND.
Wouldn't that answer my issue?

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1914
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 8:39 am

I have been only dimly aware of SMI - I've used I2C, SPI, SD, but not SMI - so when you mentioned NAND I didn't immediately think of it. But yes - the BCM2835 has an SMI interface, and there is a driver and overlay for it in the RPi kernel trees. There is also a NAND adaptation layer driver and overlay.

Note that the generic SMI overlay tries to claim GPIOs 2-25, while the SMI NAND overlays wants GPIOs 0-15 for an 8-bit data bus.

There isn't a lot of documentation available, but have a read through this thread and I'll try to answer any questions you have.

lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 9:43 am

Thanks again for your help.
I did notice that there is that smi-nand ovleray and went through the thread you mentioned. Unfortunately, the thread hardly mentions the nand issue, so I couldn't find any help there. The only thing I could get from there, is that looks like I need to load both smi overlay and smi-nand overlay, which sounds quiet weird. I though only nand-smi is to be used.

Moreover, Looking at the pinout connectivity of ALT2 (https://elinux.org/RPi_BCM2835_GPIOs), I couldn't understand the correct physical connection.
The only signals I could be sure to connect are OE/RE to J8-31 and WE to J8-26.
The nand uses the same pins both for address and for data, so I guess that would be on SD0-SD7 (since SAx is only available up to SA5).
So I am missing the connectivity for the rest of the signals: CLE, ALE, R_B and CE. Is there anyway to understand what is connected where, according to the driver/device tree?

Thanks, again, for you major help.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1914
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 10:00 am

The post is a bit ambiguous, but the smi-nand overlay (at least as it is now) is standalone.

I don't know whether the SMI interface can multiplex address and data on the same lines - that's clearly not the way this overlay is expected to be used. I've pinged LukeW, the author of the driver, in case he has any insights or suggestions.

lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 10:28 am

Address and Data are multiplexed on NAND device, That is how NAND works. The main issue is that it should support both output and input.
Is there any 'thumb-rule' where I can find how to connect the RPI3 headers pin? How can I find each pins' connectivity, from the smi-nand driver?

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1914
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 10:40 am

The GPIO alternate function assignments are listed on page 102 of the BCM2835 ARM Peripherals guide.

lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Re: Connecting external raw nand using GPIO - RPI3b

Mon Jul 16, 2018 11:01 am

I know that guide, but on ALT1, which is the relevant assignment for the SMI-NAND, GPIO-GPIO, are called SA5-SA0, while it should have CE, R/B ALE, CLE ext.

I noticed, on the driver code, the following defines:
#define SMI_NAND_CLE_PIN 0x01
#define SMI_NAND_ALE_PIN 0x02

and I wonder does these pins are GPIO1 and GPIO2?

User avatar
LukeW
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7
Joined: Tue Jul 07, 2015 2:19 pm

Re: Connecting external raw nand using GPIO - RPI3b

Wed Jul 18, 2018 6:09 pm

SMI has a 6 bit "address" bus (SA0 to SA5), which I think is misnamed. These pins idle high in between transactions, and seem to be useful mainly for enables, not addresses. This is what they are used for in the SMI NAND driver, which is a small shim sitting between Linux's MTD (NAND) stack and the SMI driver.

If you look a little below those lines you picked out:

Code: Select all

static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
					     unsigned int ctrl)
{
	uint32_t cmd32 = cmd;
	uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
	struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
	struct bcm2835_smi_instance *inst = host->smi_inst;

	if (ctrl & NAND_CLE)
		addr |= SMI_NAND_CLE_PIN;
	if (ctrl & NAND_ALE)
		addr |= SMI_NAND_ALE_PIN;
	/* Lower ALL the CS pins! */
	if (ctrl & NAND_NCE)
		addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);

	bcm2835_smi_set_address(inst, addr);

	if (cmd != NAND_CMD_NONE)
		bcm2835_smi_write_buf(inst, &cmd32, 1);
}
This is a function which takes a command from the MTD driver stack, and carries that command out via SMI. Those constants you saw aren't pin numbers, but bit flags which are used to build the SMI "address".

So you need to wire the NAND CLE to the SA0 pin (0x1 == 1 << 0), and the NAND ALE to the SA1 pin (0x2 == 1 << 1).

lioryb
Posts: 8
Joined: Thu Jul 12, 2018 11:02 am

Re: Connecting external raw nand using GPIO - RPI3b

Thu Jul 19, 2018 7:28 am

Thank you Luke for you reply.

So, I understand SA0-SA5 are actually used for all the NAND controls? where can I find the CE and R_B conrols?

I am experiencing a few more issues with the driver, and I would be thankful if you could help.


when I add the SMI-NAND overlay, w
Apparently, in bcm2835_smi_nand_probe, there is a call:

Code: Select all

	this = &host->nand_chip;
	mtd = &host->mtd;
	
	...
	
	this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
	
	...

	/* First scan to find the device and get the page size */
	if (nand_scan_ident(mtd, 1, NULL))
		return -ENXIO;
and in this nand_scan_ident function:

Code: Select all

int nand_scan_ident(struct mtd_info *mtd, int maxchips,
		    struct nand_flash_dev *table)
{
	int i, nand_maf_id, nand_dev_id;
	struct nand_chip *chip = mtd_to_nand(mtd);
	int ret;

	ret = nand_dt_init(chip);
	if (ret)
		return ret;

	if (!mtd->name && mtd->dev.parent)
		mtd->name = dev_name(mtd->dev.parent);

	if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
		/*
		 * Default functions assigned for chip_select() and
		 * cmdfunc() both expect cmd_ctrl() to be populated,
		 * so we need to check that that's the case
		 */
		pr_err("chip.cmd_ctrl() callback is not provided");
		return -EINVAL;
	}
And the load fails with this error where the callback is not provided.

I think that the issue is with

Code: Select all

mtd = &host->mtd;
and it should actually be:

Code: Select all

mtd = nand_to_mtd(this);
Am I correct?
Thanks in advance

TheNoOne
Posts: 5
Joined: Fri Sep 14, 2018 7:28 pm

Re: Connecting external raw nand using GPIO - RPI3b

Sat Sep 22, 2018 8:39 pm

Hi, I'm also trying to get this working. Currently I have a Waveshare NandFlash Board (https://www.waveshare.com/wiki/NandFlash_Board_(A)) which contains a K9F1G08U0E 128MB Chip with a nice header to connect to the Pi 1B+ and above. The pins are mapped as follows:

Code: Select all

NAND    <=> RaspberryPi (GPIO)
------------------------------
GND,VCC <=> GND,3.3V
D0-D7   <=> SD0-SD7 (8-15)
CLE     <=> SA0 (5)
ALE     <=> SA1 (4)
WE      <=> SWE_N (7)
RE      <=> SOE_N (6)
CE      <=> GND
R_B     <=> not connected

config.txt contains only one line:

Code: Select all

dtoverlay=smi-nand

After testing some older kernel versions I noticed that the NAND chip is detected in 4.4.50, but not working in 4.9.11 and above. There is a callback function missing in the bcm2835_smi_nand driver. But theres an even bigger problem: all erase blocks are detected as bad. Anybody know why?

Code: Select all

[    0.000000] Linux version 4.9.11+ ([email protected]) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #971 Mon Feb 20 20:40:26 GMT 2017
...
[    9.765751] smi-bcm2835 20600000.smi: initialised
[   10.157228] nand: chip.cmd_ctrl() callback is not provided
...

Code: Select all

[    0.000000] Linux version 4.4.50+ ([email protected]) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #970 Mon Feb 20 19:12:50 GMT 2017
...
[   11.357678] nand: device found, Manufacturer ID: 0xec, Chip ID: 0xf1
[   11.357716] nand: Samsung NAND 128MiB 3,3V 8-bit
[   11.357732] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[   11.357773] Scanning device for bad blocks
[   11.357839] Bad eraseblock 0 at 0x000000000000
[   11.357886] Bad eraseblock 1 at 0x000000020000
[   11.357934] Bad eraseblock 2 at 0x000000040000
[   11.357977] Bad eraseblock 3 at 0x000000060000
[   11.358023] Bad eraseblock 4 at 0x000000080000
[   11.358066] Bad eraseblock 5 at 0x0000000a0000
[   11.358109] Bad eraseblock 6 at 0x0000000c0000
[   11.358154] Bad eraseblock 7 at 0x0000000e0000
...
Last edited by TheNoOne on Sun Sep 23, 2018 4:53 pm, edited 1 time in total.

TheNoOne
Posts: 5
Joined: Fri Sep 14, 2018 7:28 pm

Re: Connecting external raw nand using GPIO - RPI3b

Sun Sep 23, 2018 5:43 am

Maybe this commit is required, but the current raspberry kernel is too old: https://github.com/torvalds/linux/commi ... fb7d54f18c
I'll try to compile my own kernel!

TheNoOne
Posts: 5
Joined: Fri Sep 14, 2018 7:28 pm

Re: Connecting external raw nand using GPIO - RPI3b

Fri Oct 26, 2018 8:35 pm

I'm now running 4.19 from https://github.com/raspberrypi/firmware ... f31b58b8ae which should now contain support for the K9F1G08U0E (https://github.com/raspberrypi/linux/bl ... ung.c#L103), but I'm still out of luck.

I patched bcm2835_smi_nand.c using the following patch and did an insmod of the new module file:

Code: Select all

diff --git a/drivers/mtd/nand/raw/bcm2835_smi_nand.c b/drivers/mtd/nand/raw/bcm2835_smi_nand.c
index 78dc4fcc7..5a2374dc3 100644
--- a/drivers/mtd/nand/raw/bcm2835_smi_nand.c
+++ b/drivers/mtd/nand/raw/bcm2835_smi_nand.c
@@ -50,10 +50,18 @@
 struct bcm2835_smi_nand_host {
 	struct bcm2835_smi_instance *smi_inst;
 	struct nand_chip nand_chip;
-	struct mtd_info mtd;
 	struct device *dev;
 };
 
+static const struct mtd_partition partition_info[] = {
+  [0] = {
+		.name	= "bcm2835-smi-nand-0",
+		.offset	= 0,
+		.size	= MTDPART_SIZ_FULL
+  }
+};
+#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
+
 /****************************************************************************
 *
 *   NAND functionality implementation
@@ -135,10 +143,8 @@ static int bcm2835_smi_nand_probe(struct platform_device *pdev)
 	struct mtd_info *mtd;
 	struct device *dev = &pdev->dev;
 	struct device_node *node = dev->of_node, *smi_node;
-	struct mtd_part_parser_data ppdata;
 	struct smi_settings *smi_settings;
 	struct bcm2835_smi_instance *smi_inst;
-	int ret = -ENXIO;
 
 	if (!node) {
 		dev_err(dev, "No device tree node supplied!");
@@ -185,8 +191,7 @@ static int bcm2835_smi_nand_probe(struct platform_device *pdev)
 	/* Link the structures together */
 
 	this = &host->nand_chip;
-	mtd = &host->mtd;
-	mtd->priv = this;
+	mtd = nand_to_mtd(this);
 	mtd->owner = THIS_MODULE;
 	mtd->dev.parent = dev;
 	mtd->name = DRIVER_NAME;
@@ -194,7 +199,6 @@ static int bcm2835_smi_nand_probe(struct platform_device *pdev)
 	/* 20 us command delay time... */
 	this->chip_delay = 20;
 
-	this->priv = host;
 	this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
 	this->read_byte = bcm2835_smi_nand_read_byte;
 	this->write_byte = bcm2835_smi_nand_write_byte;
@@ -202,6 +206,7 @@ static int bcm2835_smi_nand_probe(struct platform_device *pdev)
 	this->read_buf = bcm2835_smi_nand_read_buf;
 
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	/* Should never be accessed directly: */
 
@@ -213,15 +218,15 @@ static int bcm2835_smi_nand_probe(struct platform_device *pdev)
 	if (nand_scan(mtd, 1))
 		return -ENXIO;
 
-	nand_release(mtd);
-	return -EINVAL;
+	mtd_device_register(mtd, partition_info, NUM_PARTITIONS);
+	return 0;
 }
 
 static int bcm2835_smi_nand_remove(struct platform_device *pdev)
 {
 	struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
 
-	nand_release(&host->mtd);
+	nand_release(nand_to_mtd(&host->nand_chip));
 
 	return 0;
 }

But it is still returning all blocks as bad:

Code: Select all

[ 1178.690227] nand: device found, Manufacturer ID: 0xec, Chip ID: 0xf1
[ 1178.690249] nand: Samsung NAND 128MiB 3,3V 8-bit
[ 1178.690262] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 1178.690295] Scanning device for bad blocks
[ 1178.690362] Bad eraseblock 0 at 0x000000000000
[ 1178.690413] Bad eraseblock 1 at 0x000000020000
[ 1178.690457] Bad eraseblock 2 at 0x000000040000
...
[ 1178.735415] Bad eraseblock 1021 at 0x000007fa0000
[ 1178.735458] Bad eraseblock 1022 at 0x000007fc0000
[ 1178.735500] Bad eraseblock 1023 at 0x000007fe0000
[ 1178.871318] Creating 1 MTD partitions on "smi-nand-bcm2835":
[ 1178.871363] 0x000000000000-0x000008000000 : "bcm2835-smi-nand-0"

I also tried patching nand_samsung.c by disabling bad block scanning:

Code: Select all

diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
index ef022f62f..acc61378a 100644
--- a/drivers/mtd/nand/raw/nand_samsung.c
+++ b/drivers/mtd/nand/raw/nand_samsung.c
@@ -105,6 +105,7 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
 				if (chip->id.len > 4 &&
 				    (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
 					chip->options |= NAND_NO_SUBPAGE_WRITE;
+					chip->options |= NAND_SKIP_BBTSCAN;
 				break;
 			default:
 				break;

Code: Select all

[ 1326.148649] nand: device found, Manufacturer ID: 0xec, Chip ID: 0xf1
[ 1326.148671] nand: Samsung NAND 128MiB 3,3V 8-bit
[ 1326.148685] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 1326.166529] Creating 1 MTD partitions on "smi-nand-bcm2835":
[ 1326.166568] 0x000000000000-0x000008000000 : "bcm2835-smi-nand-0"

But this shifts the problem only a layer up to ubiformat:

Code: Select all

[email protected]:~ $ sudo ubiformat -v /dev/mtd0
ubiformat: mtd0 (nand), size 134217728 bytes (128.0 MiB), 1024 eraseblocks of 131072 bytes (128.0 KiB), min. I/O size 2048 bytes
libscan: start scanning eraseblocks 0-1024
libscan: scanning eraseblock 0: bad
...
libscan: scanning eraseblock 352: bad
libscan: scanning eraseblock 353: bad
libscan: scanning eraseblock 354: alien
:x

Anybody else having more luck experimenting with bcm2835-smi-nand?

gorgias
Posts: 1
Joined: Fri Oct 19, 2018 12:46 pm

Re: Connecting external raw nand using GPIO - RPI3b

Sat Oct 27, 2018 5:21 pm

How did you know the correspondence between GPIO pins and NAND pins?
What I see in smi-nand-overlay.dts is only these. I didn't know which is IO0-7 and which is read_busy.

Code: Select all

brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
Could you tell me? if possible.

TheNoOne
Posts: 5
Joined: Fri Sep 14, 2018 7:28 pm

Re: Connecting external raw nand using GPIO - RPI3b

Mon Oct 29, 2018 7:46 pm

PhilE wrote:
Mon Jul 16, 2018 10:40 am
The GPIO alternate function assignments are listed on page 102 of the BCM2835 ARM Peripherals guide.
I did just lookup this reference.

http://datasheetcafe.databank.netdna-cd ... Pinout.gif
nandpi.png
nandpi.png (164.97 KiB) Viewed 1736 times

TheNoOne
Posts: 5
Joined: Fri Sep 14, 2018 7:28 pm

Re: Connecting external raw nand using GPIO - RPI3b

Sun Nov 04, 2018 3:58 pm

I've tried everything on a 3B and I got strange results:

Code: Select all

Nov  2 11:57:41 nand3pi kernel: [ 2395.558265] nand: second ID read did not match ec,f1 against ec,00
Nov  2 11:57:41 nand3pi kernel: [ 2395.558282] nand: No NAND device found

Nov  2 11:58:35 nand3pi kernel: [ 2449.563278] nand: second ID read did not match ec,f1 against ec,ec
Nov  2 11:58:35 nand3pi kernel: [ 2449.563294] nand: No NAND device found
I'll hook up a logic analyzer to see whats going on!

I've also tried reading the Waveshare board using NANDway from https://github.com/hjudges/NORway which works fine btw.

Return to “Device Tree”