/*
- * Copyright (C) 2012-2015 Lothar Waßmann <LW@KARO-electronics.de>
+ * Copyright (C) 2012-2016 Lothar Waßmann <LW@KARO-electronics.de>
*
* See file CREDITS for list of people who contributed to this
* project.
#include <asm/io.h>
#include <linux/sizes.h>
-#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
#include <asm/imx-common/regs-gpmi.h>
#include <asm/imx-common/regs-bch.h>
u32 disbb_search;
};
-struct mx6_dbbt_header {
- u32 checksum;
- u32 fingerprint;
- u32 version;
- u32 number_bb;
- u32 number_pages;
- u8 spare[492];
-};
-
-struct mx6_dbbt {
- u32 nand_number;
- u32 number_bb;
- u32 bb_num[2040 / 4];
-};
-
-struct mx6_ivt {
- u32 magic;
- u32 app_start_addr;
- u32 rsrvd1;
- void *dcd;
- void *boot_data;
- void *self;
- void *csf;
- u32 rsrvd2;
-};
-
-struct mx6_boot_data {
- void *start;
- u32 length;
- u32 plugin;
-};
-
#define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET)
+#define BF_SET_VAL(r, v, bf) r = ((r) & ~bf##_MASK) | (((v) << bf##_OFFSET) & bf##_MASK)
static nand_info_t *mtd = &nand_info[0];
static bool doit;
ecc[i] = calculate_parity_13_8(src[i]);
}
+static struct bch_regs bch_save;
+static struct bch_regs *bch_base = (void *)BCH_BASE_ADDRESS;
+
+/*
+ * Reprogram BCH engine for 40bit ECC on chunks of 128 byte
+ * and 32 byte of metadata as required by the i.MX6UL ROM code.
+ */
+static void tx6_init_bch(void)
+{
+ u32 fl0 = readl(&bch_base->hw_bch_flash0layout0);
+ u32 fl1 = readl(&bch_base->hw_bch_flash0layout1);
+
+ bch_save.hw_bch_flash0layout0 = fl0;
+ bch_save.hw_bch_flash0layout1 = fl1;
+
+ BF_SET_VAL(fl0, 32, BCH_FLASHLAYOUT0_META_SIZE);
+ BF_SET_VAL(fl0, 7, BCH_FLASHLAYOUT0_NBLOCKS);
+
+ BF_SET_VAL(fl0, 0x14, BCH_FLASHLAYOUT0_ECC0);
+ BF_SET_VAL(fl0, 128 / 4, BCH_FLASHLAYOUT0_DATA0_SIZE);
+
+ BF_SET_VAL(fl1, 0x14, BCH_FLASHLAYOUT1_ECCN);
+ BF_SET_VAL(fl1, 128 / 4, BCH_FLASHLAYOUT1_DATAN_SIZE);
+
+ writel(fl0, &bch_base->hw_bch_flash0layout0);
+ writel(fl1, &bch_base->hw_bch_flash0layout1);
+}
+
+static void tx6_restore_bch(void)
+{
+ writel(bch_save.hw_bch_flash0layout0, &bch_base->hw_bch_flash0layout0);
+ writel(bch_save.hw_bch_flash0layout1, &bch_base->hw_bch_flash0layout1);
+}
+
static u32 calc_chksum(void *buf, size_t size)
{
u32 chksum = 0;
return ~chksum;
}
-/*
- Physical organisation of data in NAND flash:
- metadata
- payload chunk 0 (may be empty)
- ecc for metadata + payload chunk 0
- payload chunk 1
- ecc for payload chunk 1
-...
- payload chunk n
- ecc for payload chunk n
- */
-
-static inline int calc_bb_offset(nand_info_t *mtd, struct mx6_fcb *fcb)
-{
- int bb_mark_offset;
- int chunk_data_size = fcb->ecc_blockn_size * 8;
- int chunk_ecc_size = (fcb->ecc_blockn_type << 1) * 13;
- int chunk_total_size = chunk_data_size + chunk_ecc_size;
- int bb_mark_chunk, bb_mark_chunk_offs;
-
- bb_mark_offset = (mtd->writesize - fcb->metadata_size) * 8;
- if (fcb->ecc_block0_size == 0)
- bb_mark_offset -= (fcb->ecc_block0_type << 1) * 13;
-
- bb_mark_chunk = bb_mark_offset / chunk_total_size;
- bb_mark_chunk_offs = bb_mark_offset - (bb_mark_chunk * chunk_total_size);
- if (bb_mark_chunk_offs > chunk_data_size) {
- printf("Unsupported ECC layout; BB mark resides in ECC data: %u\n",
- bb_mark_chunk_offs);
- return -EINVAL;
- }
- bb_mark_offset -= bb_mark_chunk * chunk_ecc_size;
- return bb_mark_offset;
-}
-
/*
* return number of blocks to skip for a contiguous partition
* of given # blocks
int fw2_start_block, int fw_num_blocks)
{
struct gpmi_regs *gpmi_base = (void *)GPMI_BASE_ADDRESS;
- struct bch_regs *bch_base = (void *)BCH_BASE_ADDRESS;
u32 fl0, fl1;
u32 t0;
- int metadata_size;
- int bb_mark_bit_offs;
struct mx6_fcb *fcb;
int fcb_offs;
fl1 = readl(&bch_base->hw_bch_flash0layout1);
t0 = readl(&gpmi_base->hw_gpmi_timing0);
- metadata_size = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE);
+ if (!is_cpu_type(MXC_CPU_MX6UL)) {
+ int metadata_size = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE);
+
+ fcb = buf + ALIGN(metadata_size, 4);
+ fcb_offs = (void *)fcb - buf;
- fcb = buf + ALIGN(metadata_size, 4);
- fcb_offs = (void *)fcb - buf;
+ memset(buf, 0xff, fcb_offs);
+ } else {
+ fcb = buf;
+ fcb_offs = 0;
+ }
- memset(buf, 0xff, fcb_offs);
- memset(fcb, 0x00, sizeof(*fcb));
- memset(fcb + 1, 0xff, mtd->erasesize - fcb_offs - sizeof(*fcb));
+ memset(fcb, 0, mtd->erasesize - fcb_offs);
strncpy((char *)&fcb->fingerprint, "FCB ", 4);
fcb->version = cpu_to_be32(1);
fcb->dbbt_search_area = 0;
- bb_mark_bit_offs = calc_bb_offset(mtd, fcb);
- if (bb_mark_bit_offs < 0)
- return ERR_PTR(bb_mark_bit_offs);
- fcb->bb_mark_byte = bb_mark_bit_offs / 8;
- fcb->bb_mark_startbit = bb_mark_bit_offs % 8;
- fcb->bb_mark_phys_offset = mtd->writesize;
-
- pr_fcb_val(fcb, bb_mark_byte);
- pr_fcb_val(fcb, bb_mark_startbit);
- pr_fcb_val(fcb, bb_mark_phys_offset);
-
fcb->checksum = calc_chksum(&fcb->fingerprint, 512 - 4);
return fcb;
}
printf("Writing FCB to block %d @ %08llx\n", block,
(u64)block * mtd->erasesize);
if (doit) {
- chip->select_chip(mtd, 0);
- ret = chip->write_page(mtd, chip, 0, mtd->writesize,
- buf, 1, page, 0, 1);
+ if (is_cpu_type(MXC_CPU_MX6UL)) {
+ size_t len = mtd->writesize;
+
+ tx6_init_bch();
+ printf("writing block %u from buffer %p\n", block, buf);
+ ret = nand_write(mtd, block * mtd->erasesize, &len, buf);
+ tx6_restore_bch();
+ } else {
+ chip->select_chip(mtd, 0);
+ ret = chip->write_page(mtd, chip, 0, mtd->writesize,
+ buf, 1, page, 0, 1);
+ }
if (ret) {
printf("Failed to write FCB to block %u: %d\n", block, ret);
}
nand_erase_options_t erase_opts = { 0, };
size_t actual;
size_t prg_length = max_len - skip * mtd->erasesize;
- int prg_start = (start_block + skip) * mtd->erasesize;
+ int prg_start = start_block * mtd->erasesize;
- erase_opts.offset = start_block * mtd->erasesize;
+ erase_opts.offset = (start_block - skip) * mtd->erasesize;
erase_opts.length = max_len;
erase_opts.quiet = 1;
if (doit) {
actual = size;
ret = nand_write_skip_bad(mtd, prg_start, &actual, NULL,
- prg_length, addr, WITH_DROP_FFS);
+ prg_length, addr, 0);
if (ret) {
printf("Failed to program flash: %d\n", ret);
return ret;
ret = PTR_ERR(fcb);
goto out;
}
- encode_hamming_13_8(fcb, (void *)fcb + 512, 512);
+ if (!is_cpu_type(MXC_CPU_MX6UL))
+ encode_hamming_13_8(fcb, (void *)fcb + 512, 512);
ret = write_fcb(buf, fcb_start_block);
if (ret) {
}
printf("Programming U-Boot image from %p to block %lu @ %08llx\n",
- buf, fw1_start_block, (u64)fw1_start_block * mtd->erasesize);
+ addr, fw1_start_block, (u64)fw1_start_block * mtd->erasesize);
ret = tx6_prog_uboot(addr, fw1_start_block, fw1_skip, size,
max_len1);