platform: msm_shared: Introduce new functions & update bad block handling
This patch introduces 2 new functions:
qpic_nand_read - general function for reading more then one page of data
qpic_nand_write - general function for writing more then one page of data
flash_block_size and flash_spare_size used to retrieve NAND parameters
When erase/read/write block/page fails the block should be marked bad.
Change-Id: Iab74c33ba9d038e53b5c5728abdb561824dd1f78
diff --git a/include/dev/flash.h b/include/dev/flash.h
index 6c2402d..f2b10db 100644
--- a/include/dev/flash.h
+++ b/include/dev/flash.h
@@ -70,13 +70,14 @@
unsigned offset, void *data, unsigned bytes);
int flash_write(struct ptentry *ptn, unsigned write_extra_bytes, const void *data,
unsigned bytes);
-
static inline int flash_read(struct ptentry *ptn, unsigned offset, void *data,
unsigned bytes)
{
return flash_read_ext(ptn, 0, offset, data, bytes);
}
unsigned flash_page_size(void);
+unsigned flash_block_size(void);
+unsigned flash_spare_size(void);
int flash_ecc_bch_enabled(void);
diff --git a/platform/msm_shared/include/qpic_nand.h b/platform/msm_shared/include/qpic_nand.h
index 34ceb57..f640cf8 100644
--- a/platform/msm_shared/include/qpic_nand.h
+++ b/platform/msm_shared/include/qpic_nand.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2008, Google Inc.
* All rights reserved.
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -349,5 +349,11 @@
qpic_nand_uninit();
/* Api to return the nand base */
uint32_t nand_device_base();
+nand_result_t qpic_nand_read(uint32_t start_page, uint32_t num_pages,
+ unsigned char* buffer, unsigned char* spareaddr);
+nand_result_t qpic_nand_write(uint32_t start_page, uint32_t num_pages,
+ unsigned char* buffer, unsigned write_extra_bytes);
+nand_result_t qpic_nand_block_isbad(unsigned page);
+nand_result_t qpic_nand_blk_erase(uint32_t page);
#endif
diff --git a/platform/msm_shared/qpic_nand.c b/platform/msm_shared/qpic_nand.c
index 7cb57bc..91d0815 100644
--- a/platform/msm_shared/qpic_nand.c
+++ b/platform/msm_shared/qpic_nand.c
@@ -73,6 +73,8 @@
/* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash */
};
+static int qpic_nand_mark_badblock(uint32_t page);
+
static void
qpic_nand_wait_for_cmd_exec(uint32_t num_desc)
{
@@ -826,8 +828,13 @@
return nand_ret;
}
-static int
-qpic_nand_block_isbad(unsigned page)
+/**
+ * qpic_nand_block_isbad() - Checks is given block is bad
+ * @page - number of page the block starts at
+ *
+ * Returns nand_result_t
+ */
+nand_result_t qpic_nand_block_isbad(unsigned page)
{
unsigned cwperpage;
struct cfg_params params;
@@ -895,8 +902,7 @@
/* Function to erase a block on the nand.
* page: Starting page address for the block.
*/
-static int
-qpic_nand_blk_erase(uint32_t page)
+nand_result_t qpic_nand_blk_erase(uint32_t page)
{
struct cfg_params cfg;
struct cmd_element *cmd_list_ptr = ce_array;
@@ -980,6 +986,7 @@
dprintf(CRITICAL,
"NAND Erase error: Block address belongs to bad block: %d\n",
blk_addr);
+ qpic_nand_mark_badblock(page);
return NANDC_RESULT_FAILURE;
}
@@ -987,6 +994,7 @@
if (!(status & PROG_ERASE_OP_RESULT))
return NANDC_RESULT_SUCCESS;
+ qpic_nand_mark_badblock(page);
return NANDC_RESULT_FAILURE;
}
@@ -1340,6 +1348,12 @@
return flash.num_blocks;
}
+unsigned
+flash_spare_size(void)
+{
+ return flash.spare_size;
+}
+
struct ptable *
flash_get_ptable(void)
{
@@ -1540,6 +1554,105 @@
return nand_ret;
}
+/**
+ * qpic_nand_read() - read data
+ * @start_page: number of page to begin reading from
+ * @num_pages: number of pages to read
+ * @buffer: buffer where to store the read data
+ * @spareaddr: buffer where to store spare data.
+ * If null, spare data wont be read
+ *
+ * This function reads @num_pages starting from @start_page and stores the
+ * read data in buffer. Note that it's in the caller responsibility to make
+ * sure the read pages are all from same partition.
+ *
+ * Returns nand_result_t
+ */
+nand_result_t qpic_nand_read(uint32_t start_page, uint32_t num_pages,
+ unsigned char* buffer, unsigned char* spareaddr)
+{
+ unsigned i = 0, ret = 0;
+
+ if (!buffer) {
+ dprintf(CRITICAL, "qpic_nand_read: buffer = null\n");
+ return NANDC_RESULT_PARAM_INVALID;
+ }
+ while (i < num_pages) {
+ ret = qpic_nand_read_page(start_page + i, buffer + flash.page_size * i,
+ spareaddr);
+ i++;
+ if (ret == NANDC_RESULT_BAD_PAGE)
+ qpic_nand_mark_badblock(start_page + i);
+ if (ret) {
+ dprintf(CRITICAL,
+ "qpic_nand_read: reading page %d failed with %d err\n",
+ start_page + i, ret);
+ return ret;
+ }
+ }
+ return NANDC_RESULT_SUCCESS;
+}
+
+/**
+ * qpic_nand_write() - read data
+ * @start_page: number of page to begin writing to
+ * @num_pages: number of pages to write
+ * @buffer: buffer to be written
+ * @write_extra_bytes: true if spare data (ox 0xff) to be written
+ *
+ * This function writes @num_pages starting from @start_page. Note that it's
+ * in the caller responsibility to make sure the written pages are all from
+ * same partition.
+ *
+ * Returns nand_result_t
+ */
+nand_result_t qpic_nand_write(uint32_t start_page, uint32_t num_pages,
+ unsigned char* buffer, unsigned write_extra_bytes)
+{
+ int i = 0, ret = NANDC_RESULT_SUCCESS;
+ uint32_t *spare = (unsigned *)flash_spare_bytes;
+ uint32_t wsize;
+ uint32_t spare_byte_count = 0;
+
+ if (!buffer) {
+ dprintf(CRITICAL, "qpic_nand_write: buffer = null\n");
+ return NANDC_RESULT_PARAM_INVALID;
+ }
+ spare_byte_count = ((flash.cw_size * flash.cws_per_page)- flash.page_size);
+
+ if (write_extra_bytes)
+ wsize = flash.page_size + spare_byte_count;
+ else
+ wsize = flash.page_size;
+
+ memset(spare, 0xff, (spare_byte_count / flash.cws_per_page));
+
+ for (i = 0; i < (int)num_pages; i++) {
+ memcpy(rdwr_buf, buffer, flash.page_size);
+ if (write_extra_bytes) {
+ memcpy(rdwr_buf + flash.page_size,
+ buffer + flash.page_size, spare_byte_count);
+ ret = qpic_nand_write_page(start_page + i,
+ NAND_CFG, rdwr_buf, rdwr_buf + flash.page_size);
+ } else {
+ ret = qpic_nand_write_page(start_page + i,
+ NAND_CFG, rdwr_buf, spare);
+ }
+ if (ret) {
+ dprintf(CRITICAL,
+ "flash_write: write failure @ page %d, block %d\n",
+ start_page + i,
+ (start_page + i) / flash.num_pages_per_blk);
+ if (ret == NANDC_RESULT_BAD_PAGE)
+ qpic_nand_mark_badblock(start_page + i);
+ goto out;
+ }
+ buffer += wsize;
+ }
+out:
+ return ret;
+}
+
/* Function to read a flash partition.
* ptn : Partition to read.
* extra_per_page : Spare data to be read.