From fd0007a9efb34e924465ddb981e61e1fe5d55100 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 05:57:27 +0200 Subject: [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB Due to the DBBT, multiple FCBs, two bootloaders and the possibility of bad blocks the bootloader partition needs more space. Increase it to 4MB. Signed-off-by: Sascha Hauer --- arch/arm/dts/imx6dl-tx6u-801x.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/imx6dl-tx6u-801x.dts b/arch/arm/dts/imx6dl-tx6u-801x.dts index 43104b2b8..a480408f5 100644 --- a/arch/arm/dts/imx6dl-tx6u-801x.dts +++ b/arch/arm/dts/imx6dl-tx6u-801x.dts @@ -18,12 +18,12 @@ &gpmi { partition@0 { label = "barebox"; - reg = <0x0 0x100000>; + reg = <0x0 0x400000>; }; partition@1 { label = "barebox-environment"; - reg = <0x100000 0x100000>; + reg = <0x400000 0x100000>; }; }; From ff40732d0adfba399a3a2914d347a85c24fbf461 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 11 Jun 2015 15:45:56 +0200 Subject: [PATCH 02/10] mtd: partition: implement write_oob To enable mtd_write_oob for partitions. Signed-off-by: Sascha Hauer --- drivers/mtd/partition.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index 98b90819b..c11a3db1c 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -31,6 +31,16 @@ static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, len, retlen, buf); } +static int mtd_part_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + if (to >= mtd->size) + return -EINVAL; + if (ops->datbuf && to + ops->len > mtd->size) + return -EINVAL; + return mtd->master->write_oob(mtd->master, to + mtd->master_offset, ops); +} + static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) { int ret; @@ -160,6 +170,9 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; } + if (mtd->write_oob) + part->write_oob = mtd_part_write_oob; + part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; part->size = size; part->name = xstrdup(name); From e7b23c6a9df57b5c8bba4fa9c10f8b5f793745cc Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 10 Jun 2015 15:04:20 +0200 Subject: [PATCH 03/10] filetype: Add filetype for MXS bootstream Signed-off-by: Sascha Hauer --- common/filetype.c | 3 +++ include/filetype.h | 1 + 2 files changed, 4 insertions(+) diff --git a/common/filetype.c b/common/filetype.c index 25d97614e..28a4b2ca2 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -60,6 +60,7 @@ static const struct filetype_str filetype_str[] = { "TI OMAP CH boot image (big endian)", "ch-image-be" }, [filetype_xz_compressed] = { "XZ compressed", "xz" }, [filetype_exe] = { "MS-DOS executable", "exe" }, + [filetype_mxs_bootstream] = { "Freescale MXS bootstream", "mxsbs" }, }; const char *file_type_to_string(enum filetype f) @@ -292,6 +293,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize) if (buf8[0] == 'M' && buf8[1] == 'Z') return filetype_exe; + if (le32_to_cpu(buf[5]) == 0x504d5453) + return filetype_mxs_bootstream; if (is_barebox_arm_head(_buf)) return filetype_arm_barebox; diff --git a/include/filetype.h b/include/filetype.h index cca4dad7f..e452b7ac9 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -34,6 +34,7 @@ enum filetype { filetype_ch_image_be, filetype_exe, filetype_xz_compressed, + filetype_mxs_bootstream, filetype_max, }; From a10366acd8e509cb65c8645775325c882ba5a55a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 06:07:32 +0200 Subject: [PATCH 04/10] ARM: i.MX6: bbu nand: Move to common place The code can be used on i.MX28 aswell, so move it to a common place. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/Kconfig | 9 --------- arch/arm/mach-imx/Makefile | 1 - arch/arm/mach-imx/include/mach/bbu.h | 9 --------- common/Kconfig | 8 ++++++++ common/Makefile | 1 + .../imx6-bbu-nand.c => common/imx-bbu-nand-fcb.c | 0 include/bbu.h | 9 +++++++++ 7 files changed, 18 insertions(+), 19 deletions(-) rename arch/arm/mach-imx/imx6-bbu-nand.c => common/imx-bbu-nand-fcb.c (100%) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c71347770..812a9f9ec 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -112,15 +112,6 @@ config BAREBOX_UPDATE_IMX_EXTERNAL_NAND depends on MTD_WRITE default y -config BAREBOX_UPDATE_IMX6_NAND - bool - depends on ARCH_IMX6 - depends on BAREBOX_UPDATE - depends on MTD - depends on MTD_WRITE - depends on NAND_MXS - default y - comment "Freescale i.MX System-on-Chip" config ARCH_IMX1 diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index ae953b1bf..0c8ca4b9d 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -21,6 +21,5 @@ obj-y += devices.o imx.o esdctl.o obj-y += boot.o obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o -obj-$(CONFIG_BAREBOX_UPDATE_IMX6_NAND) += imx6-bbu-nand.o pbl-y += esdctl.o lwl-y += cpu_init.o diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h index 5eb9a4736..803909139 100644 --- a/arch/arm/mach-imx/include/mach/bbu.h +++ b/arch/arm/mach-imx/include/mach/bbu.h @@ -75,15 +75,6 @@ static inline int imx_bbu_external_nor_register_handler(const char *name, char * } #endif -#if defined(CONFIG_BAREBOX_UPDATE_IMX6_NAND) -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); -#else -static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) -{ - return -ENOSYS; -} -#endif - #if defined(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) int imx_bbu_external_nand_register_handler(const char *name, char *devicefile, unsigned long flags); diff --git a/common/Kconfig b/common/Kconfig index 1c5d14c1c..0ebfe1e07 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -94,6 +94,14 @@ config EFI_DEVICEPATH config FILE_LIST bool +config BAREBOX_UPDATE_IMX_NAND_FCB + bool + depends on ARCH_IMX6 + depends on BAREBOX_UPDATE + depends on MTD_WRITE + depends on NAND_MXS + default y + menu "General Settings" config LOCALVERSION diff --git a/common/Makefile b/common/Makefile index 2738238c6..74801f7e2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -52,6 +52,7 @@ lwl-$(CONFIG_IMD) += imd-barebox.o obj-$(CONFIG_IMD) += imd.o obj-$(CONFIG_FILE_LIST) += file-list.o obj-$(CONFIG_FIRMWARE) += firmware.o +obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/arch/arm/mach-imx/imx6-bbu-nand.c b/common/imx-bbu-nand-fcb.c similarity index 100% rename from arch/arm/mach-imx/imx6-bbu-nand.c rename to common/imx-bbu-nand-fcb.c diff --git a/include/bbu.h b/include/bbu.h index 4a3d35e7c..c5f22be7a 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -50,4 +50,13 @@ static inline int bbu_register_handler(struct bbu_handler *unused) #endif +#if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) +int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); +#else +static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + return -ENOSYS; +} +#endif + #endif /* __INCLUDE_BBU_H */ From 92a5a43ac7127c9616b369e90faec718c42ec7c7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 06:40:52 +0200 Subject: [PATCH 05/10] imx-bbu-nand-fcb: Fix debug messages We should print the block number before increasing it, not afterwards. Signed-off-by: Sascha Hauer --- common/imx-bbu-nand-fcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index d2bfedbad..5b984d414 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -275,8 +275,8 @@ static int imx6_bbu_erase(struct mtd_info *mtd) while (len > 0) { pr_debug("erasing at 0x%08llx\n", offset); if (mtd_block_isbad(mtd, offset)) { - offset += mtd->erasesize; pr_debug("erase skip block @ 0x%08llx\n", offset); + offset += mtd->erasesize; continue; } @@ -308,9 +308,9 @@ static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, s buf, offset, len); if (mtd_block_isbad(mtd, offset)) { + pr_debug("write skip block @ 0x%08llx\n", offset); offset += mtd->erasesize; block++; - pr_debug("write skip block @ 0x%08llx\n", offset); continue; } From 103b88ace1c85be724bd758fe21366d090315c76 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 06:23:30 +0200 Subject: [PATCH 06/10] imx-bbu-nand-fcb: Use barebox partition instead of whole device We used to use nand0 device for storing barebox and made the assumption that there is enough space at the beginning of the first device. Instead, use the barebox partition directly. This requires that the partition where barebox should be stored is named 'barebox', that is the case for all boards currently. Signed-off-by: Sascha Hauer --- common/imx-bbu-nand-fcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index 5b984d414..ca7df97f8 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -370,7 +370,7 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da if (ret) return ret; - bcb_cdev = cdev_by_name("nand0"); + bcb_cdev = cdev_by_name(handler->devicefile); if (!bcb_cdev) { pr_err("%s: No FCB device!\n", __func__); return -ENODEV; @@ -478,7 +478,7 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) int ret; handler = xzalloc(sizeof(*handler)); - handler->devicefile = "/dev/nand0"; + handler->devicefile = "nand0.barebox"; handler->name = name; handler->flags = flags; handler->handler = imx6_bbu_nand_update; From 22f8077c391c6a226dbb9a5228af8e9840fc0e42 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 10 Jun 2015 15:13:16 +0200 Subject: [PATCH 07/10] imx-bbu-nand-fcb: make available for i.MX28 aswell The code can be used with slight modifications on i.MX28 aswell. Add a i.MX28 registration function and move the differences to function callbacks. Signed-off-by: Sascha Hauer --- common/Kconfig | 2 +- common/imx-bbu-nand-fcb.c | 173 +++++++++++++++++++++++++++++++++----- include/bbu.h | 5 ++ 3 files changed, 157 insertions(+), 23 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 0ebfe1e07..31944c553 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -96,7 +96,7 @@ config FILE_LIST config BAREBOX_UPDATE_IMX_NAND_FCB bool - depends on ARCH_IMX6 + depends on ARCH_IMX6 || ARCH_IMX28 depends on BAREBOX_UPDATE depends on MTD_WRITE depends on NAND_MXS diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index ca7df97f8..920b5a1b8 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -17,7 +17,7 @@ * */ -#define pr_fmt(fmt) "imx6-bbu-nand: " fmt +#define pr_fmt(fmt) "imx-bbu-nand-fcb: " fmt #include #include @@ -28,17 +28,17 @@ #include #include #include -#include #include #include #include #include +#include struct dbbt_block { uint32_t Checksum; uint32_t FingerPrint; uint32_t Version; - uint32_t reserved; + uint32_t numberBB; /* reserved on i.MX6 */ uint32_t DBBTNumOfPages; }; @@ -102,6 +102,16 @@ struct fcb_block { uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */ }; +struct imx_nand_fcb_bbu_handler { + struct bbu_handler handler; + + void (*fcb_create)(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd); + void (*dbbt_create)(struct imx_nand_fcb_bbu_handler *imx_handler, + struct dbbt_block *dbbt, int num_bad_blocks); + enum filetype filetype; +}; + #define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) #define GETBIT(v,n) (((v) >> (n)) & 0x1) @@ -228,7 +238,8 @@ static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset) return ret; } -static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) +static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) { fcb->FingerPrint = 0x20424346; fcb->Version = 0x01000000; @@ -241,12 +252,6 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1; fcb->EccBlockNEccType = fcb->EccBlock0EccType; - /* Also hardcoded in kobs-ng */ - fcb->DataSetup = 80; - fcb->DataHold = 60; - fcb->AddressSetup = 25; - fcb->DSAMPLE_TIME = 6; - fcb->MetadataBytes = 0x0000000a; fcb->EccBlock0Size = 0x00000200; fcb->EccBlockNSize = 0x00000200; @@ -260,12 +265,14 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) fcb->BBMarkerPhysicalOffset = mtd->writesize; + imx_handler->fcb_create(imx_handler, fcb, mtd); + fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4); return 0; } -static int imx6_bbu_erase(struct mtd_info *mtd) +static int imx_bbu_erase(struct mtd_info *mtd) { uint64_t offset = 0; int len = SZ_2M; @@ -295,7 +302,7 @@ static int imx6_bbu_erase(struct mtd_info *mtd) return 0; } -static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len) +static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len) { uint64_t offset = block * mtd->erasesize; int ret; @@ -348,8 +355,10 @@ static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last) return n_bad_blocks; } -static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) +static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) { + struct imx_nand_fcb_bbu_handler *imx_handler = + container_of(handler, struct imx_nand_fcb_bbu_handler, handler); struct cdev *bcb_cdev; struct mtd_info *mtd; int ret, block_fw1, block_fw2, block_last; @@ -361,9 +370,14 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da void *fw; unsigned fw_size; int i; + enum filetype filetype; - if (file_detect_type(data->image, data->len) != filetype_arm_barebox && - !bbu_force(data, "Not an ARM barebox image")) + filetype = file_detect_type(data->image, data->len); + + if (filetype != imx_handler->filetype && + !bbu_force(data, "Image is not of type %s but of type %s", + file_type_to_string(imx_handler->filetype), + file_type_to_string(filetype))) return -EINVAL; ret = bbu_confirm(data); @@ -398,17 +412,17 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da block_fw1 = 4; - ret = imx6_bbu_erase(mtd); + ret = imx_bbu_erase(mtd); if (ret) goto out; - ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size); + ret = imx_bbu_write_firmware(mtd, block_fw1, fw, fw_size); if (ret < 0) goto out; block_fw2 = ret; - ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size); + ret = imx_bbu_write_firmware(mtd, block_fw2, fw, fw_size); if (ret < 0) goto out; @@ -419,7 +433,7 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize; fcb->PagesInFirmware2 = fcb->PagesInFirmware1; - fcb_create(fcb, mtd); + fcb_create(imx_handler, fcb, mtd); encode_hamming_13_8(fcb, ecc, 512); /* @@ -447,8 +461,11 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da if (ret < 0) goto out; - if (ret > 0) + if (ret > 0) { dbbt->DBBTNumOfPages = 1; + if (imx_handler->dbbt_create) + imx_handler->dbbt_create(imx_handler, dbbt, ret); + } for (i = 2; i < 4; i++) { ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page); @@ -472,16 +489,32 @@ out: return ret; } +static void imx6_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) +{ + /* Also hardcoded in kobs-ng */ + fcb->DataSetup = 80; + fcb->DataHold = 60; + fcb->AddressSetup = 25; + fcb->DSAMPLE_TIME = 6; + fcb->MetadataBytes = 10; +} + int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) { + struct imx_nand_fcb_bbu_handler *imx_handler; struct bbu_handler *handler; int ret; - handler = xzalloc(sizeof(*handler)); + imx_handler = xzalloc(sizeof(*imx_handler)); + imx_handler->fcb_create = imx6_fcb_create; + imx_handler->filetype = filetype_arm_barebox; + + handler = &imx_handler->handler; handler->devicefile = "nand0.barebox"; handler->name = name; handler->flags = flags; - handler->handler = imx6_bbu_nand_update; + handler->handler = imx_bbu_nand_update; ret = bbu_register_handler(handler); if (ret) @@ -489,3 +522,99 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) return ret; } + +#ifdef CONFIG_ARCH_IMX28 +#include + +#define GPMI_TIMING0 0x00000070 +#define GPMI_TIMING0_ADDRESS_SETUP_MASK (0xff << 16) +#define GPMI_TIMING0_ADDRESS_SETUP_OFFSET 16 +#define GPMI_TIMING0_DATA_HOLD_MASK (0xff << 8) +#define GPMI_TIMING0_DATA_HOLD_OFFSET 8 +#define GPMI_TIMING0_DATA_SETUP_MASK 0xff +#define GPMI_TIMING0_DATA_SETUP_OFFSET 0 + +#define GPMI_TIMING1 0x00000080 + +#define BCH_MODE 0x00000020 + +#define BCH_FLASH0LAYOUT0 0x00000080 +#define BCH_FLASHLAYOUT0_NBLOCKS_MASK (0xff << 24) +#define BCH_FLASHLAYOUT0_NBLOCKS_OFFSET 24 +#define BCH_FLASHLAYOUT0_META_SIZE_MASK (0xff << 16) +#define BCH_FLASHLAYOUT0_META_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12) +#define BCH_FLASHLAYOUT0_ECC0_OFFSET 12 +#define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0 + +#define BCH_FLASH0LAYOUT1 0x00000090 +#define BCH_FLASHLAYOUT1_PAGE_SIZE_MASK (0xffff << 16) +#define BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12) +#define BCH_FLASHLAYOUT1_ECCN_OFFSET 12 +#define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0 + +static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) +{ + u32 fl0, fl1, t0; + void __iomem *bch_regs = (void *)MXS_BCH_BASE; + void __iomem *gpmi_regs = (void *)MXS_GPMI_BASE; + + fl0 = readl(bch_regs + BCH_FLASH0LAYOUT0); + fl1 = readl(bch_regs + BCH_FLASH0LAYOUT1); + t0 = readl(gpmi_regs + GPMI_TIMING0); + + fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + fcb->DataSetup = BF_VAL(t0, GPMI_TIMING0_DATA_SETUP); + fcb->DataHold = BF_VAL(t0, GPMI_TIMING0_DATA_HOLD); + fcb->AddressSetup = BF_VAL(t0, GPMI_TIMING0_ADDRESS_SETUP); + fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + fcb->NumEccBlocksPerPage = BF_VAL(fl0, BCH_FLASHLAYOUT0_NBLOCKS); + fcb->EraseThreshold = readl(bch_regs + BCH_MODE); +} + +static void imx28_dbbt_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct dbbt_block *dbbt, int num_bad_blocks) +{ + uint32_t a = 0; + uint8_t *p = (void *)dbbt; + int i; + + dbbt->numberBB = num_bad_blocks; + + for (i = 4; i < 512; i++) + a += p[i]; + + a ^= 0xffffffff; + + dbbt->Checksum = a; +} + +int imx28_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + struct imx_nand_fcb_bbu_handler *imx_handler; + struct bbu_handler *handler; + int ret; + + imx_handler = xzalloc(sizeof(*imx_handler)); + imx_handler->fcb_create = imx28_fcb_create; + imx_handler->dbbt_create = imx28_dbbt_create; + + imx_handler->filetype = filetype_mxs_bootstream; + + handler = &imx_handler->handler; + handler->devicefile = "nand0.barebox"; + handler->name = name; + handler->flags = flags; + handler->handler = imx_bbu_nand_update; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} +#endif diff --git a/include/bbu.h b/include/bbu.h index c5f22be7a..4cf97e17d 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -52,11 +52,16 @@ static inline int bbu_register_handler(struct bbu_handler *unused) #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); +int imx28_bbu_nand_register_handler(const char *name, unsigned long flags); #else static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) { return -ENOSYS; } +static inline int imx28_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + return -ENOSYS; +} #endif #endif /* __INCLUDE_BBU_H */ From c3400f3d6430af32baaa9f4a878561e9faca7500 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 06:58:24 +0200 Subject: [PATCH 08/10] imx-bbu-nand-fcb: Let DBBT start at page 1 We used to put the FCB in the first two NAND blocks and the DBBT in the third and fourth block. It's much more space efficient to put the FCB and DBBT together into the same eraseblock in different pages. This way we can store four FCBs and four DBBTs instead of two only. Signed-off-by: Sascha Hauer --- common/imx-bbu-nand-fcb.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index 920b5a1b8..d65b9cd91 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -257,8 +257,8 @@ static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1; - /* DBBT search area starts at third block */ - fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2; + /* DBBT search area starts at second page on first block */ + fcb->DBBTSearchAreaStartAddress = 1; fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd); fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd); @@ -445,10 +445,6 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat */ memset(fcb_raw_page + mtd->writesize, 0xFF, 2); - ret = raw_write_page(mtd, fcb_raw_page, 0); - if (ret) - goto out; - ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize); if (ret) goto out; @@ -467,14 +463,19 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat imx_handler->dbbt_create(imx_handler, dbbt, ret); } - for (i = 2; i < 4; i++) { - ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page); + for (i = 0; i < 4; i++) { + ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize * i); + if (ret) + goto out; + + ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize, + mtd->writesize, &written, dbbt_page); if (ret) goto out; if (dbbt->DBBTNumOfPages > 0) { - ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4, - 2048, &written, dbbt_data_page); + ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 5, + mtd->writesize, &written, dbbt_data_page); if (ret) goto out; } From 4e880df3470eb099c9934e6b37af87ab47255c52 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 07:03:43 +0200 Subject: [PATCH 09/10] imx-bbu-nand-fcb: Erase whole partition Now that we use a partition for the bootloader instead of the whole NAND device we can erase it completely instead of hardcoded 2MB. Signed-off-by: Sascha Hauer --- common/imx-bbu-nand-fcb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index d65b9cd91..c4f49b551 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -275,11 +275,10 @@ static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, static int imx_bbu_erase(struct mtd_info *mtd) { uint64_t offset = 0; - int len = SZ_2M; struct erase_info erase; int ret; - while (len > 0) { + while (offset < mtd->size) { pr_debug("erasing at 0x%08llx\n", offset); if (mtd_block_isbad(mtd, offset)) { pr_debug("erase skip block @ 0x%08llx\n", offset); @@ -296,7 +295,6 @@ static int imx_bbu_erase(struct mtd_info *mtd) return ret; offset += mtd->erasesize; - len -= mtd->erasesize; } return 0; From 6ab66787fc15a286b6142b09f9d7c2654dee78a9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 12 Jun 2015 07:48:51 +0200 Subject: [PATCH 10/10] imx-bbu-nand-fcb: Split space for firmware in two equal regions We used to write the second firmware right after the first firmware. However, splitting the available space into two equal regions has advantages: When we update barebox the next time the generated FCB/DBBT blocks will be the same as with the last update, so in case of power failure it is more likely that we have valid data in one of the FCB/DBBT areas. Signed-off-by: Sascha Hauer --- common/imx-bbu-nand-fcb.c | 48 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index c4f49b551..22031f5b7 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -300,7 +300,8 @@ static int imx_bbu_erase(struct mtd_info *mtd) return 0; } -static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len) +static int imx_bbu_write_firmware(struct mtd_info *mtd, unsigned block, + unsigned num_blocks, void *buf, size_t len) { uint64_t offset = block * mtd->erasesize; int ret; @@ -309,6 +310,9 @@ static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, si while (len > 0) { int now = min(len, mtd->erasesize); + if (!num_blocks) + return -ENOSPC; + pr_debug("writing %p at 0x%08llx, left 0x%08x\n", buf, offset, len); @@ -327,6 +331,7 @@ static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, si len -= now; buf += now; block++; + num_blocks--; } return block; @@ -359,16 +364,17 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat container_of(handler, struct imx_nand_fcb_bbu_handler, handler); struct cdev *bcb_cdev; struct mtd_info *mtd; - int ret, block_fw1, block_fw2, block_last; + int ret, block_fw1, block_fw2; struct fcb_block *fcb; struct dbbt_block *dbbt; void *fcb_raw_page, *dbbt_page, *dbbt_data_page; void *ecc; int written; void *fw; - unsigned fw_size; + unsigned fw_size, partition_size; int i; enum filetype filetype; + unsigned num_blocks_fcb_dbbt, num_blocks, num_blocks_fw; filetype = file_detect_type(data->image, data->len); @@ -378,10 +384,6 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat file_type_to_string(filetype))) return -EINVAL; - ret = bbu_confirm(data); - if (ret) - return ret; - bcb_cdev = cdev_by_name(handler->devicefile); if (!bcb_cdev) { pr_err("%s: No FCB device!\n", __func__); @@ -389,6 +391,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat } mtd = bcb_cdev->mtd; + partition_size = mtd->size; fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize); @@ -408,24 +411,39 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat fw = xzalloc(fw_size); memcpy(fw, data->image, data->len); - block_fw1 = 4; + num_blocks_fcb_dbbt = 4; + num_blocks = partition_size / mtd->erasesize; + num_blocks_fw = (num_blocks - num_blocks_fcb_dbbt) / 2; + + block_fw1 = num_blocks_fcb_dbbt; + block_fw2 = num_blocks_fcb_dbbt + num_blocks_fw; + + pr_info("writing first firmware to block %d (ofs 0x%08x)\n", + block_fw1, block_fw1 * mtd->erasesize); + pr_info("writing second firmware to block %d (ofs 0x%08x)\n", + block_fw2, block_fw2 * mtd->erasesize); + pr_info("maximum size per firmware: 0x%08x bytes\n", + num_blocks_fw * mtd->erasesize); + + if (num_blocks_fw * mtd->erasesize < fw_size) + return -ENOSPC; + + ret = bbu_confirm(data); + if (ret) + goto out; ret = imx_bbu_erase(mtd); if (ret) goto out; - ret = imx_bbu_write_firmware(mtd, block_fw1, fw, fw_size); + ret = imx_bbu_write_firmware(mtd, block_fw1, num_blocks_fw, fw, fw_size); if (ret < 0) goto out; - block_fw2 = ret; - - ret = imx_bbu_write_firmware(mtd, block_fw2, fw, fw_size); + ret = imx_bbu_write_firmware(mtd, block_fw2, num_blocks_fw, fw, fw_size); if (ret < 0) goto out; - block_last = ret; - fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize; fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize; fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize; @@ -451,7 +469,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat dbbt->FingerPrint = 0x54424244; dbbt->Version = 0x01000000; - ret = dbbt_data_create(mtd, dbbt_data_page, block_last); + ret = dbbt_data_create(mtd, dbbt_data_page, block_fw2 + num_blocks_fw); if (ret < 0) goto out;