Merge "qca: Add logic to restrict runmulticore command on secondary cores"
diff --git a/arch/arm/dts/ipq40xx-dk04.dtsi b/arch/arm/dts/ipq40xx-dk04.dtsi
index df68c2e..879fdbd 100644
--- a/arch/arm/dts/ipq40xx-dk04.dtsi
+++ b/arch/arm/dts/ipq40xx-dk04.dtsi
@@ -98,7 +98,7 @@
gpio = <23>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -109,7 +109,7 @@
gpio = <24>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -120,7 +120,7 @@
gpio = <25>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -130,7 +130,7 @@
gpio4 {
gpio = <26>;
func = <1>;
- pull = <GPIO_PULL_UP>;
+ pull = <DRV_TYPE_C>;
drvstr = <GPIO_10MA>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
@@ -142,7 +142,7 @@
gpio = <27>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_16MA>;
+ drvstr = <DRV_TYPE_A>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -153,7 +153,7 @@
gpio = <28>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -164,7 +164,7 @@
gpio = <29>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -175,7 +175,7 @@
gpio = <30>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -186,7 +186,7 @@
gpio = <31>;
func = <1>;
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -196,8 +196,8 @@
gpio10 {
gpio = <32>;
func = <1>;
- pull = <GPIO_NO_PULL>;
- drvstr = <GPIO_10MA>;
+ pull = <GPIO_PULL_UP>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
diff --git a/arch/arm/dts/ipq40xx-dk07.dtsi b/arch/arm/dts/ipq40xx-dk07.dtsi
index dda45df..bebf5cf 100644
--- a/arch/arm/dts/ipq40xx-dk07.dtsi
+++ b/arch/arm/dts/ipq40xx-dk07.dtsi
@@ -48,9 +48,9 @@
mmc_gpio {
gpio1 {
gpio = <23>;
- func = <1>;
+ func = <1>; /* sdio0 */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -59,9 +59,9 @@
gpio2 {
gpio = <24>;
- func = <1>;
+ func = <1>; /* sdio1 */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -70,9 +70,9 @@
gpio3 {
gpio = <25>;
- func = <1>;
+ func = <1>; /* sdio2 */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -81,9 +81,9 @@
gpio4 {
gpio = <26>;
- func = <1>;
+ func = <1>; /* sdio3 */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -92,9 +92,9 @@
gpio5 {
gpio = <27>;
- func = <1>;
+ func = <1>; /* sdio_clk */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_16MA>;
+ drvstr = <DRV_TYPE_A>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
@@ -103,9 +103,9 @@
gpio6 {
gpio = <28>;
- func = <1>;
+ func = <1>; /* sdio_cmd */
pull = <GPIO_PULL_UP>;
- drvstr = <GPIO_10MA>;
+ drvstr = <DRV_TYPE_C>;
oe = <GPIO_OE_DISABLE>;
vm = <GPIO_VM_ENABLE>;
od_en = <GPIO_OD_DISABLE>;
diff --git a/arch/arm/include/asm/arch-qca-common/qpic_nand.h b/arch/arm/include/asm/arch-qca-common/qpic_nand.h
index 64460c8..41f9fbc 100644
--- a/arch/arm/include/asm/arch-qca-common/qpic_nand.h
+++ b/arch/arm/include/asm/arch-qca-common/qpic_nand.h
@@ -130,6 +130,8 @@
#define NAND_ERASED_CW_DETECT_STATUS_PAGE_ALL_ERASED 7
#define NAND_ERASED_CW_DETECT_STATUS_CODEWORD_ALL_ERASED 6
#define NAND_ERASED_CW_DETECT_STATUS_CODEWORD_ERASED 4
+#define NAND_CW_ERASED (BIT(NAND_ERASED_CW_DETECT_STATUS_CODEWORD_ERASED) | \
+ BIT(NAND_ERASED_CW_DETECT_STATUS_CODEWORD_ALL_ERASED))
#define NAND_ERASED_CW_DETECT_CFG_RESET_CTRL 1
#define NAND_ERASED_CW_DETECT_CFG_ACTIVATE_CTRL 0
@@ -159,6 +161,8 @@
#define PROG_ERASE_OP_RESULT (1 << 7)
+/* NAND buffer status */
+#define NAND_BUFFER_UNCORRECTABLE (1 << 8)
#define NUM_ERRORS_MASK 0x0000001f
#define NUM_ERRORS(i) ((i) << 0)
@@ -288,8 +292,7 @@
NANDC_RESULT_TIMEOUT = 2,
NANDC_RESULT_PARAM_INVALID = 3,
NANDC_RESULT_DEV_NOT_SUPPORTED = 4,
- NANDC_RESULT_BAD_PAGE = 5,
- NANDC_RESULT_BAD_BLOCK = 6,
+ NANDC_RESULT_BAD_BLOCK = 5,
} nand_result_t;
enum nand_bad_block_value
@@ -405,10 +408,10 @@
struct qpic_nand_bam_pipes pipes;
};
-enum nand_ecc_width
-{
- NAND_WITH_4_BIT_ECC,
- NAND_WITH_8_BIT_ECC,
+struct read_stats {
+ uint32_t flash_sts;
+ uint32_t buffer_sts;
+ uint32_t erased_cw_sts;
};
struct qpic_nand_dev {
@@ -420,7 +423,6 @@
unsigned block_size;
unsigned spare_size;
unsigned num_blocks;
- enum nand_ecc_width ecc_width;
unsigned num_pages_per_blk;
unsigned num_pages_per_blk_mask;
unsigned widebus;
@@ -428,6 +430,9 @@
unsigned cw_size;
unsigned cws_per_page;
unsigned bad_blk_loc;
+ unsigned ecc_bytes_hw;
+ unsigned spare_bytes;
+ unsigned bbm_size;
unsigned dev_cfg;
uint32_t cfg0;
uint32_t cfg1;
@@ -440,7 +445,10 @@
unsigned char *pad_oob;
unsigned char *zero_page;
unsigned char *zero_oob;
+ unsigned char *tmp_datbuf;
+ unsigned char *tmp_oobbuf;
uint16_t timing_mode_support;
+ struct read_stats stats[QPIC_NAND_MAX_CWS_IN_PAGE];
};
void qpic_nand_init(void);
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index 42862d9..7815bdc 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -135,8 +135,7 @@
flash = dev_get_uclass_priv(new);
#else
- if (flash)
- spi_flash_free(flash);
+ spi_flash_free(flash);
new = spi_flash_probe(bus, cs, speed, mode);
flash = new;
diff --git a/common/env_sf.c b/common/env_sf.c
index 8463f26..d079aaf 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -214,8 +214,6 @@
}
err_read:
- spi_flash_free(env_flash);
- env_flash = NULL;
out:
free(tmp_env1);
free(tmp_env2);
@@ -316,7 +314,6 @@
if (ret)
gd->env_valid = 1;
out:
- spi_flash_free(env_flash);
if (buf)
free(buf);
env_flash = NULL;
diff --git a/drivers/mtd/nand/qpic_nand.c b/drivers/mtd/nand/qpic_nand.c
index faa9498..dfaecd3 100644
--- a/drivers/mtd/nand/qpic_nand.c
+++ b/drivers/mtd/nand/qpic_nand.c
@@ -53,6 +53,10 @@
static struct bam_instance bam;
struct nand_ecclayout fake_ecc_layout;
+static int
+qpic_nand_read_page(struct mtd_info *mtd, uint32_t page,
+ enum nand_cfg_value cfg_mode, struct mtd_oob_ops *ops);
+
static const struct udevice_id qpic_ver_ids[] = {
{ .compatible = "qcom,qpic-nand.1.4.20", .data = QCA_QPIC_V1_4_20 },
{ .compatible = "qcom,qpic-nand.1.5.20", .data = QCA_QPIC_V1_5_20 },
@@ -171,48 +175,52 @@
qpic_nand_wait_for_cmd_exec(1);
}
-static nand_result_t
-qpic_nand_check_status(struct mtd_info *mtd, uint32_t status)
+static int
+qpic_nand_check_read_status(struct mtd_info *mtd, struct read_stats *stats)
{
- uint32_t erase_sts;
+ uint32_t status = stats->flash_sts;
/* Check for errors */
- if (status & NAND_FLASH_ERR) {
+ if (!(status & NAND_FLASH_ERR)) {
+ uint32_t corrected = stats->buffer_sts & NUM_ERRORS_MASK;
+ mtd->ecc_stats.corrected += corrected;
+ return corrected;
+ }
+
+ if (status & NAND_FLASH_MPU_ERR)
+ return -EPERM;
+
+ if (status & NAND_FLASH_TIMEOUT_ERR)
+ return -ETIMEDOUT;
+
+ if (stats->buffer_sts & NAND_BUFFER_UNCORRECTABLE) {
/* Check if this is an ECC error on an erased page. */
- if (status & NAND_FLASH_OP_ERR) {
- erase_sts = qpic_nand_read_reg(
- NAND_ERASED_CW_DETECT_STATUS, 0);
- if ((erase_sts &
- (1 << NAND_ERASED_CW_DETECT_STATUS_PAGE_ALL_ERASED))) {
- /* Mask the OP ERROR. */
- status &= ~NAND_FLASH_OP_ERR;
- qpic_nand_erased_status_reset(ce_array, 0);
- }
- }
-
- /* ECC error flagged on an erased page read.
- * Ignore and return success.
- */
- if (!(status & NAND_FLASH_ERR))
- return NANDC_RESULT_SUCCESS;
-
- printf("Nand Flash error. Status = %d\n", status);
-
- if (status & NAND_FLASH_OP_ERR) {
- mtd->ecc_stats.failed++;
+ if ((stats->erased_cw_sts & NAND_CW_ERASED) != NAND_CW_ERASED)
return -EBADMSG;
- }
+
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static int
+qpic_nand_check_status(struct mtd_info *mtd, uint32_t status)
+{
+ /* Check for errors */
+ if (status & NAND_FLASH_ERR) {
+ printf("Nand Flash error. Status = %d\n", status);
if (status & NAND_FLASH_MPU_ERR)
return -EPERM;
if (status & NAND_FLASH_TIMEOUT_ERR)
return -ETIMEDOUT;
- else
- return NANDC_RESULT_FAILURE;
+
+ return -EIO;
}
- return NANDC_RESULT_SUCCESS;
+ return 0;
}
static uint32_t
@@ -599,9 +607,9 @@
dev->timing_mode_support = param_page->timing_mode_support;
if (ecc_bits >= 8)
- dev->ecc_width = NAND_WITH_8_BIT_ECC;
+ mtd->ecc_strength = 8;
else
- dev->ecc_width = NAND_WITH_4_BIT_ECC;
+ mtd->ecc_strength = 4;
onfi_save_params_err:
return onfi_ret;
@@ -626,41 +634,39 @@
/* Codeword Size = UD_SIZE_BYTES + ECC_PARITY_SIZE_BYTES
* + SPARE_SIZE_BYTES + Bad Block size
*/
- if (dev->ecc_width & NAND_WITH_8_BIT_ECC) {
+ if (mtd->ecc_strength == 8) {
dev->cw_size = NAND_CW_SIZE_8_BIT_ECC;
/* Use 8-bit ecc */
dev->ecc_bch_cfg |= (1 << NAND_DEV0_ECC_MODE_SHIFT);
if (dev->widebus) {
- /* spare size bytes in each CW */
- dev->cfg0 |= (0 << NAND_DEV0_CFG0_SPARE_SZ_BYTES_SHIFT);
- /* parity bytes in each CW */
- dev->ecc_bch_cfg |= (14 <<
- NAND_DEV0_ECC_PARITY_SZ_BYTES_SHIFT);
+ dev->ecc_bytes_hw = 14;
+ dev->spare_bytes = 0;
+ dev->bbm_size = 2;
} else {
- /* spare size bytes in each CW */
- dev->cfg0 |= (2 << NAND_DEV0_CFG0_SPARE_SZ_BYTES_SHIFT);
- /* parity bytes in each CW */
- dev->ecc_bch_cfg |= (13 <<
- NAND_DEV0_ECC_PARITY_SZ_BYTES_SHIFT);
+ dev->ecc_bytes_hw = 13;
+ dev->spare_bytes = 2;
+ dev->bbm_size = 1;
}
} else {
dev->cw_size = NAND_CW_SIZE_4_BIT_ECC;
if (dev->widebus) {
- /* spare size bytes in each CW */
- dev->cfg0 |= (2 << NAND_DEV0_CFG0_SPARE_SZ_BYTES_SHIFT);
- /* parity bytes in each CW */
- dev->ecc_bch_cfg |= (8 <<
- NAND_DEV0_ECC_PARITY_SZ_BYTES_SHIFT);
+ dev->ecc_bytes_hw = 8;
+ dev->spare_bytes = 2;
+ dev->bbm_size = 2;
} else {
- /* spare size bytes in each CW */
- dev->cfg0 |= (4 << NAND_DEV0_CFG0_SPARE_SZ_BYTES_SHIFT);
- /* parity bytes in each CW */
- dev->ecc_bch_cfg |= (7 <<
- NAND_DEV0_ECC_PARITY_SZ_BYTES_SHIFT);
+ dev->ecc_bytes_hw = 7;
+ dev->spare_bytes = 4;
+ dev->bbm_size = 1;
}
}
+ /* spare size bytes in each CW */
+ dev->cfg0 |= dev->spare_bytes << NAND_DEV0_CFG0_SPARE_SZ_BYTES_SHIFT;
+ /* parity bytes in each CW */
+ dev->ecc_bch_cfg |=
+ dev->ecc_bytes_hw << NAND_DEV0_ECC_PARITY_SZ_BYTES_SHIFT;
+
qpic_oob_size = dev->cw_size * dev->cws_per_page - mtd->writesize;
if (mtd->oobsize < qpic_oob_size) {
@@ -1448,7 +1454,7 @@
else
qpic_nand_get_info_flash_dev(mtd, flash_dev);
- dev->ecc_width = NAND_WITH_4_BIT_ECC;
+ mtd->ecc_strength = 4;
dev->num_blocks = mtd->size;
dev->num_blocks /= (dev->block_size);
@@ -1587,6 +1593,95 @@
}
static int
+qpic_nand_check_erased_buf(unsigned char *buf, int len, int bitflips_threshold)
+{
+ int bitflips = 0;
+
+ for (; len > 0; len--, buf++) {
+ bitflips += 8 - hweight8(*buf);
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ return bitflips;
+}
+
+/*
+ * Now following logic is being added to identify the erased codeword
+ * bitflips.
+ * 1. Maintain the bitmasks for the codewords which generated uncorrectable
+ * error.
+ * 2. Read the raw data again in temp buffer and count the number of zeros.
+ * Since spare bytes are unused in ECC layout and won’t affect ECC
+ * correctability so no need to count number of zero in spare bytes.
+ * 3. If the number of zero is below ECC correctability then it can be
+ * treated as erased CW. In this case, make all the data/oob of actual user
+ * buffers as 0xff.
+ */
+static int
+qpic_nand_check_erased_page(struct mtd_info *mtd, uint32_t page,
+ unsigned char *datbuf,
+ unsigned char *oobbuf,
+ unsigned int uncorrectable_err_cws,
+ unsigned int *max_bitflips)
+{
+ struct mtd_oob_ops raw_page_ops;
+ struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd);
+ unsigned char *tmp_datbuf;
+ unsigned int tmp_datasize, datasize, oobsize;
+ int i, start_cw, last_cw, ret, data_bitflips;
+
+ raw_page_ops.mode = MTD_OPS_RAW;
+ raw_page_ops.len = mtd->writesize;
+ raw_page_ops.ooblen = mtd->oobsize;
+ raw_page_ops.datbuf = dev->tmp_datbuf;
+ raw_page_ops.oobbuf = dev->tmp_oobbuf;
+ raw_page_ops.retlen = 0;
+ raw_page_ops.oobretlen = 0;
+
+ ret = qpic_nand_read_page(mtd, page, NAND_CFG_RAW, &raw_page_ops);
+ if (ret)
+ return ret;
+
+ start_cw = ffs(uncorrectable_err_cws) - 1;
+ last_cw = fls(uncorrectable_err_cws);
+
+ tmp_datbuf = dev->tmp_datbuf + start_cw * dev->cw_size;
+ tmp_datasize = dev->cw_size - dev->spare_bytes;
+ datasize = DATA_BYTES_IN_IMG_PER_CW;
+ datbuf += start_cw * datasize;
+
+ for (i = start_cw; i < last_cw;
+ i++, datbuf += datasize, tmp_datbuf += dev->cw_size) {
+ if (!(BIT(i) & uncorrectable_err_cws))
+ continue;
+
+ data_bitflips =
+ qpic_nand_check_erased_buf(tmp_datbuf, tmp_datasize,
+ mtd->ecc_strength);
+ if (data_bitflips < 0) {
+ mtd->ecc_stats.failed++;
+ continue;
+ }
+
+ *max_bitflips =
+ max_t(unsigned int, *max_bitflips, data_bitflips);
+
+ if (i == dev->cws_per_page - 1) {
+ oobsize = dev->cws_per_page << 2;
+ datasize = DATA_BYTES_IN_IMG_PER_CW - oobsize;
+ if (oobbuf)
+ memset(oobbuf, 0xff, oobsize);
+ }
+
+ if (datbuf)
+ memset(datbuf, 0xff, datasize);
+ }
+
+ return 0;
+}
+
+static int
qpic_nand_read_page(struct mtd_info *mtd, uint32_t page,
enum nand_cfg_value cfg_mode,
struct mtd_oob_ops *ops)
@@ -1594,8 +1689,7 @@
struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd);
struct cfg_params params;
uint32_t ecc;
- uint32_t flash_sts[QPIC_NAND_MAX_CWS_IN_PAGE];
- uint32_t buffer_sts[QPIC_NAND_MAX_CWS_IN_PAGE];
+ struct read_stats *stats = dev->stats;
uint32_t addr_loc_0;
uint32_t addr_loc_1;
struct cmd_element *cmd_list_ptr = ce_array;
@@ -1606,12 +1700,12 @@
int nand_ret = NANDC_RESULT_SUCCESS;
uint8_t flags = 0;
uint32_t *cmd_list_temp = NULL;
- uint32_t num_errors;
uint16_t data_bytes;
uint16_t ud_bytes_in_last_cw;
uint16_t oob_bytes;
- unsigned char *buffer;
- unsigned char *spareaddr;
+ unsigned char *buffer, *ops_datbuf = ops->datbuf;
+ unsigned char *spareaddr, *ops_oobbuf = ops->oobbuf;
+ unsigned int max_bitflips = 0, uncorrectable_err_cws = 0;
params.addr0 = page << 16;
params.addr1 = (page >> 16) & 0xff;
@@ -1735,7 +1829,7 @@
num_cmd_desc++;
bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_STATUS,
- (uint32_t)((addr_t)&(flash_sts[i])),
+ (uint32_t)((addr_t)&(stats[i].flash_sts)),
CE_READ_TYPE);
cmd_list_temp = (uint32_t *)cmd_list_ptr;
@@ -1743,10 +1837,15 @@
cmd_list_ptr++;
bam_add_cmd_element(cmd_list_ptr, NAND_BUFFER_STATUS,
- (uint32_t)((addr_t)&(buffer_sts[i])),
+ (uint32_t)((addr_t)&(stats[i].buffer_sts)),
CE_READ_TYPE);
cmd_list_ptr++;
+ bam_add_cmd_element(cmd_list_ptr, NAND_ERASED_CW_DETECT_STATUS,
+ (uint32_t)((addr_t)&(stats[i].erased_cw_sts)),
+ CE_READ_TYPE);
+ cmd_list_ptr++;
+
if (i == (dev->cws_per_page) - 1) {
flags = BAM_DESC_CMD_FLAG | BAM_DESC_UNLOCK_FLAG;
} else
@@ -1794,22 +1893,39 @@
/* Check status */
for (i = 0; i < (dev->cws_per_page) ; i ++) {
- flash_sts[i] = qpic_nand_check_status(mtd, flash_sts[i]);
- if (flash_sts[i]) {
- printf("NAND page read failed. page: %x status %x\n",
- page, flash_sts[i]);
+ if (cfg_mode == NAND_CFG_RAW)
+ nand_ret = qpic_nand_check_status(mtd,
+ stats[i].flash_sts);
+ else
+ nand_ret = qpic_nand_check_read_status(mtd, &stats[i]);
+
+ if (nand_ret < 0) {
+ if (nand_ret == -EBADMSG) {
+ uncorrectable_err_cws |= BIT(i);
+ continue;
+ }
+
goto qpic_nand_read_page_error;
}
+
+ max_bitflips = max_t(unsigned int, max_bitflips, nand_ret);
}
- for (i = 0; i < (dev->cws_per_page); i++) {
- num_errors = buffer_sts[i];
- num_errors &= NUM_ERRORS_MASK;
- if(num_errors)
- mtd->ecc_stats.corrected++;
+ if (uncorrectable_err_cws) {
+ nand_ret = qpic_nand_check_erased_page(mtd, page, ops_datbuf,
+ ops_oobbuf,
+ uncorrectable_err_cws,
+ &max_bitflips);
+ if (nand_ret < 0)
+ goto qpic_nand_read_page_error;
}
+
+ return max_bitflips;
+
qpic_nand_read_page_error:
-return nand_ret;
+ printf("NAND page read failed. page: %x status %x\n",
+ page, nand_ret);
+ return nand_ret;
}
static int qpic_nand_read_oob(struct mtd_info *mtd, loff_t to,
@@ -1820,9 +1936,9 @@
struct nand_chip *chip = MTD_NAND_CHIP(mtd);
uint32_t start_page;
uint32_t num_pages;
- loff_t offs;
- uint32_t corrected;
enum nand_cfg_value cfg_mode;
+ unsigned int max_bitflips = 0;
+ unsigned int ecc_failures = mtd->ecc_stats.failed;
/* We don't support MTD_OOB_PLACE as of yet. */
if (ops->mode == MTD_OPS_PLACE_OOB)
@@ -1849,8 +1965,6 @@
start_page = ((to >> chip->page_shift));
num_pages = qpic_get_read_page_count(mtd, ops);
- corrected = mtd->ecc_stats.corrected;
-
for (i = 0; i < num_pages; i++) {
struct mtd_oob_ops page_ops;
page_ops.mode = ops->mode;
@@ -1863,25 +1977,24 @@
ret = qpic_nand_read_page(mtd, start_page + i, cfg_mode,
&page_ops);
- if (ret == NANDC_RESULT_BAD_PAGE) {
- offs = (start_page + i) << chip->page_shift;
- qpic_nand_mark_badblock(mtd, offs);
- }
- if (ret) {
- printf("qpic_nand_read: reading page %d failed with %d err \n",
- start_page + i, ret);
+ if (ret < 0) {
+ printf("%s: reading page %d failed with %d err\n",
+ __func__, start_page + i, ret);
return ret;
}
+
+ max_bitflips = max_t(unsigned int, max_bitflips, ret);
qpic_nand_read_datcopy(mtd, ops);
qpic_nand_read_oobcopy(mtd, ops);
}
- if (mtd->ecc_stats.corrected != corrected) {
- ret = -EUCLEAN;
- return ret;
+ if (ecc_failures != mtd->ecc_stats.failed) {
+ printf("%s: ecc failure while reading from %llx\n",
+ __func__, to);
+ return -EBADMSG;
}
- return NANDC_RESULT_SUCCESS;
+ return max_bitflips;
}
/**
@@ -1989,7 +2102,6 @@
struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd);
int i, ret = NANDC_RESULT_SUCCESS;
struct nand_chip *chip = MTD_NAND_CHIP(mtd);
- loff_t offs;
u_long start_page;
u_long num_pages;
enum nand_cfg_value cfg_mode;
@@ -2045,10 +2157,6 @@
printf("flash_write: write failure @ page %ld, block %ld\n",
start_page + i,
(start_page + i) / (dev->num_pages_per_blk));
- if (ret == NANDC_RESULT_BAD_PAGE) {
- offs = (start_page + i) << chip->page_shift;
- qpic_nand_mark_badblock(mtd, offs);
- }
goto out;
} else {
qpic_nand_write_datinc(mtd, ops);
@@ -2257,6 +2365,7 @@
mtd->_sync = qpic_nand_sync;
mtd->ecclayout = NULL;
+ mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
chip->page_shift = ffs(mtd->writesize) - 1;
chip->phys_erase_shift = ffs(mtd->erasesize) - 1;
@@ -2353,10 +2462,11 @@
dev = MTD_QPIC_NAND_DEV(mtd);
qpic_nand_mtd_params(mtd);
- alloc_size = (mtd->writesize /* For dev->pad_dat */
- + mtd->oobsize /* For dev->pad_oob */
- + mtd->writesize /* For dev->zero_page */
- + mtd->oobsize); /* For dev->zero_oob */
+ /*
+ * allocate buffer for dev->pad_dat, dev->pad_oob, dev->zero_page,
+ * dev->zero_oob, dev->tmp_datbuf, dev->tmp_oobbuf
+ */
+ alloc_size = 3 * (mtd->writesize + mtd->oobsize);
dev->buffers = malloc(alloc_size);
if (dev->buffers == NULL) {
@@ -2380,6 +2490,11 @@
memset(dev->zero_page, 0x0, mtd->writesize);
memset(dev->zero_oob, 0x0, mtd->oobsize);
+ dev->tmp_datbuf = buf;
+ buf += mtd->writesize;
+ dev->tmp_oobbuf = buf;
+ buf += mtd->oobsize;
+
/* Register with MTD subsystem. */
ret = nand_register(CONFIG_QPIC_NAND_NAND_INFO_IDX);
if (ret < 0) {
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 0cafc29..071c42d 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -17,6 +17,8 @@
#include "sf_internal.h"
+struct spi_flash *spi_flash_ptr[MAX_SF_BUS_NUM][MAX_SF_CS_NUM] = {NULL};
+
/**
* spi_flash_probe_slave() - Probe for a SPI flash device on a bus
*
@@ -83,10 +85,16 @@
{
struct spi_slave *bus;
+ if (spi_flash_ptr[busnum][cs] != NULL)
+ return spi_flash_ptr[busnum][cs];
+
bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
if (!bus)
return NULL;
- return spi_flash_probe_tail(bus);
+
+ spi_flash_ptr[busnum][cs] = spi_flash_probe_tail(bus);
+
+ return spi_flash_ptr[busnum][cs];
}
#ifdef CONFIG_OF_SPI_FLASH
@@ -104,11 +112,15 @@
void spi_flash_free(struct spi_flash *flash)
{
+ if (flash) {
#ifdef CONFIG_SPI_FLASH_MTD
- spi_flash_mtd_unregister();
+ spi_flash_mtd_unregister();
#endif
- spi_free_slave(flash->spi);
- free(flash);
+ spi_free_slave(flash->spi);
+ free(flash);
+ }
+
+ memset(spi_flash_ptr, NULL, sizeof(spi_flash_ptr));
}
#else /* defined CONFIG_DM_SPI_FLASH */
diff --git a/include/dt-bindings/qcom/gpio-ipq40xx.h b/include/dt-bindings/qcom/gpio-ipq40xx.h
index 57829d2..6074692 100644
--- a/include/dt-bindings/qcom/gpio-ipq40xx.h
+++ b/include/dt-bindings/qcom/gpio-ipq40xx.h
@@ -55,6 +55,12 @@
#define GPIO_14MA 6
#define GPIO_16MA 7
+/* GPIO TLMM for IPQ40XX: Drive Strength */
+#define DRV_TYPE_A 7
+#define DRV_TYPE_B 3
+#define DRV_TYPE_C 1
+#define DRV_TYPE_D 0
+
/* GPIO TLMM: Status */
#define GPIO_OE_DISABLE 0
#define GPIO_OE_ENABLE 1
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 4a51b5f..995d123 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -30,6 +30,8 @@
#ifndef CONFIG_SF_DEFAULT_BUS
# define CONFIG_SF_DEFAULT_BUS 0
#endif
+#define MAX_SF_BUS_NUM 5
+#define MAX_SF_CS_NUM 5
struct spi_slave;