/* * Copyright (c) @CompanyNameMagicTag 2018-2020. All rights reserved. * Description: NON-OS NANDFLASH DRIVER * Author: @CompanyNameTag * Create: 2020-10-15 */ #include "nandflash.h" #include "securec.h" #include "stdint.h" #include "watchdog.h" #include "hal_nandflash.h" #include "nandflash_inner.h" #include "nandflash.h" #include "tcxo.h" #include "hal_nandflash.h" #include "nandflash_config.h" #include "nandflash_qspi.h" #include "hal_nandflash.h" nandflash_trans_type_t g_trans_type = TRANS_BY_DMA_QUAD; #define FLASH_GET_P_FAIL_STATUS(x) (0x08 & (x)) #define FLASH_GET_E_FAIL_STATUS(x) (0x04 & (x)) #define TIMEOUT 1000 #define MC_FLASH_WAIT_10US 10 #define NAND_ID_DATA_SIZE 2 static qspi_data_type_def g_nand_qspi_data = {0}; errcode_t uapi_nandflash_read_id(uint16_t *id) { if (id == NULL) { return ERRCODE_INVALID_PARAM; } static qspi_data_type_def qspi_data = {0}; qspi_data.instruction = CMD_FLASH_ID; qspi_data.address_mode = MC_OSPI_ADDRESS_NONE; qspi_data.address = 0; qspi_data.address_size = 0; qspi_data.dummy_cycles = MC_OSPI_CYCLES_8_BITS; qspi_data.data_mode = MC_OSPI_DATA_1_LINE; qspi_data.data_size = NAND_ID_DATA_SIZE; *id = read_id(&qspi_data); return ERRCODE_SUCC; } uint32_t mc_flash_read_sr(uint8_t addr, uint8_t *data) { uapi_watchdog_kick(); qspi_data_type_def qspi_data = {0}; qspi_data.instruction = CMD_FLASH_RDSR; qspi_data.address_mode = MC_OSPI_ADDRESS_1_LINE; qspi_data.address = addr; qspi_data.address_size = MC_OSPI_ADDRESS_8_BITS; qspi_data.dummy_cycles = MC_OSPI_CYCLES_NONE; qspi_data.data_mode = MC_OSPI_DATA_1_LINE; qspi_data.data_size = 1; /* 1: one byte */ *data = read_sr(&qspi_data, addr); return MC_SUCCESS; } uint32_t mc_flash_write_sr(uint8_t addr, uint8_t data) { uapi_watchdog_kick(); uint32_t ret; qspi_data_type_def qspi_data = {0}; qspi_data.instruction = CMD_FLASH_WRSR; qspi_data.address_mode = MC_OSPI_ADDRESS_1_LINE; qspi_data.address = addr; qspi_data.address_size = MC_OSPI_ADDRESS_8_BITS; qspi_data.dummy_cycles = MC_OSPI_CYCLES_NONE; qspi_data.data_mode = MC_OSPI_DATA_1_LINE; qspi_data.data_size = 1; /* 1: one byte */ ret = write_sr(&qspi_data, addr, data); return ret; } void mc_flash_write_cmd(uint8_t cmd) { write_cmd(cmd); } void mc_flash_busy_wait(void) { uapi_watchdog_kick(); qspi_data_type_def qspi_data = {0}; qspi_data.instruction = CMD_FLASH_RDSR; qspi_data.address_mode = MC_OSPI_ADDRESS_1_LINE; qspi_data.address = CMD_FLASH_SR3_ADDR; qspi_data.address_size = MC_OSPI_ADDRESS_8_BITS; qspi_data.dummy_cycles = MC_OSPI_CYCLES_NONE; qspi_data.data_mode = MC_OSPI_DATA_1_LINE; qspi_data.data_size = 1; uint8_t status = read_sr(&qspi_data, (uint8_t)qspi_data.address); uint32_t timeout = TIMEOUT; uint32_t i = 1; while ((status & 0x1) != 0 && timeout != 0) { uapi_tcxo_delay_us(i * MC_FLASH_WAIT_10US); i++; status = read_sr(&qspi_data, (uint8_t)qspi_data.address); timeout = timeout - 1; } if ((status & 0x1) != 0) { PRINT("mc_flash_busy_wait , nandflash status:%x not equal zero!!!\r\n", status); } return; } uint32_t mc_flash_read_page(uint32_t nand_page, uint8_t *data, uint32_t data_len, uint8_t *oob, uint32_t oob_len, uint8_t *status_reg) { uapi_watchdog_kick(); NFPRINT("mc_flash_read_page nand_page = %d\r\n", nand_page); uint32_t page_addr; errno_t err_code; uint8_t error_cnt = 0; if (nand_page >= (get_nand_flash()->pages_per_block * get_nand_flash()->total_block)) { return MC_FAILURE; } mc_flash_busy_wait(); page_addr = SWAP_U32(nand_page); NFPRINT("page addr = %u \r\n", page_addr); qspi_data_type_def qspi_data = {0}; qspi_data.data_ptr = (uint8_t *)&page_addr; qspi_data.instruction = 0x13; read_cell_array(&qspi_data); mc_flash_busy_wait(); qspi_data_type_def qspi_read_buffer = {0}; qspi_read_buffer.instruction = 0x03; qspi_read_buffer.data_size = get_nand_flash()->bytes_per_page + get_nand_flash()->bytes_per_oob; read_buffer(&qspi_read_buffer, data, data_len, oob, oob_len); mc_flash_read_sr(CMD_FLASH_SR3_ADDR, status_reg); NFPRINT("mc_flash_read_page success status = %x\r\n", *status_reg); return MC_SUCCESS; } uint32_t mc_flash_write_page(uint32_t nand_page, uint8_t *data, uint32_t data_len, uint8_t *oob, uint32_t oob_len) { uapi_watchdog_kick(); uint32_t ret; uint32_t page_addr; uint8_t status_reg; write_cmd(CMD_FLASH_WREN); qspi_data_type_def p_load_qspi_data = {0}; p_load_qspi_data.instruction = 0x02; p_load_qspi_data.data_size = get_nand_flash()->bytes_per_page + get_nand_flash()->bytes_per_oob; program_load(&p_load_qspi_data, data, data_len, oob, oob_len); qspi_data_type_def e_load_qspi_data = {0}; e_load_qspi_data.instruction = CMD_FLASH_PP_EXE; page_addr = SWAP_U32(nand_page); e_load_qspi_data.data_ptr = (uint8_t *)&page_addr; program_execute(&e_load_qspi_data); mc_flash_busy_wait(); mc_flash_read_sr(CMD_FLASH_SR3_ADDR, &status_reg); if (FLASH_GET_P_FAIL_STATUS(status_reg) != 0) { ret = MC_FAILURE; } else { ret = MC_SUCCESS; } write_cmd(CMD_FLASH_WRDI); NFPRINT("mc_flash_write_page nand_page = %d, ret = %d , status = %x\r\n", nand_page, ret, status_reg); return ret; } uint32_t mc_flash_erase_block(uint32_t block_no) { uapi_watchdog_kick(); NFPRINT("mc_flash_erase_block block_no = %d\r\n", block_no); uint32_t ret; uint32_t page_addr; uint8_t reg_status; page_addr = SWAP_U32(block_no * get_nand_flash()->pages_per_block); write_cmd(CMD_FLASH_WREN); qspi_data_type_def erase_qspi_data = {0}; erase_qspi_data.data_ptr = (uint8_t *)&page_addr; erase_qspi_data.instruction = 0xd8; block_erase(&erase_qspi_data); mc_flash_busy_wait(); mc_flash_read_sr(CMD_FLASH_SR3_ADDR, ®_status); if (FLASH_GET_E_FAIL_STATUS(reg_status) != 0) { ret = MC_FAILURE; } else { ret = MC_SUCCESS; } write_cmd(CMD_FLASH_WRDI); NFPRINT("mc_flash_erase_block ret = %d , status =%x\r\n", ret, reg_status); return ret; } uint32_t mc_flash_mark_bad_block(uint32_t block_no) { uapi_watchdog_kick(); PRINT("mark block %d is bad= %d\r\n", block_no); write_cmd(CMD_FLASH_WREN); uint32_t mark_sign = 0xbbccffff; qspi_data_type_def mark = {0}; mark.instruction = CMD_FLASH_PP_RANDOM; mark.data_ptr = (uint8_t *)&mark_sign; mark.address = (uint16_t)(get_nand_flash()->bytes_per_page); mark_bad_block(&mark); qspi_data_type_def execute = {0}; execute.instruction = CMD_FLASH_PP_EXE; uint32_t page_addr = SWAP_U32(block_no * get_nand_flash()->pages_per_block); execute.data_ptr = (uint8_t *)&page_addr; program_execute(&execute); mc_flash_busy_wait(); write_cmd(CMD_FLASH_WRDI); return MC_SUCCESS; } uint32_t mc_flash_check_bad_block(uint32_t block_no) { uapi_watchdog_kick(); uint32_t ret = NOT_BAD_BLOCK; uint32_t page_addr = SWAP_U32(block_no * get_nand_flash()->pages_per_block); qspi_data_type_def cell_read = {0}; cell_read.data_ptr = (uint8_t *)&page_addr; cell_read.instruction = CMD_FLASH_READ_PAGE; read_cell_array(&cell_read); mc_flash_busy_wait(); qspi_data_type_def random_read = {0}; uint32_t check_value; random_read.data_ptr = &check_value; random_read.instruction = CMD_FLASH_READ; random_read.data_size = 4; // 4 is data length random_read.address = (uint16_t)(get_nand_flash()->bytes_per_page); read_buffer_single_line_width_8(&random_read); /* check the oob fisrt byte 2 and byte 3 bytes, they are badblock bits */ check_value = check_value >> 16; // 16 is mark pos need if (check_value == 0xbbcc) { return BAD_BLOCK; } NFPRINT("block %d is ret = %d , good ok 1 bad\r\n", block_no, ret); return ret; } void set_trans_type(nandflash_trans_type_t type) { g_trans_type = type; } nandflash_trans_type_t get_trans_type(void) { return g_trans_type; }