mirror of
https://github.com/hzyitc/openwrt-redmi-ax3000.git
synced 2025-12-16 16:31:57 +00:00
398 lines
13 KiB
Diff
398 lines
13 KiB
Diff
From 64cb8eaaa6b3f987d5e8126278f6f829d252d4e8 Mon Sep 17 00:00:00 2001
|
|
From: Md Sadre Alam <mdalam@codeaurora.org>
|
|
Date: Wed, 8 Jul 2020 10:40:59 +0530
|
|
Subject: [PATCH 3/7] mtd: rawnand: qcom: Add initial support for qspi nand
|
|
|
|
This change will add initial support for qspi (serial nand).
|
|
|
|
QPIC Version v.2.0 onwards supports serial nand as well so this
|
|
change will initialize all required register to enable qspi (serial
|
|
nand).
|
|
|
|
This change is supporting very basic functionality of qspi nand flash.
|
|
|
|
1. Reset device (Reset QSPI NAND device).
|
|
|
|
2. Device detection (Read id QSPI NAND device).
|
|
|
|
Signed-off-by: Md Sadre Alam <mdalam@codeaurora.org>
|
|
Change-Id: I5f29df80bcb8e58a1938eced1a8d88c237aceb1d
|
|
|
|
Pick from https://git.codelinaro.org/clo/qsdk/oss/kernel/linux-ipq-5.4/-/commit/dbd01aa96d9d5bf5978e3c6ef2a4118ce7cc0bba
|
|
|
|
Signed-off-by: hzy <hzyitc@outlook.com>
|
|
---
|
|
drivers/mtd/nand/raw/nand_ids.c | 13 +++
|
|
drivers/mtd/nand/raw/qcom_nandc.c | 168 ++++++++++++++++++++++++++++--
|
|
2 files changed, 171 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
|
|
index ba27902fc54b..03e472055d9e 100644
|
|
--- a/drivers/mtd/nand/raw/nand_ids.c
|
|
+++ b/drivers/mtd/nand/raw/nand_ids.c
|
|
@@ -53,6 +53,19 @@ struct nand_flash_dev nand_flash_ids[] = {
|
|
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
|
NAND_ECC_INFO(40, SZ_1K), 4 },
|
|
|
|
+ {"GD5F1GQ4RE9IG SPI NAND 1G 1.8V 4-bit",
|
|
+ { .id = {0xc8, 0xc1} },
|
|
+ SZ_2K, SZ_128, SZ_128K, 0, 2, 128, NAND_ECC_INFO(8, SZ_512) },
|
|
+ {"GD5F1GQ4RE9IH SPI NAND 1G 1.8V 4-bit",
|
|
+ { .id = {0xc8, 0xc9} },
|
|
+ SZ_2K, SZ_128, SZ_128K, 0, 2, 64, NAND_ECC_INFO(4, SZ_512) },
|
|
+ {"GD5F2GQ5REYIH SPI NAND 2G 4-bit",
|
|
+ { .id = {0xc8, 0x22} },
|
|
+ SZ_2K, SZ_256, SZ_128K, 0, 2, 64, NAND_ECC_INFO(4, SZ_512) },
|
|
+ {"MT29F1G01ABBFDWB-IT SPI NAND 1G 1.8V 4-bit",
|
|
+ { .id = {0x2c, 0x15} },
|
|
+ SZ_2K, SZ_128, SZ_128K, 0, 2, 128, NAND_ECC_INFO(8, SZ_512) },
|
|
+
|
|
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
|
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
|
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS),
|
|
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
|
|
index 375ae6a2d799..361ee116422f 100644
|
|
--- a/drivers/mtd/nand/raw/qcom_nandc.c
|
|
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
|
|
@@ -35,22 +35,33 @@
|
|
#define NAND_DEV_CMD1 0xa4
|
|
#define NAND_DEV_CMD2 0xa8
|
|
#define NAND_DEV_CMD_VLD 0xac
|
|
+#define NAND_DEV_CMD7 0xb0
|
|
+#define NAND_DEV_CMD8 0xb4
|
|
+#define NAND_DEV_CMD9 0xb8
|
|
+#define NAND_FLASH_SPI_CFG 0xc0
|
|
+#define NAND_SPI_NUM_ADDR_CYCLES 0xc4
|
|
+#define NAND_SPI_BUSY_CHECK_WAIT_CNT 0xc8
|
|
+#define NAND_DEV_CMD3 0xd0
|
|
+#define NAND_DEV_CMD4 0xd4
|
|
+#define NAND_DEV_CMD5 0xd8
|
|
+#define NAND_DEV_CMD6 0xdc
|
|
#define SFLASHC_BURST_CFG 0xe0
|
|
#define NAND_ERASED_CW_DETECT_CFG 0xe8
|
|
#define NAND_ERASED_CW_DETECT_STATUS 0xec
|
|
#define NAND_EBI2_ECC_BUF_CFG 0xf0
|
|
#define FLASH_BUF_ACC 0x100
|
|
-
|
|
#define NAND_CTRL 0xf00
|
|
#define NAND_VERSION 0xf08
|
|
#define NAND_READ_LOCATION_0 0xf20
|
|
#define NAND_READ_LOCATION_1 0xf24
|
|
#define NAND_READ_LOCATION_2 0xf28
|
|
#define NAND_READ_LOCATION_3 0xf2c
|
|
#define NAND_READ_LOCATION_LAST_CW_0 0xf40
|
|
#define NAND_READ_LOCATION_LAST_CW_1 0xf44
|
|
#define NAND_READ_LOCATION_LAST_CW_2 0xf48
|
|
#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
|
|
+#define NAND_QSPI_MSTR_CONFIG 0xf60
|
|
+
|
|
|
|
/* dummy register offsets, used by write_reg_dma */
|
|
#define NAND_DEV_CMD1_RESTORE 0xdead
|
|
@@ -179,6 +194,28 @@
|
|
#define ECC_BCH_4BIT BIT(2)
|
|
#define ECC_BCH_8BIT BIT(3)
|
|
|
|
+/* QSPI NAND config reg bits */
|
|
+#define LOAD_CLK_CNTR_INIT_EN (1 << 28)
|
|
+#define CLK_CNTR_INIT_VAL_VEC 0x924
|
|
+#define FEA_STATUS_DEV_ADDR 0xc0
|
|
+#define SPI_CFG (1 << 0)
|
|
+
|
|
+/* CMD register value for qspi nand */
|
|
+#define CMD0_VAL 0x1080D8D8
|
|
+#define CMD1_VAL 0xF00F3000
|
|
+#define CMD2_VAL 0xF0FF709F
|
|
+#define CMD3_VAL 0x3F310015
|
|
+#define CMD7_VAL 0x04061F0F
|
|
+#define CMD_VLD_VAL 0xd
|
|
+#define SPI_NUM_ADDR 0xDA4DB
|
|
+#define WAIT_CNT 0x10
|
|
+
|
|
+/* QSPI NAND CMD reg bits value */
|
|
+#define SPI_WP (1 << 28)
|
|
+#define SPI_HOLD (1 << 27)
|
|
+#define SPI_TRANSFER_MODE_x1 (1 << 29)
|
|
+#define SPI_TRANSFER_MODE_x4 (3 << 29)
|
|
+
|
|
#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \
|
|
nandc_set_reg(chip, reg, \
|
|
((cw_offset) << READ_LOCATION_OFFSET) | \
|
|
@@ -314,6 +351,9 @@ struct nandc_regs {
|
|
__le32 read_location_last1;
|
|
__le32 read_location_last2;
|
|
__le32 read_location_last3;
|
|
+ __le32 spi_cfg;
|
|
+ __le32 num_addr_cycle;
|
|
+ __le32 busy_wait_cnt;
|
|
|
|
__le32 erased_cw_detect_cfg_clr;
|
|
__le32 erased_cw_detect_cfg_set;
|
|
@@ -367,6 +407,7 @@ struct qcom_nand_controller {
|
|
|
|
struct clk *core_clk;
|
|
struct clk *aon_clk;
|
|
+ struct clk *iomacro_clk;
|
|
|
|
union {
|
|
/* will be used only by QPIC for BAM DMA */
|
|
@@ -460,13 +501,15 @@ struct qcom_nand_host {
|
|
* @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
|
|
+ * @is_serial_nand - QSPI nand flag, whether QPIC support serial nand or not
|
|
*/
|
|
struct qcom_nandc_props {
|
|
u32 ecc_modes;
|
|
bool is_bam;
|
|
bool is_qpic;
|
|
bool qpic_v2;
|
|
u32 dev_cmd_reg_start;
|
|
+ bool is_serial_nand;
|
|
};
|
|
|
|
/* Frees the BAM transaction memory */
|
|
@@ -640,6 +683,12 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
|
|
return ®s->read_location_last2;
|
|
case NAND_READ_LOCATION_LAST_CW_3:
|
|
return ®s->read_location_last3;
|
|
+ case NAND_FLASH_SPI_CFG:
|
|
+ return ®s->spi_cfg;
|
|
+ case NAND_SPI_NUM_ADDR_CYCLES:
|
|
+ return ®s->num_addr_cycle;
|
|
+ case NAND_SPI_BUSY_CHECK_WAIT_CNT:
|
|
+ return ®s->busy_wait_cnt;
|
|
default:
|
|
return NULL;
|
|
}
|
|
@@ -1244,11 +1293,23 @@ static int read_id(struct qcom_nand_host *host, int column)
|
|
{
|
|
struct nand_chip *chip = &host->chip;
|
|
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
|
+ u32 cmd = OP_FETCH_ID;
|
|
|
|
if (column == -1)
|
|
return 0;
|
|
|
|
- nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
|
|
+ if (nandc->props->is_serial_nand) {
|
|
+ cmd |= (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1);
|
|
+ /* For spi nand read 2-bytes id only
|
|
+ * else if nandc->buf_count == 4; then the id value
|
|
+ * will repeat and the SLC device will be detect as MLC.
|
|
+ * by nand base layer
|
|
+ * so overwrite the nandc->buf_count == 2;
|
|
+ */
|
|
+ nandc->buf_count = 2;
|
|
+ }
|
|
+
|
|
+ nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
|
|
nandc_set_reg(chip, NAND_ADDR0, column);
|
|
nandc_set_reg(chip, NAND_ADDR1, 0);
|
|
nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
|
|
@@ -1268,8 +1329,13 @@ static int reset(struct qcom_nand_host *host)
|
|
{
|
|
struct nand_chip *chip = &host->chip;
|
|
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
|
+ int cmd_rst;
|
|
+
|
|
+ cmd_rst = OP_RESET_DEVICE;
|
|
+ if (nandc->props->is_serial_nand)
|
|
+ cmd_rst |= (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1);
|
|
|
|
- nandc_set_reg(chip, NAND_FLASH_CMD, OP_RESET_DEVICE);
|
|
+ nandc_set_reg(chip, NAND_FLASH_CMD, cmd_rst);
|
|
nandc_set_reg(chip, NAND_EXEC_CMD, 1);
|
|
|
|
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
|
|
@@ -2471,6 +2537,8 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
|
|
int cwperpage, bad_block_byte, ret;
|
|
bool wide_bus;
|
|
int ecc_mode = 1;
|
|
+ int num_addr_cycle = 5, dsbl_sts_aftr_write = 0;
|
|
+ int wr_rd_bsy_gap = 2, recovery_cycle = 7;
|
|
|
|
/* controller only supports 512 bytes data steps */
|
|
ecc->size = NANDC_STEP_SIZE;
|
|
@@ -2579,33 +2647,43 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
|
|
host->cw_size = host->cw_data + ecc->bytes;
|
|
bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
|
|
|
|
+ /* For QSPI serial nand QPIC config register value got changed
|
|
+ * so configure the new value for qspi serial nand
|
|
+ */
|
|
+ if (nandc->props->is_serial_nand) {
|
|
+ num_addr_cycle = 3;
|
|
+ dsbl_sts_aftr_write = 1;
|
|
+ wr_rd_bsy_gap = 20;
|
|
+ recovery_cycle = 0;
|
|
+ }
|
|
+
|
|
host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
|
|
| host->cw_data << UD_SIZE_BYTES
|
|
- | 0 << DISABLE_STATUS_AFTER_WRITE
|
|
- | 5 << NUM_ADDR_CYCLES
|
|
+ | dsbl_sts_aftr_write << DISABLE_STATUS_AFTER_WRITE
|
|
+ | num_addr_cycle << NUM_ADDR_CYCLES
|
|
| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
|
|
| 0 << STATUS_BFR_READ
|
|
| 1 << SET_RD_MODE_AFTER_STATUS
|
|
| host->spare_bytes << SPARE_SIZE_BYTES;
|
|
|
|
- host->cfg1 = 7 << NAND_RECOVERY_CYCLES
|
|
+ host->cfg1 = recovery_cycle << NAND_RECOVERY_CYCLES
|
|
| 0 << CS_ACTIVE_BSY
|
|
| bad_block_byte << BAD_BLOCK_BYTE_NUM
|
|
| 0 << BAD_BLOCK_IN_SPARE_AREA
|
|
- | 2 << WR_RD_BSY_GAP
|
|
+ | wr_rd_bsy_gap << WR_RD_BSY_GAP
|
|
| wide_bus << WIDE_FLASH
|
|
| host->bch_enabled << ENABLE_BCH_ECC;
|
|
|
|
host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
|
|
| host->cw_size << UD_SIZE_BYTES
|
|
- | 5 << NUM_ADDR_CYCLES
|
|
+ | num_addr_cycle << NUM_ADDR_CYCLES
|
|
| 0 << SPARE_SIZE_BYTES;
|
|
|
|
- host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
|
|
+ host->cfg1_raw = recovery_cycle << NAND_RECOVERY_CYCLES
|
|
| 0 << CS_ACTIVE_BSY
|
|
| 17 << BAD_BLOCK_BYTE_NUM
|
|
| 1 << BAD_BLOCK_IN_SPARE_AREA
|
|
- | 2 << WR_RD_BSY_GAP
|
|
+ | wr_rd_bsy_gap << WR_RD_BSY_GAP
|
|
| wide_bus << WIDE_FLASH
|
|
| 1 << DEV0_CFG1_ECC_DISABLE;
|
|
|
|
@@ -2781,6 +2859,47 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
|
|
return 0;
|
|
}
|
|
|
|
+static void qspi_write_reg_bam(struct qcom_nand_controller *nandc,
|
|
+ unsigned int val, unsigned int reg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ clear_bam_transaction(nandc);
|
|
+ nandc_set_reg(chip, reg, val);
|
|
+ write_reg_dma(nandc, reg, 1, NAND_BAM_NEXT_SGL);
|
|
+
|
|
+ ret = submit_descs(nandc);
|
|
+ if (ret)
|
|
+ dev_err(nandc->dev, "Error in submitting descriptor to write config reg\n");
|
|
+ free_descs(nandc);
|
|
+}
|
|
+
|
|
+static void qspi_nand_init(struct qcom_nand_controller *nandc)
|
|
+{
|
|
+ u32 spi_cfg_val = 0x0;
|
|
+ u32 reg = 0x0;
|
|
+
|
|
+ spi_cfg_val |= (LOAD_CLK_CNTR_INIT_EN | CLK_CNTR_INIT_VAL_VEC
|
|
+ | FEA_STATUS_DEV_ADDR | SPI_CFG);
|
|
+
|
|
+ qspi_write_reg_bam(nandc, 0x0, NAND_FLASH_SPI_CFG);
|
|
+ qspi_write_reg_bam(nandc, spi_cfg_val, NAND_FLASH_SPI_CFG);
|
|
+ spi_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
|
|
+ qspi_write_reg_bam(nandc, spi_cfg_val, NAND_FLASH_SPI_CFG);
|
|
+
|
|
+ reg = dev_cmd_reg_addr(nandc, NAND_DEV_CMD0);
|
|
+ nandc_write(nandc, reg, CMD0_VAL);
|
|
+ nandc_write(nandc, reg + 4, CMD1_VAL);
|
|
+ nandc_write(nandc, reg + 8, CMD2_VAL);
|
|
+ nandc_write(nandc, reg + 12, CMD_VLD_VAL);
|
|
+ nandc_write(nandc, reg + 16, CMD7_VAL);
|
|
+ reg = dev_cmd_reg_addr(nandc, NAND_DEV_CMD3);
|
|
+ nandc_write(nandc, reg, CMD3_VAL);
|
|
+
|
|
+ qspi_write_reg_bam(nandc, SPI_NUM_ADDR, NAND_SPI_NUM_ADDR_CYCLES);
|
|
+ qspi_write_reg_bam(nandc, WAIT_CNT, NAND_SPI_BUSY_CHECK_WAIT_CNT);
|
|
+}
|
|
+
|
|
static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
|
|
struct qcom_nand_host *host,
|
|
struct device_node *dn)
|
|
@@ -2830,6 +2949,9 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
|
|
/* set up initial status value */
|
|
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
|
|
|
|
+ if (nandc->props->is_serial_nand)
|
|
+ qspi_nand_init(nandc);
|
|
+
|
|
ret = nand_scan(chip, 1);
|
|
if (ret)
|
|
return ret;
|
|
@@ -2934,6 +3056,12 @@ static int qcom_nandc_probe(struct platform_device *pdev)
|
|
if (IS_ERR(nandc->aon_clk))
|
|
return PTR_ERR(nandc->aon_clk);
|
|
|
|
+ if (nandc->props->is_serial_nand) {
|
|
+ nandc->iomacro_clk = devm_clk_get(dev, "io_macro");
|
|
+ if (IS_ERR(nandc->iomacro_clk))
|
|
+ return PTR_ERR(nandc->iomacro_clk);
|
|
+ }
|
|
+
|
|
ret = qcom_nandc_parse_dt(pdev);
|
|
if (ret)
|
|
return ret;
|
|
@@ -2962,6 +3090,12 @@ static int qcom_nandc_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
goto err_nandc_alloc;
|
|
|
|
+ if (nandc->props->is_serial_nand) {
|
|
+ ret = clk_prepare_enable(nandc->iomacro_clk);
|
|
+ if (ret)
|
|
+ goto err_setup;
|
|
+ }
|
|
+
|
|
ret = qcom_nandc_setup(nandc);
|
|
if (ret)
|
|
goto err_setup;
|
|
@@ -3009,6 +3143,7 @@ static const struct qcom_nandc_props ipq806x_nandc_props = {
|
|
.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
|
|
.is_bam = false,
|
|
.dev_cmd_reg_start = 0x0,
|
|
+ .is_serial_nand = false,
|
|
};
|
|
|
|
static const struct qcom_nandc_props ipq4019_nandc_props = {
|
|
@@ -3016,6 +3151,7 @@ static const struct qcom_nandc_props ipq4019_nandc_props = {
|
|
.is_bam = true,
|
|
.is_qpic = true,
|
|
.dev_cmd_reg_start = 0x0,
|
|
+ .is_serial_nand = false,
|
|
};
|
|
|
|
static const struct qcom_nandc_props ipq8074_nandc_props = {
|
|
@@ -3023,6 +3159,15 @@ static const struct qcom_nandc_props ipq8074_nandc_props = {
|
|
.is_bam = true,
|
|
.is_qpic = true,
|
|
.dev_cmd_reg_start = 0x7000,
|
|
+ .is_serial_nand = false,
|
|
+};
|
|
+
|
|
+static const struct qcom_nandc_props ipq5018_nandc_props = {
|
|
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
|
|
+ .is_bam = true,
|
|
+ .qpic_v2 = true,
|
|
+ .dev_cmd_reg_start = 0x7000,
|
|
+ .is_serial_nand = true,
|
|
};
|
|
|
|
/*
|
|
@@ -3046,6 +3190,10 @@ static const struct of_device_id qcom_nandc_of_match[] = {
|
|
.compatible = "qcom,ebi2-nandc-bam-v1.5.0",
|
|
.data = &ipq8074_nandc_props,
|
|
},
|
|
+ {
|
|
+ .compatible = "qcom,ebi2-nandc-bam-v2.1.1",
|
|
+ .data = &ipq5018_nandc_props,
|
|
+ },
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
|
|
--
|
|
2.25.1
|
|
|