/* * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. */ /*****************************************************************************/ /* MXIC QE(bit) include in Status Register */ #define MX_SPI_NOR_SR_QE_SHIFT 6 #define MX_SPI_NOR_SR_QE_MASK (1 << MX_SPI_NOR_SR_QE_SHIFT) #define mx_spi_nor_get_qe_by_sr(sr) (((sr) & MX_SPI_NOR_SR_QE_MASK) \ >> MX_SPI_NOR_SR_QE_SHIFT) /*****************************************************************************/ /* * enable QE bit if 4X R/W is supported by MXIC "25L(256/257)35(E/F)" SPI */ #ifndef CONFIG_DTR_MODE_SUPPORT static void clear_dtr_mode(struct fmc_spi *spi, unsigned char status) { unsigned int regval; struct fmc_host *host = (struct fmc_host *)spi->host; unsigned char config; unsigned short reg; config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX); regval = fmc_read(host, FMC_GLOBAL_CFG); if ((regval >> DTR_MODE_REQUEST_SHIFT) & 0x1) { regval &= (~(1 << DTR_MODE_REQUEST_SHIFT)); regval = fmc_write(host, FMC_GLOBAL_CFG, regval); } if (config & CR_DUMMY_CYCLE) { config &= (~CR_DUMMY_CYCLE); reg = ((unsigned short)config << SPI_NOR_CR_SHIFT) | status; writew(reg, host->iobase); spi->driver->write_enable(spi); fmc100_op_reg(spi, SPI_CMD_WRSR, sizeof(unsigned short), fmc_op_write_data_en(ENABLE)); } } #endif /*****************************************************************************/ static void spi_mx25l25635e_set_cmd(struct fmc_spi *spi) { unsigned int regval; struct fmc_host *host = (struct fmc_host *)spi->host; regval = fmc_cmd_cmd1(SPI_CMD_WRSR); 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); } /*****************************************************************************/ static int spi_mx25l25635e_qe_enable(struct fmc_spi *spi) { unsigned char status; unsigned char 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 MXIC SPI Nor %s Quad.\n", str[op]); status = spi_general_get_flash_register(spi, SPI_CMD_RDSR); fmc_pr(QE_DBG, "\t||-Read Status Register[%#x]%#x\n", SPI_CMD_RDSR, status); #ifndef CONFIG_DTR_MODE_SUPPORT clear_dtr_mode(spi, status); #endif if (mx_spi_nor_get_qe_by_sr(status) == op) { fmc_pr(QE_DBG, "\t|*-Quad was %sd, status:%#x\n", str[op], status); return op; } spi->driver->write_enable(spi); if (op) status |= MX_SPI_NOR_SR_QE_MASK; else status &= ~MX_SPI_NOR_SR_QE_MASK; writeb(status, host->iobase); fmc_pr(QE_DBG, "\t||-Write IO[%p]%#x\n", host->iobase, *(unsigned char *)host->iobase); spi_mx25l25635e_set_cmd(spi); spi->driver->wait_ready(spi); status = spi_general_get_flash_register(spi, SPI_CMD_RDSR); if (mx_spi_nor_get_qe_by_sr(status) == op) 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); fmc_pr(QE_DBG, "\t|*-End MXIC SPI Nor %s Quad.\n", str[op]); return op; } #ifdef CONFIG_DTR_MODE_SUPPORT /*****************************************************************************/ void spi_mxic_set_reg(struct fmc_spi *spi) { unsigned int regval; struct fmc_host *host = (struct fmc_host *)spi->host; regval = fmc_cmd_cmd1(SPI_CMD_WRSR); fmc_write(host, FMC_CMD, regval); fmc_pr(DTR_DB, " 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(DTR_DB, " Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval); regval = fmc_data_num_cnt(SPI_NOR_SR_LEN + SPI_NOR_CR_LEN); fmc_write(host, FMC_DATA_NUM, regval); fmc_pr(DTR_DB, " 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(DTR_DB, " Set OP[%#x]%#x\n", FMC_OP, regval); } /*****************************************************************************/ int spi_mxic_output_driver_strength_set(struct fmc_spi *spi, int dtr_en) { unsigned char status; unsigned char config; unsigned short reg; unsigned short val = 0; unsigned int ix; struct fmc_host *host = (struct fmc_host *)spi->host; /************************************************************************/ /* DC[1:0] | Numbers of Dummy clock cycles| Quad IO DTR Read */ /* 00(default)| 6 | 54 */ /* 01 | 6 | 54 */ /* 10 | 8 | 70/80R */ /* 11 | 10 | 84/100R */ /************************************************************************/ unsigned int str_dummy[] = { DTR_DUMMY_CYCLES_6, dtr_rdcr_dc_mask(0), DTR_DUMMY_CYCLES_6, dtr_rdcr_dc_mask(1), DTR_DUMMY_CYCLES_8, dtr_rdcr_dc_mask(2), DTR_DUMMY_CYCLES_10, dtr_rdcr_dc_mask(3), 0, 0, }; /* get the RDCR and RDSR */ spi->driver->wait_ready(spi); /* setting the DC value to match high system clock */ config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX); fmc_pr(DTR_DB, "Get Config Register[%#x]\n", config); /* check the QE value */ status = spi_general_get_flash_register(spi, SPI_CMD_RDSR); fmc_pr(DTR_DB, "Get Status Register[%#x]\n", status); reg = ((unsigned short)config << SPI_NOR_CR_SHIFT) | status; if (dtr_en == ENABLE) { /* setting DC value */ fmc_pr(DTR_DB, "Get the dummy value[%#x]\n", spi->read->dummy); /* Only the element with an even number of arrays is required, so increase is 2 */ for (ix = 0; str_dummy[ix]; ix += _2B) { if (spi->read->dummy < str_dummy[ix]) break; val = (unsigned short)str_dummy[ix + 1]; } } else { val = dtr_rdcr_dc_mask(0); } reg = dtr_rdcr_dc_bit_clr(reg) | (val << DTR_RDSR_DC_SHIFT); spi->driver->write_enable(spi); writew(reg, host->iobase); fmc_pr(DTR_DB, "Write IO[%p]%#x\n", host->iobase, *(unsigned short *)host->iobase); spi_mxic_set_reg(spi); fmc_cmd_wait_cpu_finish(host); config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX); if ((config >> DTR_RDCR_DC_SHIFT) != (unsigned char)val) { printf("* Set DC dummy fail.\n"); return -1; } return 0; } unsigned int spi_mxic_check_spi_dtr_support(struct fmc_spi *spi) { unsigned int regval; unsigned int rd_sfdp_dummy = 1; unsigned int sfdp_addrcycle = 3; struct fmc_host *host = (struct fmc_host *)spi->host; /* get the RDCR and RDSR */ spi->driver->wait_ready(spi); /* Read the Serial Flash Discoverable Parameter (SFDP) */ fmc_write(host, FMC_CMD, SPI_CMD_RD_SFDP); fmc_pr(DTR_DB, "\t Set CMD[%#x]%#x\n", FMC_CMD, SPI_CMD_RD_SFDP); regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN | op_cfg_addr_num(sfdp_addrcycle) | op_cfg_dummy_num(rd_sfdp_dummy); fmc_write(host, FMC_OP_CFG, regval); fmc_pr(DTR_DB, "\t\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval); regval = fmc_data_num_cnt(SFDP_BUF_LEN); fmc_write(host, FMC_DATA_NUM, regval); fmc_pr(DTR_DB, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval); regval = fmc_op_dummy_en(ENABLE) | fmc_op_cmd1_en(ENABLE) | fmc_op_addr_en(ENABLE) | fmc_op_read_data_en(ENABLE) | FMC_OP_REG_OP_START; fmc_write(host, FMC_OP, regval); fmc_pr(DTR_DB, "\t Set OP[%#x]%#x\n", FMC_OP, regval); fmc_cmd_wait_cpu_finish(host); regval = readb((char *)host->iobase + SFDP_DTR_BYTE_SHIFT); fmc_pr(DTR_DB, "\t the dtr_mode_support is: %#x\n", regval); /* get the DTR mode support bit */ spi->dtr_mode_support = (regval >> SFDP_DTR_BIT_SHIFT) & SFDP_DTR_BIT_MASK; return spi->dtr_mode_support; } #endif /* CONFIG_DTR_MODE_SUPPORT */