summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Turley <patrick.turley@freescale.com>2010-03-26 17:54:18 -0500
committerPatrick Turley <patrick.turley@freescale.com>2010-03-26 17:55:59 -0500
commitbce7c35ca96a68c2d1b0d156c2cb00abc87cad6f (patch)
tree5116728ff1e1dba3720cdd2387d622542ca7215e
parent49de29931ade68f33ce01b683c702a24a2ad7b6f (diff)
ENGR00122062 Interim i.MX28 NAND Flash driver change to support bootingrel_imx_2.6.31_10.03.00
Changed the driver to detect ECC-based writes to the boot area and write a byte to the OOB that matches the ROM behavior. Signed-off-by: Patrick Turley <patrick.turley@freescale.com>
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi-base.c60
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi.h2
2 files changed, 50 insertions, 12 deletions
diff --git a/drivers/mtd/nand/gpmi1/gpmi-base.c b/drivers/mtd/nand/gpmi1/gpmi-base.c
index 7c91b44678da..fb62a8667194 100644
--- a/drivers/mtd/nand/gpmi1/gpmi-base.c
+++ b/drivers/mtd/nand/gpmi1/gpmi-base.c
@@ -1035,10 +1035,15 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t * buf)
{
struct gpmi_nand_data *g = chip->priv;
+ struct gpmi_platform_data *gpd = g->gpd;
+ uint8_t *bufvirt, *oobvirt;
dma_addr_t bufphys, oobphys;
int err;
+ uint64_t last_write_byte_address;
/* if we can't map it, copy it */
+ bufvirt = (uint8_t *) buf;
+ oobvirt = chip->oob_poi;
bufphys = oobphys = ~0;
if (map_buffers && virt_addr_valid(buf))
@@ -1046,23 +1051,41 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd,
(void *)buf, mtd->writesize,
DMA_TO_DEVICE);
if (dma_mapping_error(&g->dev->dev, bufphys)) {
+ bufvirt = g->data_buffer;
bufphys = g->data_buffer_handle;
memcpy(g->data_buffer, buf, mtd->writesize);
copies++;
}
- /* if OOB is all FF, leave it as such */
- if (!is_ff(chip->oob_poi, mtd->oobsize) || bch_mode()) {
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys)) {
- oobphys = g->oob_buffer_handle;
- memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
- copies++;
- }
- } else
- ff_writes++;
+ if (map_buffers)
+ oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
+ mtd->oobsize, DMA_TO_DEVICE);
+ if (dma_mapping_error(&g->dev->dev, oobphys)) {
+ oobvirt = g->oob_buffer;
+ oobphys = g->oob_buffer_handle;
+ memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
+ copies++;
+ }
+
+ /*
+ * Check if we're writing to the boot area.
+ *
+ * If we're writing to the boot area, then we're almost certainly
+ * writing a boot stream. In that case, we need to hack the data that's
+ * being written.
+ */
+
+ last_write_byte_address = g->last_write_page_address * mtd->writesize;
+
+ if ((gpd->boot_area_size_in_bytes) &&
+ (last_write_byte_address < gpd->boot_area_size_in_bytes)) {
+ /*
+ printk(KERN_INFO
+ "Writing to the boot area at byte:0x%08llx page:0x%08x",
+ last_write_byte_address, g->last_write_page_address);
+ */
+ oobvirt[0] = bufvirt[0];
+ }
/* call ECC */
g->hc->write(g->hc, g->selected_chip, g->cchip->d,
@@ -1348,6 +1371,7 @@ static int gpmi_dev_ready(struct mtd_info *mtd)
*/
static void gpmi_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
+ unsigned i;
struct nand_chip *chip = mtd->priv;
struct gpmi_nand_data *g = chip->priv;
struct mxs_dma_desc **d = g->cchip->d;
@@ -1380,6 +1404,18 @@ static void gpmi_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (g->cmd_buffer_sz == 0)
return;
+ /*
+ * Check if this is a command that introduces a page write. If so, we
+ * need to capture the page address to which we are writing.
+ */
+
+ if (g->cmd_buffer[0] == NAND_CMD_SEQIN) {
+ g->last_write_page_address = 0;
+ for (i = 3; i < g->cmd_buffer_sz; i++)
+ g->last_write_page_address |=
+ g->cmd_buffer[i] << ((i - 3) * 8);
+ }
+
/* output command */
(*d)->cmd.cmd.data = 0;
diff --git a/drivers/mtd/nand/gpmi1/gpmi.h b/drivers/mtd/nand/gpmi1/gpmi.h
index 45db15c3b7ba..072c2ad2f442 100644
--- a/drivers/mtd/nand/gpmi1/gpmi.h
+++ b/drivers/mtd/nand/gpmi1/gpmi.h
@@ -288,6 +288,8 @@ struct gpmi_nand_data {
struct nand_device_info device_info;
+ unsigned last_write_page_address;
+
#if defined(CONFIG_MTD_PARTITIONS)
struct mtd_info *general_use_mtd;
struct mtd_partition *partitions;