From 17828c5be2c0a7c07ce7d37828276adb374abcf0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 28 Aug 2019 12:01:38 +0200 Subject: ARM: omap: am35xx_emif4: Fix bit polling ((x & (1 << 10)) == 0x1) can never be true as the compiler mourns about. Fix this to actually do what the comment says: Wait till bit 10 is cleared. Looking at the corresponding U-Boot code also suggests that this is the right thing to do. Signed-off-by: Sascha Hauer --- arch/arm/mach-omap/am35xx_emif4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-omap/am35xx_emif4.c b/arch/arm/mach-omap/am35xx_emif4.c index 38fc0f02d2..678a338fd6 100644 --- a/arch/arm/mach-omap/am35xx_emif4.c +++ b/arch/arm/mach-omap/am35xx_emif4.c @@ -37,7 +37,7 @@ void am35xx_emif4_init(void) writel(regval, &emif4_base->sdram_iodft_tlgc); /* Wait till that bit clears*/ - while ((readl(&emif4_base->sdram_iodft_tlgc) & (1 << 10)) == 0x1); + while (readl(&emif4_base->sdram_iodft_tlgc) & (1 << 10)); /* Re-verify the DDR PHY status*/ while ((readl(&emif4_base->sdram_sts) & (1 << 2)) == 0x0); -- cgit v1.2.3 From b3f6d0f4dcbb46eaadf0e1c47d97b5c5d25fd0b4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 26 Aug 2019 14:35:01 +0200 Subject: mtd: nand: gpmc: Add BCH16 support This adds support for BCH16 ECC encoding. The support is mostly taken from Linux-5.3-rc6. One major change is the different wrap mode used. The Kernel uses wrapmode 1, which means "pass all data through the BCH engine". Still the Kernel has to skip the OOB marker which is done by reading all user data, then use NAND_CMD_RNDOUT to position right behind the OOB marker and then read the ECC data. Instead of doing this we use wrap mode 4 which allows us to bypass the OOB marker from the BCH engine automatically. This explains bch_wrapmode = 1, eccsize0 = 0, eccsize1 = 52 vs. bch_wrapmode = 4, eccsize0 = 4, eccsize1 = 52 Signed-off-by: Sascha Hauer --- arch/arm/mach-omap/include/mach/gpmc_nand.h | 1 + drivers/bus/omap-gpmc.c | 3 + drivers/mtd/nand/nand_omap_gpmc.c | 333 +++++++++++++++++++++++++++- include/linux/mtd/mtd-abi.h | 2 +- 4 files changed, 330 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h index c9730a9454..f172b576eb 100644 --- a/arch/arm/mach-omap/include/mach/gpmc_nand.h +++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h @@ -34,6 +34,7 @@ enum gpmc_ecc_mode { OMAP_ECC_HAMMING_CODE_HW_ROMCODE, OMAP_ECC_BCH8_CODE_HW, OMAP_ECC_BCH8_CODE_HW_ROMCODE, + OMAP_ECC_BCH16_CODE_HW, }; /** omap nand platform data structure */ diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c index a3fccb2182..8fd7a91740 100644 --- a/drivers/bus/omap-gpmc.c +++ b/drivers/bus/omap-gpmc.c @@ -448,6 +448,9 @@ static struct dt_eccmode modes[] = { }, { .name = "bch8", .mode = OMAP_ECC_BCH8_CODE_HW_ROMCODE, + }, { + .name = "bch16", + .mode = OMAP_ECC_BCH16_CODE_HW, }, }; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 2dcf7e723b..ba2c2c4314 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -70,6 +70,7 @@ #include #include #include +#include #include "nand_omap_bch_decoder.h" @@ -91,6 +92,10 @@ static const uint8_t bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; +static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, + 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, + 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, + 0x07, 0x0e}; static const char *ecc_mode_strings[] = { "software", @@ -232,7 +237,7 @@ static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, { struct nand_chip *nand = (struct nand_chip *)(mtd->priv); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); - unsigned int reg; + unsigned int reg, reg1, val; unsigned int val1 = 0x0, val2 = 0x0; unsigned int val3 = 0x0, val4 = 0x0; int ecc_size = 8; @@ -274,6 +279,45 @@ static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ *ecc_code++ = ((val1 >> 8) & 0x0f) | ((val1 >> 20) & 0xf0); break; + + case OMAP_ECC_BCH16_CODE_HW: + reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * sblock); + reg1 = 0x300 + (0x10 * sblock); + + val = readl(oinfo->gpmc_base + reg1 + 0x8); + ecc_code[0] = ((val >> 8) & 0xFF); + ecc_code[1] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg1 + 0x4); + ecc_code[2] = ((val >> 24) & 0xFF); + ecc_code[3] = ((val >> 16) & 0xFF); + ecc_code[4] = ((val >> 8) & 0xFF); + ecc_code[5] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg1 + 0x0); + ecc_code[6] = ((val >> 24) & 0xFF); + ecc_code[7] = ((val >> 16) & 0xFF); + ecc_code[8] = ((val >> 8) & 0xFF); + ecc_code[9] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0xc); + ecc_code[10] = ((val >> 24) & 0xFF); + ecc_code[11] = ((val >> 16) & 0xFF); + ecc_code[12] = ((val >> 8) & 0xFF); + ecc_code[13] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x8); + ecc_code[14] = ((val >> 24) & 0xFF); + ecc_code[15] = ((val >> 16) & 0xFF); + ecc_code[16] = ((val >> 8) & 0xFF); + ecc_code[17] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x4); + ecc_code[18] = ((val >> 24) & 0xFF); + ecc_code[19] = ((val >> 16) & 0xFF); + ecc_code[20] = ((val >> 8) & 0xFF); + ecc_code[21] = ((val >> 0) & 0xFF); + val = readl(oinfo->gpmc_base + reg + 0x0); + ecc_code[22] = ((val >> 24) & 0xFF); + ecc_code[23] = ((val >> 16) & 0xFF); + ecc_code[24] = ((val >> 8) & 0xFF); + ecc_code[25] = ((val >> 0) & 0xFF); + break; default: return -EINVAL; } @@ -294,7 +338,7 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); int j, actual_eccsize; const uint8_t *erased_ecc_vec; - unsigned int err_loc[8]; + unsigned int err_loc[16]; int bch_max_err; int bitflip_count = 0; bool eccflag = 0; @@ -311,6 +355,11 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, erased_ecc_vec = bch8_vector; bch_max_err = BCH8_MAX_ERROR; break; + case OMAP_ECC_BCH16_CODE_HW: + actual_eccsize = eccsize; + erased_ecc_vec = bch16_vector; + bch_max_err = 16; + break; default: dev_err(oinfo->pdev, "invalid driver configuration\n"); return -EINVAL; @@ -441,13 +490,27 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) case OMAP_ECC_BCH8_CODE_HW: case OMAP_ECC_BCH8_CODE_HW_ROMCODE: if (mode == NAND_ECC_READ) { - eccsize1 = 0x1A; eccsize0 = 0x18; + eccsize0 = 24; + eccsize1 = 26; bch_mod = 1; - bch_wrapmode = 0x04; + bch_wrapmode = 4; } else { - eccsize1 = 0x20; eccsize0 = 0x00; + eccsize0 = 0; + eccsize1 = 32; bch_mod = 1; - bch_wrapmode = 0x06; + bch_wrapmode = 6; + } + break; + case OMAP_ECC_BCH16_CODE_HW: + bch_mod = 2; + if (mode == NAND_ECC_READ) { + bch_wrapmode = 4; + eccsize0 = 4; /* ECC bits in nibbles per sector */ + eccsize1 = 52; /* non-ECC bits in nibbles per sector */ + } else { + bch_wrapmode = 4; + eccsize0 = 4; /* extra bits in nibbles per sector */ + eccsize1 = 52; /* OOB bits in nibbles per sector */ } break; case OMAP_ECC_HAMMING_CODE_HW_ROMCODE: @@ -483,7 +546,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) GPMC_ECC_CONFIG_ECCBCHTSEL(bch_mod) | GPMC_ECC_CONFIG_ECCWRAPMODE(bch_wrapmode) | dev_width | - GPMC_ECC_CONFIG_ECCTOPSECTOR(3) | + GPMC_ECC_CONFIG_ECCTOPSECTOR(nand->ecc.steps - 1) | GPMC_ECC_CONFIG_ECCCS(cs) | GPMC_ECC_CONFIG_ECCENABLE); } @@ -689,6 +752,234 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd, return max_bitflips; } +/** + * erased_sector_bitflips - count bit flips + * @data: data sector buffer + * @oob: oob buffer + * oinfo: gpmc_nand_info + * + * Check the bit flips in erased page falls below correctable level. + * If falls below, report the page as erased with correctable bit + * flip, else report as uncorrectable page. + */ +static int erased_sector_bitflips(u_char *data, u_char *oob, + struct gpmc_nand_info *oinfo) +{ + int flip_bits = 0, i; + + for (i = 0; i < oinfo->nand.ecc.size; i++) { + flip_bits += hweight8(~data[i]); + if (flip_bits > oinfo->nand.ecc.strength) + return 0; + } + + for (i = 0; i < oinfo->nand.ecc.bytes - 1; i++) { + flip_bits += hweight8(~oob[i]); + if (flip_bits > oinfo->nand.ecc.strength) + return 0; + } + + /* + * Bit flips falls in correctable level. + * Fill data area with 0xFF + */ + if (flip_bits) { + memset(data, 0xFF, oinfo->nand.ecc.size); + memset(oob, 0xFF, oinfo->nand.ecc.bytes); + } + + return flip_bits; +} + +/** + * omap_elm_correct_data - corrects page data area in case error reported + * @chip: NAND chip object + * @data: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from HW ECC registers + * + * Calculated ecc vector reported as zero in case of non-error pages. + * In case of non-zero ecc vector, first filter out erased-pages, and + * then process data via ELM to detect bit-flips. + */ +static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, + u_char *read_ecc, u_char *calc_ecc) +{ + struct gpmc_nand_info *oinfo = chip->priv; + struct nand_ecc_ctrl *ecc = &oinfo->nand.ecc; + int eccsteps = oinfo->nand.ecc.steps; + int i , j, stat = 0; + int eccflag, actual_eccbytes; + struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; + u_char *ecc_vec = calc_ecc; + u_char *spare_ecc = read_ecc; + const u_char *erased_ecc_vec; + u_char *buf; + int bitflip_count; + bool is_error_reported = false; + u32 bit_pos, byte_pos, error_max, pos; + int err; + + switch (oinfo->ecc_mode) { + case OMAP_ECC_BCH8_CODE_HW: + /* omit 14th ECC byte reserved for ROM code compatibility */ + actual_eccbytes = ecc->bytes - 1; + erased_ecc_vec = bch8_vector; + break; + case OMAP_ECC_BCH16_CODE_HW: + actual_eccbytes = ecc->bytes; + erased_ecc_vec = bch16_vector; + break; + default: + dev_err(oinfo->pdev, "invalid driver configuration\n"); + return -EINVAL; + } + + /* Initialize elm error vector to zero */ + memset(err_vec, 0, sizeof(err_vec)); + + for (i = 0; i < eccsteps ; i++) { + eccflag = 0; /* initialize eccflag */ + + /* + * Check any error reported, + * In case of error, non zero ecc reported. + */ + for (j = 0; j < actual_eccbytes; j++) { + if (calc_ecc[j] != 0) { + eccflag = 1; /* non zero ecc, error present */ + break; + } + } + + if (eccflag == 1) { + if (memcmp(calc_ecc, erased_ecc_vec, + actual_eccbytes) == 0) { + /* + * calc_ecc[] matches pattern for ECC(all 0xff) + * so this is definitely an erased-page + */ + } else { + buf = &data[oinfo->nand.ecc.size * i]; + /* + * count number of 0-bits in read_buf. + * This check can be removed once a similar + * check is introduced in generic NAND driver + */ + bitflip_count = erased_sector_bitflips( + buf, read_ecc, oinfo); + if (bitflip_count) { + /* + * number of 0-bits within ECC limits + * So this may be an erased-page + */ + stat += bitflip_count; + } else { + /* + * Too many 0-bits. It may be a + * - programmed-page, OR + * - erased-page with many bit-flips + * So this page requires check by ELM + */ + err_vec[i].error_reported = true; + is_error_reported = true; + } + } + } + + /* Update the ecc vector */ + calc_ecc += ecc->bytes; + read_ecc += ecc->bytes; + } + + /* Check if any error reported */ + if (!is_error_reported) + return stat; + + /* Decode BCH error using ELM module */ + elm_decode_bch_error_page(ecc_vec, err_vec); + + err = 0; + for (i = 0; i < eccsteps; i++) { + if (err_vec[i].error_uncorrectable) { + dev_err(oinfo->pdev, + "uncorrectable bit-flips found\n"); + err = -EBADMSG; + } else if (err_vec[i].error_reported) { + for (j = 0; j < err_vec[i].error_count; j++) { + switch (oinfo->ecc_mode) { + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + pos = err_vec[i].error_loc[j]; + break; + default: + return -EINVAL; + } + error_max = (ecc->size + actual_eccbytes) * 8; + /* Calculate bit position of error */ + bit_pos = pos % 8; + + /* Calculate byte position of error */ + byte_pos = (error_max - pos - 1) / 8; + + if (pos < error_max) { + if (byte_pos < 512) { + pr_debug("bitflip@dat[%d]=%x\n", + byte_pos, data[byte_pos]); + data[byte_pos] ^= 1 << bit_pos; + } else { + pr_debug("bitflip@oob[%d]=%x\n", + (byte_pos - 512), + spare_ecc[byte_pos - 512]); + spare_ecc[byte_pos - 512] ^= + 1 << bit_pos; + } + } else { + dev_err(oinfo->pdev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); + err = -EBADMSG; + } + } + } + + /* Update number of correctable errors */ + stat = max_t(unsigned int, stat, err_vec[i].error_count); + + /* Update page data with sector size */ + data += ecc->size; + spare_ecc += ecc->bytes; + } + + return (err) ? err : stat; +} + +static int gpmc_read_page_hwecc_elm(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + int i; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + + for (i = 0; eccsteps; eccsteps--, i++) + __omap_calculate_ecc(mtd, &ecc_calc[i * eccbytes], i); + + return omap_elm_correct_data(chip, buf, ecc_code, ecc_calc); +} + static int gpmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) @@ -732,7 +1023,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, { struct mtd_info *minfo = &oinfo->minfo; struct nand_chip *nand = &oinfo->nand; - int offset; + int offset, err; int i, j; if (nand->options & NAND_BUSWIDTH_16) @@ -807,6 +1098,32 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, for (i = 2; i < 58; i++) omap_oobinfo.eccpos[j++] = i; break; + case OMAP_ECC_BCH16_CODE_HW: + oinfo->nand.ecc.size = 512; + oinfo->nand.ecc.bytes = 26; + oinfo->nand.ecc.strength = 16; + oinfo->nand.ecc.steps = + minfo->writesize / oinfo->nand.ecc.size; + oinfo->nand.ecc.total = + oinfo->nand.ecc.steps * oinfo->nand.ecc.bytes; + omap_oobinfo.eccbytes = oinfo->nand.ecc.total; + + for (i = 0; i < oinfo->nand.ecc.total; i++) + omap_oobinfo.eccpos[i] = i + 2; + + /* reserved marker already included in ecclayout->eccbytes */ + omap_oobinfo.oobfree->offset = + omap_oobinfo.eccpos[oinfo->nand.ecc.total - 1] + 1; + + err = elm_config(BCH16_ECC, + oinfo->minfo.writesize / nand->ecc.size, + nand->ecc.size, nand->ecc.bytes); + if (err < 0) + return err; + + nand->ecc.read_page = gpmc_read_page_hwecc_elm; + + break; case OMAP_ECC_SOFT: nand->ecc.layout = NULL; nand->ecc.mode = NAND_ECC_SOFT; diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index 9bca9b5e06..dfcb3554fb 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -137,7 +137,7 @@ struct nand_oobfree { }; #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 -#define MTD_MAX_ECCPOS_ENTRIES_LARGE 128 /* FIXME : understand why 448 is not working */ +#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640 /* * ECC layout control structure. Exported to userspace for * diagnosis and to allow creation of raw images -- cgit v1.2.3 From 63ea06d03e9f0ef574ff4d68b1bd3b3abff67e8e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 28 Aug 2019 11:21:13 +0200 Subject: ARM: OMAP: bbu: Add an all-in-one NAND update handler This adds a NAND update handler which automatically detects on the filetype which stage shall be updated. It takes a single partition for both the xload images and the barebox images. It uses a fixed layout on this partition, so there's no need to configure anything on the board side. Signed-off-by: Sascha Hauer --- arch/arm/mach-omap/am33xx_bbu_nand.c | 146 ++++++++++++++++++++++++++++++++++ arch/arm/mach-omap/include/mach/bbu.h | 6 ++ 2 files changed, 152 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap/am33xx_bbu_nand.c b/arch/arm/mach-omap/am33xx_bbu_nand.c index 4c1a28d37e..8c487c8ebb 100644 --- a/arch/arm/mach-omap/am33xx_bbu_nand.c +++ b/arch/arm/mach-omap/am33xx_bbu_nand.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include struct nand_bbu_handler { @@ -134,3 +136,147 @@ int am33xx_bbu_nand_slots_register_handler(const char *name, char **devicefile, return ret; } + +#define XLOAD_BLOCKS 4 + +static int nand_update_handler_complete(struct bbu_handler *handler, + struct bbu_data *data) +{ + const void *image = data->image; + size_t size = data->len; + enum filetype filetype; + struct cdev *cdev; + struct mtd_info *mtd; + int ret, i; + int npebs; + + filetype = file_detect_type(image, size); + + cdev = cdev_by_name(handler->devicefile); + if (!cdev) { + pr_err("%s: No NAND device found\n", __func__); + return -ENODEV; + } + + mtd = cdev->mtd; + if (!mtd) { + pr_err("%s: %s is not a mtd device\n", __func__, + handler->devicefile); + return -EINVAL; + } + + npebs = mtd_div_by_eb(mtd->size, mtd); + + /* + * Sanity check: We need at minimum 6 eraseblocks: 4 for the four xload + * binaries and 2 for the barebox images. + */ + if (npebs < XLOAD_BLOCKS + 2) + return -EINVAL; + + if (filetype == filetype_arm_barebox) { + int npebs_bb = (npebs - XLOAD_BLOCKS) / 2; + + pr_info("Barebox image detected, updating 2nd stage\n"); + + /* last chance before erasing the flash */ + ret = bbu_confirm(data); + if (ret) + goto out; + + ret = mtd_peb_write_file(mtd, XLOAD_BLOCKS, npebs_bb, data->image, + data->len); + if (ret) + goto out; + + ret = mtd_peb_write_file(mtd, XLOAD_BLOCKS + npebs_bb, npebs_bb, + data->image, data->len); + if (ret) + goto out; + + } else if (filetype == filetype_ch_image) { + int written = 0; + void *buf; + + pr_info("xload image detected, updating 1st stage\n"); + + if (data->len > mtd->erasesize) { + pr_err("Image is bigger than eraseblock, this is not supported\n"); + ret = -EINVAL; + goto out; + } + + /* last chance before erasing the flash */ + ret = bbu_confirm(data); + if (ret) + goto out; + + buf = xzalloc(mtd->erasesize); + memcpy(buf, data->image, data->len); + + for (i = 0; i < 4; i++) { + if (mtd_peb_is_bad(mtd, i)) { + pr_info("PEB%d is bad, skipping\n", i); + continue; + } + + ret = mtd_peb_erase(mtd, i); + if (ret) + continue; + + ret = mtd_peb_write(mtd, buf, i, 0, mtd->erasesize); + if (ret) { + pr_err("Failed to write MLO to PEB%d: %s\n", i, + strerror(-ret)); + continue; + } + written++; + } + + free(buf); + + if (written) + ret = 0; + else + ret = -EIO; + } else { + pr_err("%s of type %s is not a valid update file image\n", + data->imagefile, file_type_to_string(filetype)); + return -EINVAL; + } +out: + return ret; +} + +/** + * am33xx_bbu_nand_register_handler - register a NAND update handler + * @device: The nand cdev name (usually "nand0.barebox") + * + * This registers an update handler suitable for updating barebox to NAND. This + * update handler takes a single NAND partition for both the xload images and the + * barebox images. The first four blocks are used for the 4 xload copies, the + * remaining space is divided into two equally sized parts for two barebox images. + * The update handler automatically detects based on the filetype if the xload + * or the 2nd stage barebox shall be updated. + * + * FIXME: Currently for actually loading a barebox image from an xload image + * flashed with this layout a suitable layout has to be registered by the xload + * image using omap_set_barebox_part(). In the next step this should be the + * default. + */ +int am33xx_bbu_nand_register_handler(const char *device) +{ + struct bbu_handler *handler; + int ret; + + handler = xzalloc(sizeof(*handler)); + handler->devicefile = device; + handler->handler = nand_update_handler_complete; + handler->name = "nand"; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} diff --git a/arch/arm/mach-omap/include/mach/bbu.h b/arch/arm/mach-omap/include/mach/bbu.h index c8b0a55acb..94d3f96bb4 100644 --- a/arch/arm/mach-omap/include/mach/bbu.h +++ b/arch/arm/mach-omap/include/mach/bbu.h @@ -23,6 +23,7 @@ int am33xx_bbu_nand_xloadslots_register_handler(const char *name, int num_devicefiles); int am33xx_bbu_nand_slots_register_handler(const char *name, char **devicefile, int num_devicefiles); +int am33xx_bbu_nand_register_handler(const char *device); #else static inline int am33xx_bbu_nand_xloadslots_register_handler(const char *name, char **devicefile, @@ -37,6 +38,11 @@ static inline int am33xx_bbu_nand_slots_register_handler(const char *name, { return 0; } + +static inline int am33xx_bbu_nand_register_handler(const char *device) +{ + return 0; +} #endif #ifdef CONFIG_BAREBOX_UPDATE_AM33XX_EMMC -- cgit v1.2.3