firmware/br-ext-chip-goke/board/gk7205v200/kernel/patches/00_drivers-mtd-nand-gkfmc10...

250 lines
7.0 KiB
Diff

--- linux-4.9.37/drivers/mtd/nand/gkfmc100/fmc100_spi_general.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-4.9.y/drivers/mtd/nand/gkfmc100/fmc100_spi_general.c 2021-06-07 13:01:33.000000000 +0300
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
+ */
+
+/*
+ Send set/get features command to SPI Nand flash
+*/
+u_char spi_nand_feature_op(struct fmc_spi *spi, u_char op, u_char addr,
+ u_char val)
+{
+ unsigned int reg;
+ const char *str[] = {"Get", "Set"};
+ struct fmc_host *host = (struct fmc_host *)spi->host;
+
+ if ((op == GET_OP) && (STATUS_ADDR == addr)) {
+ if (SR_DBG) {
+ pr_info("\n");
+ }
+ FMC_PR(SR_DBG, "\t\t|*-Start Get Status\n");
+
+ reg = OP_CFG_FM_CS(host->cmd_op.cs) | OP_CFG_OEN_EN;
+ fmc_writel(host, FMC_OP_CFG, reg);
+ FMC_PR(SR_DBG, "\t\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
+
+ reg = FMC_OP_READ_STATUS_EN | FMC_OP_REG_OP_START;
+ fmc_writel(host, FMC_OP, reg);
+ FMC_PR(SR_DBG, "\t\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
+
+ FMC_CMD_WAIT_CPU_FINISH(host);
+
+ val = fmc_readl(host, FMC_STATUS);
+ FMC_PR(SR_DBG, "\t\t|*-End Get Status, result: %#x\n", val);
+
+ return val;
+ }
+
+ FMC_PR(FT_DBG, "\t|||*-Start %s feature, addr[%#x]\n", str[op], addr);
+
+ fmc100_ecc0_switch(host, ENABLE);
+
+ reg = FMC_CMD_CMD1(op ? SPI_CMD_SET_FEATURE : SPI_CMD_GET_FEATURES);
+ fmc_writel(host, FMC_CMD, reg);
+ FMC_PR(FT_DBG, "\t||||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
+
+ fmc_writel(host, FMC_ADDRL, addr);
+ FMC_PR(FT_DBG, "\t||||-Set ADDRL[%#x]%#x\n", FMC_ADDRL, addr);
+
+ reg = OP_CFG_FM_CS(host->cmd_op.cs)
+ | OP_CFG_ADDR_NUM(FEATURES_OP_ADDR_NUM)
+ | OP_CFG_OEN_EN;
+ fmc_writel(host, FMC_OP_CFG, reg);
+ FMC_PR(FT_DBG, "\t||||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
+
+ reg = FMC_DATA_NUM_CNT(FEATURES_DATA_LEN);
+ fmc_writel(host, FMC_DATA_NUM, reg);
+ FMC_PR(FT_DBG, "\t||||-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
+
+ reg = FMC_OP_CMD1_EN
+ | FMC_OP_ADDR_EN
+ | FMC_OP_REG_OP_START;
+
+ if (op == SET_OP) {
+ reg |= FMC_OP_WRITE_DATA_EN;
+ fmc_writeb(val, host->iobase);
+ FMC_PR(FT_DBG, "\t||||-Write IO[%#lx]%#x\n", (long)host->iobase,
+ *(u_char *)host->iobase);
+ } else {
+ reg |= FMC_OP_READ_DATA_EN;
+ }
+
+ fmc_writel(host, FMC_OP, reg);
+ FMC_PR(FT_DBG, "\t||||-Set OP[%#x]%#x\n", FMC_OP, reg);
+
+ FMC_CMD_WAIT_CPU_FINISH(host);
+
+ if (op == GET_OP) {
+ val = fmc_readb(host->iobase);
+ FMC_PR(FT_DBG, "\t||||-Read IO[%#lx]%#x\n", (long)host->iobase,
+ *(u_char *)host->iobase);
+ }
+
+ fmc100_ecc0_switch(host, DISABLE);
+
+ FMC_PR(FT_DBG, "\t|||*-End %s Feature[%#x]:%#x\n", str[op], addr, val);
+
+ return val;
+}
+
+/*****************************************************************************/
+/*
+ Read status[C0H]:[0]bit OIP, judge whether the device is busy or not
+*/
+static int spi_general_wait_ready(struct fmc_spi *spi)
+{
+ unsigned char status;
+ unsigned long deadline = jiffies + FMC_MAX_READY_WAIT_JIFFIES;
+ struct fmc_host *host = (struct fmc_host *)spi->host;
+
+ do {
+ status = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
+ if (!(status & STATUS_OIP_MASK)) {
+ if ((host->cmd_op.l_cmd == NAND_CMD_ERASE2)
+ && (status & STATUS_E_FAIL_MASK)) {
+ return status;
+ }
+ if ((host->cmd_op.l_cmd == NAND_CMD_PAGEPROG)
+ && (status & STATUS_P_FAIL_MASK)) {
+ return status;
+ }
+ return 0;
+ }
+
+ cond_resched();
+
+ } while (!time_after_eq(jiffies, deadline));
+
+ DB_MSG("Error: SPI Nand wait ready timeout, status: %#x\n", status);
+
+ return 1;
+}
+
+/*****************************************************************************/
+/*
+ Send write enable cmd to SPI Nand, status[C0H]:[2]bit WEL must be set 1
+*/
+static int spi_general_write_enable(struct fmc_spi *spi)
+{
+ unsigned int reg;
+ struct fmc_host *host = (struct fmc_host *)spi->host;
+
+ if (WE_DBG) {
+ pr_info("\n");
+ }
+ FMC_PR(WE_DBG, "\t|*-Start Write Enable\n");
+
+ reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
+ if (reg & STATUS_WEL_MASK) {
+ FMC_PR(WE_DBG, "\t||-Write Enable was opened! reg: %#x\n",
+ reg);
+ return 0;
+ }
+
+ reg = fmc_readl(host, FMC_GLOBAL_CFG);
+ FMC_PR(WE_DBG, "\t||-Get GLOBAL_CFG[%#x]%#x\n", FMC_GLOBAL_CFG, reg);
+ if (reg & FMC_GLOBAL_CFG_WP_ENABLE) {
+ reg &= ~FMC_GLOBAL_CFG_WP_ENABLE;
+ fmc_writel(host, FMC_GLOBAL_CFG, reg);
+ FMC_PR(WE_DBG, "\t||-Set GLOBAL_CFG[%#x]%#x\n",
+ FMC_GLOBAL_CFG, reg);
+ }
+
+ reg = FMC_CMD_CMD1(SPI_CMD_WREN);
+ fmc_writel(host, FMC_CMD, reg);
+ FMC_PR(WE_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
+
+ reg = OP_CFG_FM_CS(host->cmd_op.cs) | OP_CFG_OEN_EN;
+ fmc_writel(host, FMC_OP_CFG, reg);
+ FMC_PR(WE_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
+
+ reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START;
+ fmc_writel(host, FMC_OP, reg);
+ FMC_PR(WE_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
+
+ FMC_CMD_WAIT_CPU_FINISH(host);
+
+#if WE_DBG
+ spi->driver->wait_ready(spi);
+
+ reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
+ if (reg & STATUS_WEL_MASK) {
+ FMC_PR(WE_DBG, "\t||-Write Enable success. reg: %#x\n", reg);
+ } else {
+ DB_MSG("Error: Write Enable failed! reg: %#x\n", reg);
+ return reg;
+ }
+#endif
+
+ FMC_PR(WE_DBG, "\t|*-End Write Enable\n");
+ return 0;
+}
+
+/*****************************************************************************/
+/*
+ judge whether SPI Nand support QUAD read/write or not
+*/
+static int spi_is_quad(struct fmc_spi *spi)
+{
+ const char *if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"};
+
+ FMC_PR(QE_DBG, "\t\t|||*-SPI read iftype: %s write iftype: %s\n",
+ if_str[spi->read->iftype], if_str[spi->write->iftype]);
+
+ if ((spi->read->iftype == IF_TYPE_QUAD)
+ || (spi->read->iftype == IF_TYPE_QIO)
+ || (spi->write->iftype == IF_TYPE_QUAD)
+ || (spi->write->iftype == IF_TYPE_QIO)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/*
+ Send set features cmd to SPI Nand, feature[B0H]:[0]bit QE would be set
+*/
+static int spi_general_qe_enable(struct fmc_spi *spi)
+{
+ unsigned int reg, op;
+ const char *str[] = {"Disable", "Enable"};
+
+ FMC_PR(QE_DBG, "\t||*-Start SPI Nand flash QE\n");
+
+ op = spi_is_quad(spi);
+
+ FMC_PR(QE_DBG, "\t|||*-End Quad check, SPI Nand %s Quad.\n", str[op]);
+
+ reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
+ FMC_PR(QE_DBG, "\t|||-Get [%#x]feature: %#x\n", FEATURE_ADDR, reg);
+ if ((reg & FEATURE_QE_ENABLE) == op) {
+ FMC_PR(QE_DBG, "\t||*-SPI Nand quad was %sd!\n", str[op]);
+ return op;
+ }
+
+ if (op == ENABLE) {
+ reg |= FEATURE_QE_ENABLE;
+ } else {
+ reg &= ~FEATURE_QE_ENABLE;
+ }
+
+ spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg);
+ FMC_PR(QE_DBG, "\t|||-SPI Nand %s Quad\n", str[op]);
+
+ spi->driver->wait_ready(spi);
+
+ reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
+ if ((reg & FEATURE_QE_ENABLE) == op) {
+ FMC_PR(QE_DBG, "\t|||-SPI Nand %s Quad succeed!\n", str[op]);
+ } else {
+ DB_MSG("Error: %s Quad failed! reg: %#x\n", str[op], reg);
+ }
+
+ FMC_PR(QE_DBG, "\t||*-End SPI Nand %s Quad.\n", str[op]);
+
+ return op;
+}