diff mbox

[U-Boot,v2,09/14] fastboot: Implement NAND backend

Message ID 1444912462-3949-10-git-send-email-maxime.ripard@free-electrons.com
State Accepted
Delegated to: Tom Rini
Headers show

Commit Message

Maxime Ripard Oct. 15, 2015, 12:34 p.m. UTC
So far the fastboot code was only supporting MMC-backed devices for its
flashing operations (flash and erase).

Add a storage backend for NAND-backed devices.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 common/Makefile                 |   7 +-
 common/fb_nand.c                | 195 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/f_fastboot.c |  13 ++-
 include/fb_nand.h               |  11 +++
 4 files changed, 224 insertions(+), 2 deletions(-)
 create mode 100644 common/fb_nand.c
 create mode 100644 include/fb_nand.h

Comments

Tom Rini Oct. 20, 2015, 7:46 p.m. UTC | #1
On Thu, Oct 15, 2015 at 02:34:17PM +0200, Maxime Ripard wrote:

> So far the fastboot code was only supporting MMC-backed devices for its
> flashing operations (flash and erase).
> 
> Add a storage backend for NAND-backed devices.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

This is mutually exclusive with MMC support, right?  If so, it's not
quite written that way in the #ifdef's so I think it need to be down in
say:

> @@ -569,6 +572,11 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
>  			   (void *)CONFIG_FASTBOOT_BUF_ADDR,
>  			   download_bytes, response);
>  #endif
> +#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
> +	fb_nand_flash_write(cmd, fastboot_flash_session_id,
> +			    (void *)CONFIG_FASTBOOT_BUF_ADDR,
> +			    download_bytes, response);
> +#endif

With #elif/#error "Fastboot enabled but without any backing store
support" and we drop the #error once this is Kconfig'zied.
Maxime Ripard Oct. 21, 2015, 2:57 p.m. UTC | #2
Hi Tom,

On Tue, Oct 20, 2015 at 03:46:36PM -0400, Tom Rini wrote:
> On Thu, Oct 15, 2015 at 02:34:17PM +0200, Maxime Ripard wrote:
> 
> > So far the fastboot code was only supporting MMC-backed devices for its
> > flashing operations (flash and erase).
> > 
> > Add a storage backend for NAND-backed devices.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> This is mutually exclusive with MMC support, right?  If so, it's not
> quite written that way in the #ifdef's so I think it need to be down in
> say:
> 
> > @@ -569,6 +572,11 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
> >  			   (void *)CONFIG_FASTBOOT_BUF_ADDR,
> >  			   download_bytes, response);
> >  #endif
> > +#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
> > +	fb_nand_flash_write(cmd, fastboot_flash_session_id,
> > +			    (void *)CONFIG_FASTBOOT_BUF_ADDR,
> > +			    download_bytes, response);
> > +#endif
> 
> With #elif/#error "Fastboot enabled but without any backing store
> support" and we drop the #error once this is Kconfig'zied.

We said in the precedent version that the end goal would be to support
both at the same time, if relevant.

I was willing to treat that as a followup patch, but I guess I should
do as you suggest for the time being.

Thanks!
Maxime
Tom Rini Oct. 21, 2015, 8:49 p.m. UTC | #3
On Wed, Oct 21, 2015 at 04:57:04PM +0200, Maxime Ripard wrote:
> Hi Tom,
> 
> On Tue, Oct 20, 2015 at 03:46:36PM -0400, Tom Rini wrote:
> > On Thu, Oct 15, 2015 at 02:34:17PM +0200, Maxime Ripard wrote:
> > 
> > > So far the fastboot code was only supporting MMC-backed devices for its
> > > flashing operations (flash and erase).
> > > 
> > > Add a storage backend for NAND-backed devices.
> > > 
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > 
> > This is mutually exclusive with MMC support, right?  If so, it's not
> > quite written that way in the #ifdef's so I think it need to be down in
> > say:
> > 
> > > @@ -569,6 +572,11 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
> > >  			   (void *)CONFIG_FASTBOOT_BUF_ADDR,
> > >  			   download_bytes, response);
> > >  #endif
> > > +#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
> > > +	fb_nand_flash_write(cmd, fastboot_flash_session_id,
> > > +			    (void *)CONFIG_FASTBOOT_BUF_ADDR,
> > > +			    download_bytes, response);
> > > +#endif
> > 
> > With #elif/#error "Fastboot enabled but without any backing store
> > support" and we drop the #error once this is Kconfig'zied.
> 
> We said in the precedent version that the end goal would be to support
> both at the same time, if relevant.
> 
> I was willing to treat that as a followup patch, but I guess I should
> do as you suggest for the time being.

Yeah, we want to make sure that until it's supported it can't be
configured to try and do it.
Tom Rini Nov. 13, 2015, 1:27 a.m. UTC | #4
On Thu, Oct 15, 2015 at 02:34:17PM +0200, Maxime Ripard wrote:

> So far the fastboot code was only supporting MMC-backed devices for its
> flashing operations (flash and erase).
> 
> Add a storage backend for NAND-backed devices.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Applied to u-boot/master, thanks!
diff mbox

Patch

diff --git a/common/Makefile b/common/Makefile
index 491c56552f40..4f6e6cea596b 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -274,10 +274,15 @@  obj-y += memsize.o
 obj-y += stdio.o
 
 # This option is not just y/n - it can have a numeric value
-ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+ifdef CONFIG_FASTBOOT_FLASH
 obj-y += aboot.o
+ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
 obj-y += fb_mmc.o
 endif
+ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
+obj-y += fb_nand.o
+endif
+endif
 
 obj-$(CONFIG_CMD_BLOB) += cmd_blob.o
 
diff --git a/common/fb_nand.c b/common/fb_nand.c
new file mode 100644
index 000000000000..1c80ba9edabc
--- /dev/null
+++ b/common/fb_nand.c
@@ -0,0 +1,195 @@ 
+/*
+ * Copyright 2014 Broadcom Corporation.
+ * Copyright 2015 Free Electrons.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+
+#include <aboot.h>
+#include <fastboot.h>
+#include <sparse_format.h>
+
+#include <linux/mtd/mtd.h>
+#include <jffs2/jffs2.h>
+#include <nand.h>
+
+static char *response_str;
+
+struct fb_nand_sparse {
+	nand_info_t		*nand;
+	struct part_info	*part;
+};
+
+static int fb_nand_lookup(const char *partname, char *response,
+			  nand_info_t **nand,
+			  struct part_info **part)
+{
+	struct mtd_device *dev;
+	int ret;
+	u8 pnum;
+
+	ret = mtdparts_init();
+	if (ret) {
+		error("Cannot initialize MTD partitions\n");
+		fastboot_fail(response_str, "cannot init mtdparts");
+		return ret;
+	}
+
+	ret = find_dev_and_part(partname, &dev, &pnum, part);
+	if (ret) {
+		error("cannot find partition: '%s'", partname);
+		fastboot_fail(response_str, "cannot find partition");
+		return ret;
+	}
+
+	if (dev->id->type != MTD_DEV_TYPE_NAND) {
+		error("partition '%s' is not stored on a NAND device",
+		      partname);
+		fastboot_fail(response_str, "not a NAND device");
+		return -EINVAL;
+	}
+
+	*nand = &nand_info[dev->id->num];
+
+	return 0;
+}
+
+static int _fb_nand_erase(nand_info_t *nand, struct part_info *part)
+{
+	nand_erase_options_t opts;
+	int ret;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.offset = part->offset;
+	opts.length = part->size;
+	opts.quiet = 1;
+
+	printf("Erasing blocks 0x%llx to 0x%llx\n",
+	       part->offset, part->offset + part->size);
+
+	ret = nand_erase_opts(nand, &opts);
+	if (ret)
+		return ret;
+
+	printf("........ erased 0x%llx bytes from '%s'\n",
+	       part->size, part->name);
+
+	return 0;
+}
+
+static int _fb_nand_write(nand_info_t *nand, struct part_info *part,
+			  void *buffer, unsigned int offset,
+			  unsigned int length, size_t *written)
+{
+	int flags = WITH_WR_VERIFY;
+
+#ifdef CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS
+	flags |= WITH_DROP_FFS;
+#endif
+
+	return nand_write_skip_bad(nand, offset, &length, written,
+				   part->size - (offset - part->offset),
+				   buffer, flags);
+}
+
+static int fb_nand_sparse_write(struct sparse_storage *storage,
+				void *priv,
+				unsigned int offset,
+				unsigned int size,
+				char *data)
+{
+	struct fb_nand_sparse *sparse = priv;
+	size_t written;
+	int ret;
+
+	ret = _fb_nand_write(sparse->nand, sparse->part, data,
+			     offset * storage->block_sz,
+			     size * storage->block_sz, &written);
+	if (ret < 0) {
+		printf("Failed to write sparse chunk\n");
+		return ret;
+	}
+
+	return written / storage->block_sz;
+}
+
+void fb_nand_flash_write(const char *partname, unsigned int session_id,
+			 void *download_buffer, unsigned int download_bytes,
+			 char *response)
+{
+	struct part_info *part;
+	nand_info_t *nand = NULL;
+	int ret;
+
+	/* initialize the response buffer */
+	response_str = response;
+
+	ret = fb_nand_lookup(partname, response, &nand, &part);
+	if (ret) {
+		error("invalid NAND device");
+		fastboot_fail(response_str, "invalid NAND device");
+		return;
+	}
+
+	if (is_sparse_image(download_buffer)) {
+		struct fb_nand_sparse sparse_priv;
+		sparse_storage_t sparse;
+
+		sparse_priv.nand = nand;
+		sparse_priv.part = part;
+
+		sparse.block_sz = nand->writesize;
+		sparse.start = part->offset / sparse.block_sz;
+		sparse.size = part->size  / sparse.block_sz;
+		sparse.name = part->name;
+		sparse.write = fb_nand_sparse_write;
+
+		ret = store_sparse_image(&sparse, &sparse_priv, session_id,
+					 download_buffer);
+	} else {
+		printf("Flashing raw image at offset 0x%llx\n",
+		       part->offset);
+
+		ret = _fb_nand_write(nand, part, download_buffer, part->offset,
+				     download_bytes, NULL);
+
+		printf("........ wrote %u bytes to '%s'\n",
+		       download_bytes, part->name);
+	}
+
+	if (ret) {
+		fastboot_fail(response_str, "error writing the image");
+		return;
+	}
+
+	fastboot_okay(response_str, "");
+}
+
+void fb_nand_erase(const char *partname, char *response)
+{
+	struct part_info *part;
+	nand_info_t *nand = NULL;
+	int ret;
+
+	/* initialize the response buffer */
+	response_str = response;
+
+	ret = fb_nand_lookup(partname, response, &nand, &part);
+	if (ret) {
+		error("invalid NAND device");
+		fastboot_fail(response_str, "invalid NAND device");
+		return;
+	}
+
+	ret = _fb_nand_erase(nand, part);
+	if (ret) {
+		error("failed erasing from device %s", nand->name);
+		fastboot_fail(response_str, "failed erasing from device");
+		return;
+	}
+
+	fastboot_okay(response_str, "");
+}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 9af0372007bb..20b6c18b9cfd 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -24,6 +24,9 @@ 
 #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
 #include <fb_mmc.h>
 #endif
+#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
+#include <fb_nand.h>
+#endif
 
 #define FASTBOOT_VERSION		"0.4"
 
@@ -569,6 +572,11 @@  static void cb_flash(struct usb_ep *ep, struct usb_request *req)
 			   (void *)CONFIG_FASTBOOT_BUF_ADDR,
 			   download_bytes, response);
 #endif
+#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
+	fb_nand_flash_write(cmd, fastboot_flash_session_id,
+			    (void *)CONFIG_FASTBOOT_BUF_ADDR,
+			    download_bytes, response);
+#endif
 	fastboot_flash_session_id++;
 	fastboot_tx_write_str(response);
 }
@@ -577,7 +585,7 @@  static void cb_flash(struct usb_ep *ep, struct usb_request *req)
 static void cb_oem(struct usb_ep *ep, struct usb_request *req)
 {
 	char *cmd = req->buf;
-#ifdef CONFIG_FASTBOOT_FLASH
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
 	if (strncmp("format", cmd + 4, 6) == 0) {
 		char cmdbuf[32];
                 sprintf(cmdbuf, "gpt write mmc %x $partitions",
@@ -614,6 +622,9 @@  static void cb_erase(struct usb_ep *ep, struct usb_request *req)
 #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
 	fb_mmc_erase(cmd, response);
 #endif
+#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
+	fb_nand_erase(cmd, response);
+#endif
 	fastboot_tx_write_str(response);
 }
 #endif
diff --git a/include/fb_nand.h b/include/fb_nand.h
new file mode 100644
index 000000000000..80ddef5656a8
--- /dev/null
+++ b/include/fb_nand.h
@@ -0,0 +1,11 @@ 
+/*
+ * Copyright 2014 Broadcom Corporation.
+ * Copyright 2015 Free Electrons.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void fb_nand_flash_write(const char *cmd, unsigned int session_id,
+			 void *download_buffer, unsigned int download_bytes,
+			 char *response);
+void fb_nand_erase(const char *cmd, char *response);