191 lines
5.8 KiB
C
Executable File
191 lines
5.8 KiB
C
Executable File
/*
|
|
* fmc100_spi_nm25q128evb.c
|
|
*
|
|
* The Flash Memory Controller v100 Device Driver for vendor
|
|
*
|
|
* Copyright (c) 2021 CHANGJIANG Technologies Co., Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
#define NM25Q128EVB_CR_4BYTE_MASK 0x1
|
|
|
|
#define WB_SPI_NOR_SR_ADS_MASK 1
|
|
#define wb_spi_nor_get_4byte_by_sr(sr) ((sr) & WB_SPI_NOR_SR_ADS_MASK)
|
|
|
|
#define SPI_CMD_FIRST_RESET_4ADDR 0x66
|
|
#define SPI_CMD_SECOND_RESET_4ADDR 0x99
|
|
|
|
/****************************************************************************/
|
|
static void spi_nm25q128evb_set_cmd(struct fmc_spi *spi, u8 cmd)
|
|
{
|
|
unsigned int regval;
|
|
struct fmc_host *host = (struct fmc_host *)spi->host;
|
|
|
|
regval = fmc_cmd_cmd1(cmd);
|
|
fmc_write(host, FMC_CMD, regval);
|
|
fmc_pr(AC_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
|
|
|
|
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
|
|
fmc_write(host, FMC_OP_CFG, regval);
|
|
fmc_pr(AC_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
|
|
|
|
regval = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
|
|
fmc_write(host, FMC_OP, regval);
|
|
fmc_pr(AC_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
|
|
|
|
fmc_cmd_wait_cpu_finish(host);
|
|
}
|
|
/****************************************************************************/
|
|
static int spi_nm25q128evb_entry_4addr(struct fmc_spi *spi, int enable)
|
|
{
|
|
unsigned char status;
|
|
const char *str[] = {"Disable", "Enable"};
|
|
|
|
fmc_pr(AC_DBG, "\t* Start W25Q256FV SPI Nor %s 4-byte mode.\n",
|
|
str[enable]);
|
|
|
|
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
|
|
fmc_pr(AC_DBG, "\t* W25Q(128/256)FV not support 4B mode.\n");
|
|
return 0;
|
|
}
|
|
|
|
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
|
|
fmc_pr(AC_DBG, "\t Read Status Register-3[%#x]:%#x\n", SPI_CMD_RDSR3,
|
|
status);
|
|
if (wb_spi_nor_get_4byte_by_sr(status) == enable) {
|
|
fmc_pr(AC_DBG, "\t* 4-byte was %sd, reg:%#x\n", str[enable],
|
|
status);
|
|
return 0;
|
|
}
|
|
|
|
if (enable) {
|
|
spi_nm25q128evb_set_cmd(spi, SPI_CMD_EN4B);
|
|
|
|
spi->driver->wait_ready(spi);
|
|
|
|
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
|
|
fmc_pr(AC_DBG, "\t Get Status Register 3[%#x]:%#x\n",
|
|
SPI_CMD_RDSR3, status);
|
|
if (status & W25Q256FV_CR_4BYTE_MASK) {
|
|
fmc_pr(AC_DBG, "\t Enter 4-byte success, reg[%#x]\n",
|
|
status);
|
|
} else {
|
|
db_msg("Error: Enter 4-byte failed! [%#x]\n", status);
|
|
}
|
|
} else {
|
|
/* reset cmd */
|
|
spi_nm25q128evb_set_cmd(spi, SPI_CMD_FIRST_RESET_4ADDR);
|
|
|
|
spi_nm25q128evb_set_cmd(spi, SPI_CMD_SECOND_RESET_4ADDR);
|
|
|
|
fmc_pr(AC_DBG, "\tnow W25Q256FV start software reset\n");
|
|
|
|
udelay(30); /* delay 30 us */
|
|
}
|
|
|
|
fmc_pr(AC_DBG, "\t* End W25Q256FV enter 4-byte mode.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
static void spi_nm25q128evb_set_op(struct fmc_spi *spi)
|
|
{
|
|
unsigned int regval;
|
|
struct fmc_host *host = (struct fmc_host *)spi->host;
|
|
|
|
regval = fmc_cmd_cmd1(SPI_CMD_WRSR2);
|
|
fmc_write(host, FMC_CMD, regval);
|
|
fmc_pr(QE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
|
|
|
|
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
|
|
fmc_write(host, FMC_OP_CFG, regval);
|
|
fmc_pr(QE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
|
|
|
|
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
|
|
fmc_write(host, FMC_DATA_NUM, regval);
|
|
fmc_pr(QE_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
|
|
|
|
regval = fmc_op_cmd1_en(ENABLE) |
|
|
fmc_op_write_data_en(ENABLE) |
|
|
FMC_OP_REG_OP_START;
|
|
fmc_write(host, FMC_OP, regval);
|
|
fmc_pr(QE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
|
|
|
|
fmc_cmd_wait_cpu_finish(host);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/*
|
|
enable QE bit if QUAD read write is supported by W25Q(128/256)FV
|
|
*/
|
|
static int spi_nm25q128evb_qe_enable(struct fmc_spi *spi)
|
|
{
|
|
unsigned char status, op;
|
|
const char *str[] = {"Disable", "Enable"};
|
|
struct fmc_host *host = (struct fmc_host *)spi->host;
|
|
|
|
op = spi_is_quad(spi);
|
|
|
|
fmc_pr(QE_DBG, "\t* Start SPI Nor NM25Q128EVB %s Quad.\n", str[op]);
|
|
|
|
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
|
|
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]%#x\n", SPI_CMD_RDSR2,
|
|
status);
|
|
if (op == spi_nor_get_qe_by_cr_nm(status)) {
|
|
fmc_pr(QE_DBG, "\t* Quad was %s status:%#x\n", str[op], status);
|
|
goto QE_END;
|
|
}
|
|
|
|
spi->driver->write_enable(spi);
|
|
|
|
if (op)
|
|
status |= SPI_NOR_CR_QE_MASK;
|
|
else
|
|
status &= ~SPI_NOR_CR_QE_MASK;
|
|
|
|
writeb(status, host->iobase);
|
|
fmc_pr(QE_DBG, "\t Write IO[%p]%#x\n", host->iobase,
|
|
*(unsigned char *)host->iobase);
|
|
|
|
/* There is new cmd for Write Status Register 2 by W25Q(128/256)FV */
|
|
spi_nm25q128evb_set_op(spi);
|
|
|
|
/* wait the flash have switched quad mode success */
|
|
spi->driver->wait_ready(spi);
|
|
|
|
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
|
|
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]:%#x\n",
|
|
SPI_CMD_RDSR2, status);
|
|
if (op == spi_nor_get_qe_by_cr_nm(status)) {
|
|
fmc_pr(QE_DBG, "\t %s Quad success. status:%#x\n",
|
|
str[op], status);
|
|
} else {
|
|
db_msg("Error: %s Quad failed! reg:%#x\n", str[op],
|
|
status);
|
|
}
|
|
QE_END:
|
|
/* Enable the reset pin when working on dual mode for 8PIN */
|
|
if (!op)
|
|
spi_nor_reset_pin_enable(spi, ENABLE);
|
|
|
|
fmc_pr(QE_DBG, "\t* End SPI Nor NM25Q128EVB %s Quad.\n", str[op]);
|
|
|
|
return op;
|
|
}
|
|
|