[PATCH 2/2] mtd: rawnand: qcom: Add NAND controller support for SDX55

From: Manivannan Sadhasivam
Date: Thu Nov 26 2020 - 03:57:33 EST


SDX55 uses QPIC version 2.0.0 IP for the NAND controller support.
In this version, DEV_CMD_* registers are moved to operational state,
hence CPU access in BAM mode is restricted. So, skip accessing these
registers and also use a different config for reading ONFI parameters.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
---
drivers/mtd/nand/raw/qcom_nandc.c | 68 +++++++++++++++++++++++--------
1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 777fb0de0680..c7e243dc9b2c 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -145,6 +145,7 @@
#define OP_PAGE_READ 0x2
#define OP_PAGE_READ_WITH_ECC 0x3
#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
+#define OP_PAGE_READ_ONFI_READ 0x5
#define OP_PROGRAM_PAGE 0x6
#define OP_PAGE_PROGRAM_WITH_ECC 0x7
#define OP_PROGRAM_PAGE_SPARE 0x9
@@ -460,12 +461,14 @@ struct qcom_nand_host {
* @ecc_modes - ecc mode for NAND
* @is_bam - whether NAND controller is using BAM
* @is_qpic - whether NAND CTRL is part of qpic IP
+ * @qpic_v2 - flag to indicate QPIC IP version 2
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
*/
struct qcom_nandc_props {
u32 ecc_modes;
bool is_bam;
bool is_qpic;
+ bool qpic_v2;
u32 dev_cmd_reg_start;
};

@@ -1164,7 +1167,13 @@ static int nandc_param(struct qcom_nand_host *host)
* in use. we configure the controller to perform a raw read of 512
* bytes to read onfi params
*/
- nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | PAGE_ACC | LAST_PAGE);
+ if (nandc->props->qpic_v2)
+ nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ |
+ PAGE_ACC | LAST_PAGE);
+ else
+ nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ |
+ PAGE_ACC | LAST_PAGE);
+
nandc_set_reg(nandc, NAND_ADDR0, 0);
nandc_set_reg(nandc, NAND_ADDR1, 0);
nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
@@ -1180,21 +1189,28 @@ static int nandc_param(struct qcom_nand_host *host)
| 1 << DEV0_CFG1_ECC_DISABLE);
nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);

- /* configure CMD1 and VLD for ONFI param probing */
- nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
- (nandc->vld & ~READ_START_VLD));
- nandc_set_reg(nandc, NAND_DEV_CMD1,
- (nandc->cmd1 & ~(0xFF << READ_ADDR))
- | NAND_CMD_PARAM << READ_ADDR);
+ /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
+ if (!nandc->props->qpic_v2) {
+ nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
+ (nandc->vld & ~READ_START_VLD));
+ nandc_set_reg(nandc, NAND_DEV_CMD1,
+ (nandc->cmd1 & ~(0xFF << READ_ADDR))
+ | NAND_CMD_PARAM << READ_ADDR);
+ }

nandc_set_reg(nandc, NAND_EXEC_CMD, 1);

- nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
- nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
+ if (!nandc->props->qpic_v2) {
+ nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
+ nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
+ }
+
nandc_set_read_loc(nandc, 0, 0, 512, 1);

- write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
- write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+ if (!nandc->props->qpic_v2) {
+ write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
+ write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+ }

nandc->buf_count = 512;
memset(nandc->data_buffer, 0xff, nandc->buf_count);
@@ -1205,8 +1221,10 @@ static int nandc_param(struct qcom_nand_host *host)
nandc->buf_count, 0);

/* restore CMD1 and VLD regs */
- write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
- write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
+ if (!nandc->props->qpic_v2) {
+ write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
+ write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
+ }

return 0;
}
@@ -2770,8 +2788,10 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
/* kill onenand */
if (!nandc->props->is_qpic)
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
- nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
- NAND_DEV_CMD_VLD_VAL);
+
+ if (!nandc->props->qpic_v2)
+ nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
+ NAND_DEV_CMD_VLD_VAL);

/* enable ADM or BAM DMA */
if (nandc->props->is_bam) {
@@ -2791,8 +2811,10 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
}

/* save the original values of these registers */
- nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
- nandc->vld = NAND_DEV_CMD_VLD_VAL;
+ if (!nandc->props->qpic_v2) {
+ nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
+ nandc->vld = NAND_DEV_CMD_VLD_VAL;
+ }

return 0;
}
@@ -3050,6 +3072,14 @@ static const struct qcom_nandc_props ipq8074_nandc_props = {
.dev_cmd_reg_start = 0x7000,
};

+static const struct qcom_nandc_props sdx55_nandc_props = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+ .is_bam = true,
+ .is_qpic = true,
+ .qpic_v2 = true,
+ .dev_cmd_reg_start = 0x7000,
+};
+
/*
* data will hold a struct pointer containing more differences once we support
* more controller variants
@@ -3067,6 +3097,10 @@ static const struct of_device_id qcom_nandc_of_match[] = {
.compatible = "qcom,ipq8074-nand",
.data = &ipq8074_nandc_props,
},
+ {
+ .compatible = "qcom,sdx55-nand",
+ .data = &sdx55_nandc_props,
+ },
{}
};
MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
--
2.25.1