summaryrefslogtreecommitdiffstats
path: root/common/imx-bbu-nand-fcb.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2015-06-10 15:13:16 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2015-06-12 08:28:26 +0200
commit22f8077c391c6a226dbb9a5228af8e9840fc0e42 (patch)
treeec43f6f205f5042d0840c35b03a6d0bccd93da2a /common/imx-bbu-nand-fcb.c
parent103b88ace1c85be724bd758fe21366d090315c76 (diff)
downloadbarebox-22f8077c391c6a226dbb9a5228af8e9840fc0e42.tar.gz
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 <s.hauer@pengutronix.de>
Diffstat (limited to 'common/imx-bbu-nand-fcb.c')
-rw-r--r--common/imx-bbu-nand-fcb.c173
1 files changed, 151 insertions, 22 deletions
diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index ca7df97..920b5a1 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 <filetype.h>
#include <common.h>
@@ -28,17 +28,17 @@
#include <linux/sizes.h>
#include <bbu.h>
#include <fs.h>
-#include <mach/bbu.h>
#include <linux/mtd/mtd-abi.h>
#include <linux/mtd/nand_mxs.h>
#include <linux/mtd/mtd.h>
#include <linux/stat.h>
+#include <io.h>
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,127 @@ 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;
+
+ 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 = imx_bbu_nand_update;
+
+ ret = bbu_register_handler(handler);
+ if (ret)
+ free(handler);
+
+ return ret;
+}
+
+#ifdef CONFIG_ARCH_IMX28
+#include <mach/imx28-regs.h>
+
+#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;
- handler = xzalloc(sizeof(*handler));
+ 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 = imx6_bbu_nand_update;
+ handler->handler = imx_bbu_nand_update;
ret = bbu_register_handler(handler);
if (ret)
@@ -489,3 +617,4 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
return ret;
}
+#endif