static unsigned char *hisfc350_read_ids(struct hisfc_host *host, int chipselect, unsigned char *buffer) { int regindex = 0; int numread = 8; unsigned int *ptr = (unsigned int *)buffer; if (numread > HISFC350_REG_BUF_SIZE) numread = HISFC350_REG_BUF_SIZE; hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_RDID); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(chipselect) | HISFC350_CMD_CONFIG_RW_READ | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_DATA_CNT(numread) | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); while (numread) { *ptr = hisfc_read(host, HISFC350_CMD_DATABUF0 + regindex); ptr += 1; regindex += 4; numread -= 4; } return buffer; }
static int hisfc350_reg_erase_one_block(struct hisfc_host *host, struct hisfc_spi *spi, unsigned int offset) { if (spi->driver->wait_ready(spi)) return 1; spi->driver->write_enable(spi); host->set_system_clock(host, spi->erase, TRUE); hisfc_write(host, HISFC350_CMD_INS, spi->erase->cmd); hisfc_write(host, HISFC350_CMD_ADDR, (offset & HISFC350_CMD_ADDR_MASK)); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_MEM_IF_TYPE(spi->erase->iftype) | HISFC350_CMD_CONFIG_DUMMY_CNT(spi->erase->dummy) | HISFC350_CMD_CONFIG_ADDR_EN | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); return 0; }
static void hisfc350_dma_transfer(struct hisfc_host *host, unsigned int spi_start_addr, unsigned char *dma_buffer, unsigned char is_read, unsigned int size, unsigned char chipselect) { hisfc_write(host, HISFC350_BUS_DMA_MEM_SADDR, dma_buffer); hisfc_write(host, HISFC350_BUS_DMA_FLASH_SADDR, spi_start_addr); hisfc_write(host, HISFC350_BUS_DMA_LEN, HISFC350_BUS_DMA_LEN_DATA_CNT(size)); hisfc_write(host, HISFC350_BUS_DMA_AHB_CTRL, HISFC350_BUS_DMA_AHB_CTRL_INCR4_EN | HISFC350_BUS_DMA_AHB_CTRL_INCR8_EN | HISFC350_BUS_DMA_AHB_CTRL_INCR16_EN); hisfc_write(host, HISFC350_BUS_DMA_CTRL, HISFC350_BUS_DMA_CTRL_RW(is_read) | HISFC350_BUS_DMA_CTRL_CS(chipselect) | HISFC350_BUS_DMA_CTRL_START); HISFC350_DMA_WAIT_CPU_FINISH(host); }
static int spi_s25fl256s_entry_4addr(struct hisfc_spi *spi, int enable) { struct hisfc_host *host = (struct hisfc_host *)spi->host; if (spi->addrcycle != 4) return 0; if (enable) { hisfc_write(host, HISFC350_CMD_INS, SPI_BRWR); hisfc_write(host, HISFC350_CMD_DATABUF0, SPI_EN4B); } else { hisfc_write(host, HISFC350_CMD_INS, SPI_BRWR); hisfc_write(host, HISFC350_CMD_DATABUF0, SPI_EX4B); } hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_DATA_CNT(1) | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); host->set_host_addr_mode(host, enable); return 0; }
static void hisnfc100_send_cmd_reset(struct hisnfc_host *host) { hisfc_write(host, HISNFC100_INT_CLR, HISNFC100_INT_CLR_OP_DONE); hisfc_write(host, HISNFC100_OPCODE, SPI_CMD_RESET); hisfc_write(host, HISNFC100_OP_CFG, HISNFC100_OP_CFG_DIR_TRANS_ENABLE); hisfc_write(host, HISNFC100_OP, HISNFC100_OP_SEL_CS(host->cmd_option.chipselect) | HISNFC100_OP_OPCODE_EN(ENABLE) | HISNFC100_OP_START); HISNFC100_CMD_WAIT_CPU_FINISH(host); }
/* enable QE bit if QUAD read write is supported by SPI */ static int spi_mx25l25635e_qe_enable(struct hisfc_spi *spi) { struct hisfc_host *host = (struct hisfc_host *)spi->host; unsigned int regval = 0; unsigned int qe_op = 0; if (hisfc350_is_quad(spi)) qe_op = MX_SPI_CMD_SR_QE; else qe_op = SPI_CMD_SR_XQE; spi->driver->write_enable(spi); hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_WRSR); hisfc_write(host, HISFC350_CMD_DATABUF0, qe_op); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_MEM_IF_TYPE(spi-> write->iftype) | HISFC350_CMD_CONFIG_DATA_CNT(1) | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_DUMMY_CNT(spi-> write->dummy) | HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); spi->driver->wait_ready(spi); if (DEBUG_SPI) { hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_RDSR); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_DATA_CNT(1) | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_RW_READ | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); regval = hisfc_read(host, HISFC350_CMD_DATABUF0); printf("QEbit = 0x40? : 0x%x\n", regval); if ((regval & MX_SPI_CMD_SR_QE)) printf("QE bit enable success\n"); else printf("QE bit enable failed\n"); } return 0; }
static int hisfc350_controller_spi_init(struct hisfc_spi *spi, int offset) { int regval; struct hisfc_host *host = (struct hisfc_host *)spi->host; regval = hisfc_read(host, HISFC350_BUS_FLASH_SIZE); regval &= ~(HISFC350_BUS_FLASH_SIZE_CS0_MASK << (spi->chipselect << 3)); regval |= (hisfc350_map_chipsize(spi->chipsize) << (spi->chipselect << 3)); hisfc_write(host, HISFC350_BUS_FLASH_SIZE, regval); hisfc_write(host, (HISFC350_BUS_BASE_ADDR_CS0 + (spi->chipselect << 2)), (CONFIG_HISFC350_BUFFER_BASE_ADDRESS + offset)); return 0; }
static void hisfc350_set_host_addr_mode(struct hisfc_host *host, int enable) { unsigned int regval; regval = hisfc_read(host, HISFC350_GLOBAL_CONFIG); if (enable) regval |= HISFC350_GLOBAL_CONFIG_ADDR_MODE_4B; else regval &= ~HISFC350_GLOBAL_CONFIG_ADDR_MODE_4B; hisfc_write(host, HISFC350_GLOBAL_CONFIG, regval); }
static int spi_s25fl256s_entry_4addr(struct hisfc_spi *spi, int enable) { struct hisfc_host *host = (struct hisfc_host *)spi->host; unsigned int regval = 0; if (spi->addrcycle != SPI_4BYTE_ADDR_LEN) return 0; if (enable) { hisfc_write(host, HISFC350_CMD_INS, SPI_BRWR); hisfc_write(host, HISFC350_CMD_DATABUF0, SPI_EN4B); } else { hisfc_write(host, HISFC350_CMD_INS, SPI_BRWR); hisfc_write(host, HISFC350_CMD_DATABUF0, SPI_EX4B); } hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_DATA_CNT(1) | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); if (DEBUG_SPI) { regval = hisfc_read(host, HISFC350_CMD_DATABUF0); if (!(regval & SPI_EN4B)) { printk(KERN_INFO "now is 3-byte address mode\n"); printk(KERN_INFO "regval_read_SPI : 0x%x\n", regval); } else printk(KERN_INFO "now is 4-byte address mode\n"); } host->set_host_addr_mode(host, enable); return 0; }
int hisfc350_probe(struct hisfc_host *host) { host->set_system_clock = hisfc350_set_system_clock; host->set_host_addr_mode = hisfc350_set_host_addr_mode; hisfc350_set_system_clock(host, NULL, TRUE); hisfc_write(host, HISFC350_TIMING, HISFC350_TIMING_TCSS(0x6) | HISFC350_TIMING_TCSH(0x6) | HISFC350_TIMING_TSHSL(0xf)); if (!hisfc350_spi_probe(host)) return -1; hisfc350_probe_spi_size(host); return 0; }
static int spi_w25q256fv_entry_4addr(struct hisfc_spi *spi, int enable) { struct hisfc_host *host = (struct hisfc_host *)spi->host; if (spi->addrcycle != SPI_4BYTE_ADDR_LEN) return 0; /* This chip should not enable write here, * we have confirmed with the WINBOND */ /* spi->driver->write_enable(spi); */ if (enable) { hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_EN4B); if (DEBUG_SPI) printk(KERN_INFO "now w25q256fv is 4-byte address mode\n"); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); } else { hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_FIRST_RESET_4ADDR); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); hisfc_write(host, HISFC350_CMD_INS, SPI_CMD_SECOND_RESET_4ADDR); hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); if (DEBUG_SPI) printk(KERN_INFO "now W25Q256FV 6699 cmd\n"); } /* hisfc_write(host, HISFC350_CMD_CONFIG, HISFC350_CMD_CONFIG_SEL_CS(spi->chipselect) | HISFC350_CMD_CONFIG_DATA_CNT(1) | HISFC350_CMD_CONFIG_DATA_EN | HISFC350_CMD_CONFIG_START); HISFC350_CMD_WAIT_CPU_FINISH(host); */ host->set_host_addr_mode(host, enable); return 0; }
static void hisnfc100_send_cmd_readid(struct hisnfc_host *host) { hisfc_write(host, HISNFC100_INT_CLR, HISNFC100_INT_CLR_OP_DONE); hisfc_write(host, HISNFC100_OPCODE, SPI_CMD_RDID); hisfc_write(host, HISNFC100_OP_ADDR, READ_ID_ADDR); hisfc_write(host, HISNFC100_DATA_NUM, HISNFC100_DATA_NUM_CNT(MAX_ID_LEN)); hisfc_write(host, HISNFC100_OP_CFG, HISNFC100_OP_CFG_DIR_TRANS_ENABLE); hisfc_write(host, HISNFC100_OP, HISNFC100_OP_SEL_CS(host->cmd_option.chipselect) | HISNFC100_OP_ADDR_NUM(READ_ID_ADDR_NUM) | HISNFC100_OP_OPCODE_EN(ENABLE) | HISNFC100_OP_ADDR_EN(ENABLE) | HISNFC100_OP_DATE_READ_EN(ENABLE) | HISNFC100_OP_START); HISNFC100_CMD_WAIT_CPU_FINISH(host); }
static void hisnfc100_send_cmd_erase(struct hisnfc_host *host) { unsigned val; struct hisnfc_op *spi = host->spi; if (DEBUG_ERASE) pr_info("* Enter send cmd erase!\n"); val = spi->driver->wait_ready(spi); if (val) { pr_info("hisnfc: erase wait ready fail! status[%#x]\n", val); return; } if (spi->driver->write_enable(spi)) { pr_info("%s erase write enable failed!\n", __func__); return; } if (DEBUG_ERASE) { spi_feature_op(host, GET_OP, STATUS_ADDR, &val); pr_info(" Get feature addr[0xC0], val[%#x]\n", val); } val = HISNFC100_INT_CLR_ALL; hisfc_write(host, HISNFC100_INT_CLR, val); if (DEBUG_ERASE) pr_info(" Set REG INT_CLR[0x14]%#x\n", val); val = spi->erase->cmd; hisfc_write(host, HISNFC100_OPCODE, val); if (DEBUG_ERASE) pr_info(" Set REG OPCODE[0x18]%#x\n", val); val = HISNFC100_OP_ADDRH_BLOCK_MASK(host->addr_value[1]) | HISNFC100_OP_ADDRL_BLOCK_MASK(host->addr_value[0]); hisfc_write(host, HISNFC100_OP_ADDR, val); if (DEBUG_ERASE) pr_info(" Set REG OP_ADDR[0x18]%#x\n", val); val = HISNFC100_OP_CFG_DIR_TRANS_ENABLE; hisfc_write(host, HISNFC100_OP_CFG, val); if (DEBUG_ERASE) pr_info(" Set REG OP_CFG[0x28]%#x\n", val); val = HISNFC100_OP_SEL_CS(host->cmd_option.chipselect) | HISNFC100_OP_ADDR_NUM(STD_OP_ADDR_NUM) | HISNFC100_OP_OPCODE_EN(ENABLE) | HISNFC100_OP_ADDR_EN(ENABLE) | HISNFC100_OP_START; hisfc_write(host, HISNFC100_OP, val); if (DEBUG_ERASE) pr_info(" Set REG OP[0x20]%#x\n", val); HISNFC100_CMD_WAIT_CPU_FINISH(host); if (DEBUG_ERASE) { val = spi->driver->wait_ready(spi); if (val & STATUS_E_FAIL_MASK) pr_info("hisnfc100: erase failed! status[%#x]\n", val); } if (DEBUG_ERASE) pr_info("* End send cmd erase!\n"); }
static void hisnfc100_send_cmd_pageprog(struct hisnfc_host *host) { unsigned char pages_per_block_shift; unsigned val, block_num, block_num_h, page_num; struct hisnfc_op *spi = host->spi; struct nand_chip *chip = host->chip; #ifdef HISNFC100_SUPPORT_REG_WRITE const char *op_type = "reg"; #else const char *op_type = "dma"; #endif if (DEBUG_WRITE) pr_info("* Enter %s page program!\n", op_type); val = spi->driver->wait_ready(spi); if (val) { pr_info("%s: %s page program wait ready fail! status[%#x]\n", __func__, op_type, val); return; } if (spi->driver->write_enable(spi)) { pr_info("%s %s page program write enable failed!\n", __func__, op_type); return; } val = HISNFC100_INT_CLR_ALL; hisfc_write(host, HISNFC100_INT_CLR, val); if (DEBUG_WRITE) pr_info(" Set REG INT_CLR[0x14]%#x\n", val); val = HISNFC100_OP_CFG_MEM_IF_TYPE(spi->write->iftype); hisfc_write(host, HISNFC100_OP_CFG, val); if (DEBUG_WRITE) pr_info(" Set REG OP_CFG[0x28]%#x\n", val); pages_per_block_shift = chip->phys_erase_shift - chip->page_shift; block_num = host->addr_value[1] >> pages_per_block_shift; block_num_h = block_num >> REG_CNT_HIGH_BLOCK_NUM_SHIFT; val = HISNFC100_ADDRH_SET(block_num_h); hisfc_write(host, HISNFC100_ADDRH, val); if (DEBUG_WRITE) pr_info(" Set REG ADDRH[0x2c]%#x\n", val); page_num = host->addr_value[1] - (block_num << pages_per_block_shift); val = ((block_num & REG_CNT_BLOCK_NUM_MASK) << REG_CNT_BLOCK_NUM_SHIFT) | ((page_num & REG_CNT_PAGE_NUM_MASK) << REG_CNT_PAGE_NUM_SHIFT); hisfc_write(host, HISNFC100_ADDRL, val); if (DEBUG_WRITE) pr_info(" Set REG ADDRL[0x30]%#x\n", val); #ifndef HISNFC100_SUPPORT_REG_WRITE val = HISNFC100_DMA_CTRL_ALL_ENABLE; hisfc_write(host, HISNFC100_DMA_CTRL, val); if (DEBUG_WRITE) pr_info(" Set REG DMA_CTRL[0x3c]%#x\n", val); val = host->dma_buffer; hisfc_write(host, HISNFC100_DMA_SADDR_D, val); if (DEBUG_WRITE) pr_info(" Set REG DMA_SADDR_D[0x40]%#x\n", val); val = host->dma_oob; hisfc_write(host, HISNFC100_DMA_SADDR_OOB, val); if (DEBUG_WRITE) pr_info(" Set REG DMA_SADDR_OOB[%#x]%#x\n", HISNFC100_DMA_SADDR_OOB, val); #endif val = HISNFC100_OP_CTRL_WR_OPCODE(spi->write->cmd) | HISNFC100_OP_CTRL_CS_OP(host->cmd_option.chipselect) #ifdef HISNFC100_SUPPORT_REG_WRITE | HISNFC100_OP_CTRL_OP_TYPE(OP_TYPE_REG) #else | HISNFC100_OP_CTRL_OP_TYPE(OP_TYPE_DMA) #endif | HISNFC100_OP_CTRL_RW_OP(RW_OP_WRITE) | HISNFC100_OP_CTRL_OP_READY; hisfc_write(host, HISNFC100_OP_CTRL, val); if (DEBUG_WRITE) pr_info(" Set REG OP_CTRL[0x34]%#x\n", val); HISNFC100_DMA_WAIT_INT_FINISH(host); if (DEBUG_WRITE) { val = spi->driver->wait_ready(spi); if (val & STATUS_P_FAIL_MASK) pr_info("hisnfc100: %s page program failed!", op_type); pr_info(" status[%#x]\n", val); } if (DEBUG_WRITE) pr_info("* End %s page program!\n", op_type); }
static void hisnfc100_send_cmd_readstart(struct hisnfc_host *host) { unsigned char pages_per_block_shift, only_oob = 0; unsigned short wrap = 0; unsigned val, block_num, block_num_h, page_num, addr_of = 0; struct hisnfc_op *spi = host->spi; struct nand_chip *chip = host->chip; #ifdef HISNFC100_SUPPORT_REG_READ char *op_type = "reg"; #else char *op_type = "dma"; #endif if (DEBUG_READ) pr_info("* Enter %s page read start!\n", op_type); if ((host->addr_value[0] == host->cache_addr_value[0]) && (host->addr_value[1] == host->cache_addr_value[1])) { if (DEBUG_READ) pr_info("* %s page read cache hit! addr1[%#x], ", op_type, host->addr_value[1]); pr_info("addr0[%#x]\n", host->addr_value[0]); return; } val = spi->driver->wait_ready(spi); if (val) { pr_info("%s: %s read wait ready fail! status[%#x]\n", __func__, op_type, val); return; } val = HISNFC100_INT_CLR_ALL; hisfc_write(host, HISNFC100_INT_CLR, val); if (DEBUG_READ) pr_info(" Set REG INT_CLR[0x14]%#x\n", val); if (host->cmd_option.last_cmd == NAND_CMD_READOOB) { only_oob = 1; host->cmd_option.op_config = HISNFC100_OP_CFG_RD_OP_SEL(RD_OP_READ_OOB); } else host->cmd_option.op_config = HISNFC100_OP_CFG_RD_OP_SEL(RD_OP_READ_PAGE); val = host->cmd_option.op_config | HISNFC100_OP_CFG_MEM_IF_TYPE(spi->read->iftype) | HISNFC100_OP_CFG_DUMMY_ADDR_NUM(spi->read->dummy); hisfc_write(host, HISNFC100_OP_CFG, val); if (DEBUG_READ) pr_info(" Set REG OP_CFG[0x28]%#x\n", val); pages_per_block_shift = chip->phys_erase_shift - chip->page_shift; block_num = host->addr_value[1] >> pages_per_block_shift; block_num_h = block_num >> REG_CNT_HIGH_BLOCK_NUM_SHIFT; val = HISNFC100_ADDRH_SET(block_num_h); hisfc_write(host, HISNFC100_ADDRH, val); if (DEBUG_READ) pr_info(" Set REG ADDRH[0x2c]%#x\n", val); page_num = host->addr_value[1] - (block_num << pages_per_block_shift); if (only_oob) switch (host->ecctype) { case NAND_ECC_8BIT: addr_of = REG_CNT_ECC_8BIT_OFFSET; break; case NAND_ECC_16BIT: addr_of = REG_CNT_ECC_16BIT_OFFSET; break; case NAND_ECC_24BIT: addr_of = REG_CNT_ECC_24BIT_OFFSET; break; case NAND_ECC_0BIT: default: break; } val = (((block_num & REG_CNT_BLOCK_NUM_MASK) << REG_CNT_BLOCK_NUM_SHIFT) | ((page_num & REG_CNT_PAGE_NUM_MASK) << REG_CNT_PAGE_NUM_SHIFT) | ((wrap & REG_CNT_WRAP_MASK) << REG_CNT_WRAP_SHIFT) | (addr_of & REG_CNT_ECC_OFFSET_MASK)); hisfc_write(host, HISNFC100_ADDRL, val); if (DEBUG_READ) pr_info(" Set REG ADDRL[0x30]%#x\n", val); #ifndef HISNFC100_SUPPORT_REG_READ val = HISNFC100_DMA_CTRL_ALL_ENABLE; hisfc_write(host, HISNFC100_DMA_CTRL, val); if (DEBUG_READ) pr_info(" Set REG DMA_CTRL[0x3c]%#x\n", val); val = host->dma_buffer; hisfc_write(host, HISNFC100_DMA_SADDR_D, val); if (DEBUG_READ) pr_info(" Set REG DMA_SADDR_D[0x40]%#x\n", val); val = host->dma_oob; hisfc_write(host, HISNFC100_DMA_SADDR_OOB, val); if (DEBUG_READ) pr_info(" Set REG DMA_SADDR_OOB[%#x]%#x\n", HISNFC100_DMA_SADDR_OOB, val); #endif val = HISNFC100_OP_CTRL_RD_OPCODE(spi->read->cmd) | HISNFC100_OP_CTRL_CS_OP(host->cmd_option.chipselect) #ifdef HISNFC100_SUPPORT_REG_READ | HISNFC100_OP_CTRL_OP_TYPE(OP_TYPE_REG) #else | HISNFC100_OP_CTRL_OP_TYPE(OP_TYPE_DMA) #endif | HISNFC100_OP_CTRL_RW_OP(RW_OP_READ) | HISNFC100_OP_CTRL_OP_READY; hisfc_write(host, HISNFC100_OP_CTRL, val); if (DEBUG_READ) pr_info(" Set REG OP_CTRL[0x34]%#x\n", val); HISNFC100_DMA_WAIT_INT_FINISH(host); host->cache_addr_value[0] = host->addr_value[0]; host->cache_addr_value[1] = host->addr_value[1]; if (DEBUG_READ) pr_info("* End %s page read start!\n", op_type); }