modify for the RWW function of Macronix Flash

pull/14221/head
rogeryou 2021-02-01 17:55:45 +08:00
parent 0c6753bb82
commit 0db8da1152
5 changed files with 270 additions and 17 deletions

View File

@ -42,4 +42,17 @@ uint8_t _sfdp_basic_param_table[64] = {0x30, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF,
uint8_t _sfdp_4_byte_inst_table[8] = {0x7F, 0xEF, 0xFF, 0xFF, 0x21, 0x5C, 0xDC, 0x14};
#endif
//#define MX_FLASH_SUPPORT_RWW 1
#define MX25LM51245G_FLASH_SIZE 0x4000000 /* 512 MBits => 64 MBytes */
#define MX25LM51245G_BLOCK_SIZE 0x10000 /* 1024 blocks of 64 KBytes */
#define MX25LM51245G_SECTOR_SIZE 0x1000 /* 16384 sectors of 4 kBytes */
#define MX25LM51245G_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */
#define MX25LM51245G_CHUNK_SIZE 0x10 /* fred: 16 bytes */
#ifdef MX_FLASH_SUPPORT_RWW
#define MX25LM51245G_BANK_SIZE 0x01000000 /* fred: 16 MBytes */
#define MX25LM51245G_BANK_SIZE_MASK ~(MX25LM51245G_BANK_SIZE - 1) /* fred: 0xFF000000 */
#endif
#endif // MBED_OSPI_FLASH_MX25LM51245G_H

View File

@ -62,6 +62,8 @@
#define MBED_CONF_OSPIF_OSPI_FREQ 40000000
#endif
#define MX_FLASH_SUPPORT_RWW
/** Enum ospif standard error codes
*
* @enum ospif_bd_error
@ -381,6 +383,10 @@ private:
// Detect 4-byte addressing mode and enable it if supported
int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size);
#ifdef MX_FLASH_SUPPORT_RWW
bool _is_mem_ready_rww(bd_addr_t addr, uint8_t rw);
#endif
private:
enum ospif_clear_protection_method_t {
OSPIF_BP_ULBPR, // Issue global protection unlock instruction
@ -449,6 +455,16 @@ private:
uint32_t _init_ref_count;
bool _is_initialized;
#ifdef MX_FLASH_SUPPORT_RWW
enum wait_flag {
NOT_STARTED, // no wait is started
WRITE_WAIT_STARTED, // write wait is started
ERASE_WAIT_STARTED, // erase wait is started
};
uint32_t _busy_bank; // Current busy bank
wait_flag _wait_flag; // wait flag
PlatformMutex _busy_mutex;
#endif
};
#endif

View File

@ -52,7 +52,16 @@ using namespace mbed;
#define OSPIF_NO_QUAD_ENABLE (-1)
// Configuration Register2 address
#define OSPIF_CR2_OPI_EN_ADDR 0x00000000
#define OSPIF_CR2_OPI_EN_ADDR 0x00000000
#define OSPIF_CR2_BANK_STATUS_ADDR 0xc0000000
#define OSPIF_CR2_RWWDI ((uint8_t)0x00) /*!< No active program or erase operation */
#define OSPIF_CR2_RWWDS ((uint8_t)0x01) /*!< Program/erase in other bank */
#define OSPIF_CR2_RWWBS ((uint8_t)0x03) /*!< program/erase operation in addressed bank */
#ifdef MX_FLASH_SUPPORT_RWW
#define MX25LM51245G_BANK_SIZE 0x01000000 /* 16 MBytes */
#define MX25LM51245G_BANK_SIZE_MASK ~(MX25LM51245G_BANK_SIZE - 1) /* 0xFF000000 */
#endif
/* SFDP Header Parsing */
/***********************/
@ -232,6 +241,11 @@ OSPIFBlockDevice::OSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam
_attempt_4_byte_addressing = true;
_4byte_msb_reg_write_inst = OSPIF_INST_4BYTE_REG_WRITE_DEFAULT;
_support_4_byte_inst = false;
#ifdef MX_FLASH_SUPPORT_RWW
_wait_flag = NOT_STARTED;
_busy_bank = 0xffffffff;
#endif
}
int OSPIFBlockDevice::init()
@ -358,6 +372,17 @@ int OSPIFBlockDevice::deinit()
return result;
}
if (false == _is_mem_ready()) {
tr_error("Device not ready after write, failed");
/* program_failed = true;
status = OSPIF_BD_ERROR_READY_FAILED;
goto exit_point;*/
}
#ifdef MX_FLASH_SUPPORT_RWW
_wait_flag = NOT_STARTED;
#endif
change_mode(SPI);
// Disable Device for Writing
@ -383,6 +408,29 @@ int OSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
int status = OSPIF_BD_ERROR_OK;
tr_debug("Read Inst: 0x%xh", _read_instruction);
#ifdef MX_FLASH_SUPPORT_RWW
bool need_wait;
need_wait = (_wait_flag != NOT_STARTED) && ((addr & MX25LM51245G_BANK_SIZE_MASK) == _busy_bank);
// Wait for ready
if (need_wait) {
_busy_mutex.lock();
if (_is_mem_ready_rww(addr, false) == false) {
return OSPIF_BD_ERROR_OK;
}
} else {
if (_wait_flag == WRITE_WAIT_STARTED) {
tr_debug("\r\n RWW1 CNT");
} else if (_wait_flag == ERASE_WAIT_STARTED) {
tr_debug("\r\n RWE2 CNT");
}
}
#endif
_mutex.lock();
// In DOPI mode, the number of read data should be even
@ -397,8 +445,13 @@ int OSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
_mutex.unlock();
return status;
#ifdef MX_FLASH_SUPPORT_RWW
if (need_wait) {
_busy_mutex.unlock();
}
#endif
return status;
}
int OSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
@ -418,6 +471,16 @@ int OSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
chunk = (offset + size < _page_size_bytes) ? size : (_page_size_bytes - offset);
written_bytes = chunk;
#ifdef MX_FLASH_SUPPORT_RWW
_busy_mutex.lock();
// Wait for ready
if (_is_mem_ready_rww(addr, true) == false) {
return OSPIF_BD_ERROR_OK;
}
#endif
_mutex.lock();
//Send WREN
@ -437,10 +500,14 @@ int OSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
goto exit_point;
}
buffer = static_cast<const uint8_t *>(buffer) + chunk;
addr += chunk;
size -= chunk;
#ifdef MX_FLASH_SUPPORT_RWW
_wait_flag = WRITE_WAIT_STARTED;
_busy_bank = addr & MX25LM51245G_BANK_SIZE_MASK;
_mutex.unlock();
_busy_mutex.unlock();
#else
if (false == _is_mem_ready()) {
tr_error("Device not ready after write, failed");
program_failed = true;
@ -448,6 +515,11 @@ int OSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
goto exit_point;
}
_mutex.unlock();
#endif
buffer = static_cast<const uint8_t *>(buffer) + chunk;
addr += chunk;
size -= chunk;
}
exit_point:
@ -511,6 +583,15 @@ int OSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
tr_debug("Erase - Region: %d, Type:%d ",
region, type);
#ifdef MX_FLASH_SUPPORT_RWW
_busy_mutex.lock();
// Wait for ready
if (_is_mem_ready_rww(addr, true) == false) {
return OSPIF_BD_ERROR_OK;
}
#endif
_mutex.lock();
if (_set_write_enable() != 0) {
@ -527,15 +608,14 @@ int OSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
goto exit_point;
}
addr += eu_size;
size -= eu_size;
#ifdef MX_FLASH_SUPPORT_RWW
_wait_flag = ERASE_WAIT_STARTED;
_busy_bank = addr & MX25LM51245G_BANK_SIZE_MASK;
if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) {
// erase crossed to next region
region++;
bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
}
_mutex.unlock();
_busy_mutex.unlock();
#else
if (false == _is_mem_ready()) {
tr_error("OSPI After Erase Device not ready - failed");
erase_failed = true;
@ -544,6 +624,16 @@ int OSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
}
_mutex.unlock();
#endif
addr += eu_size;
size -= eu_size;
if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) {
// erase crossed to next region
region++;
bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
}
}
exit_point:
@ -1537,6 +1627,51 @@ bool OSPIFBlockDevice::_is_mem_ready()
return mem_ready;
}
#ifdef MX_FLASH_SUPPORT_RWW
bool OSPIFBlockDevice::_is_mem_ready_rww(bd_addr_t addr, uint8_t rw)
{
uint16_t cr2_value = 0;
bool mem_ready = true;
static uint32_t rww_cnt = 0; // For testing
static uint32_t rwe_cnt = 0; // For testing
bd_addr_t bank_addr = addr & MX25LM51245G_BANK_SIZE_MASK;
if ((_wait_flag == NOT_STARTED) || (!rw && bank_addr != _busy_bank)) {
return mem_ready;
}
//Read CR2 Register 1 from device, the number of read byte need to be even in octa flash DOPI mode
if (OSPI_STATUS_OK != _ospi_send_general_command(OSPIF_INST_RDCR2, bank_addr + OSPIF_CR2_BANK_STATUS_ADDR,
NULL, 0,
(char *) &cr2_value, OSPI_DEFAULT_STATUS_REGISTERS)) { // store received value in cr2_value
tr_error("Reading CR2 Register failed");
}
cr2_value &= OSPIF_CR2_RWWBS;
if ((cr2_value == OSPIF_CR2_RWWBS) || (rw && (cr2_value == OSPIF_CR2_RWWDS))) {
// Wait until device ready
if (false == _is_mem_ready()) {
tr_error(" _is_mem_ready Failed");
mem_ready = false;
}
_wait_flag = NOT_STARTED;
} else if (!rw && (cr2_value == OSPIF_CR2_RWWDS)) {
// For testing
if (_wait_flag == WRITE_WAIT_STARTED) {
rww_cnt++;
tr_debug("rww_cnt = 0x%x ", rww_cnt);
} else {
rwe_cnt++;
tr_debug("rwe_cnt = 0x%x ", rwe_cnt);
}
}
return mem_ready;
}
#endif
/***************************************************/
/*********** OSPI Driver API Functions *************/
/***************************************************/
@ -1665,9 +1800,12 @@ ospi_status_t OSPIFBlockDevice::_ospi_send_general_command(ospi_inst_t instructi
if ((_inst_width == OSPI_CFG_BUS_OCTA) || (_inst_width == OSPI_CFG_BUS_OCTA_DTR)) {
if ((instruction == OSPIF_INST_RSR1) || (instruction == OSPIF_INST_RDID) ||
(instruction == OSPIF_INST_RDCR2) || (instruction == OSPIF_INST_RDCR)) {
_ospi.configure_format(_inst_width, _inst_size, _address_width, _address_size, OSPI_CFG_BUS_SINGLE, 0, _data_width, _dummy_cycles);
addr = 0;
} else if (instruction == OSPIF_INST_WSR1) {
_ospi.configure_format(_inst_width, _inst_size, _address_width, _address_size, OSPI_CFG_BUS_SINGLE,
0, _data_width, 4);
if (instruction != OSPIF_INST_RDCR2) {
addr = 0;
}
} else if ((instruction == OSPIF_INST_WSR1)) {
addr = 0;
}
}

View File

@ -433,6 +433,89 @@ void test_multi_threads()
}
#endif
#if defined(MX_FLASH_SUPPORT_RWW)
void test_rww_rwe()
{
utest_printf("\nTest rww and rwe Starts..\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
utest_printf("\ntest read bank1 data when write bank0\n");
// Determine start_address in bank 0
bd_addr_t start_address_B0 = sectors_addr[rand() % num_of_sectors];
utest_printf("start_address_B0=0x%016" PRIx64 "\n", start_address_B0);
// Determine start_address in bank 1
bd_addr_t start_address_B1 = start_address_B0 | 0x1000000;
utest_printf("start_address_B1=0x%016" PRIx64 "\n", start_address_B1);
// Determine data_buf_size
bd_size_t erase_size = block_device->get_erase_size(start_address_B0);
TEST_ASSERT(erase_size > 0);
bd_size_t data_buf_size = block_device->get_program_size();;
// Allocate buffer for write test data
uint8_t *data_buf = new (std::nothrow) uint8_t[data_buf_size];
TEST_SKIP_UNLESS_MESSAGE(data_buf != NULL, "Not enough memory for test");
// Allocate buffer for read test data
uint8_t *out_data_buf = new (std::nothrow) uint8_t[data_buf_size];
TEST_SKIP_UNLESS_MESSAGE(out_data_buf != NULL, "Not enough memory for test");
// First must Erase given memory region
utest_printf("erasing given memory region in bank0\n");
int err = block_device->erase(start_address_B0, erase_size);
TEST_ASSERT_EQUAL(0, err);
utest_printf("erasing given memory region in bank1\n");
err = block_device->erase(start_address_B1, erase_size);
TEST_ASSERT_EQUAL(0, err);
// Write random data to selected region to make sure data is not accidentally set to "erased" value.
// With this pre-write, the test case will fail even if block_device->erase() is broken.
for (bd_size_t i = 0; i < data_buf_size; i++) {
data_buf[i] = (uint8_t) rand();
}
utest_printf("writing given memory region in bank1\n");
err = block_device->program((const void *)data_buf, start_address_B1, data_buf_size);
TEST_ASSERT_EQUAL(0, err);
memset(out_data_buf, 0, data_buf_size);
utest_printf("writing given memory region in bank0\n");
err = block_device->program((const void *)data_buf, start_address_B0, data_buf_size);
TEST_ASSERT_EQUAL(0, err);
// Read written memory region in bank1 to verify it contains information
// utest_printf("reading written memory region in bank1 when write bank0\n");
err = block_device->read((void *)out_data_buf, start_address_B1, data_buf_size);
TEST_ASSERT_EQUAL(0, err);
// Verify erased memory region
utest_printf("verifying written memory region\n");
for (bd_size_t i = 0; i < data_buf_size; i++) {
TEST_ASSERT_EQUAL(out_data_buf[i], data_buf[i]);
}
utest_printf("\ntest read bank1 data when erase bank0\n");
utest_printf("erasing given memory region in bank0\n");
memset(out_data_buf, 0, data_buf_size);
err = block_device->erase(start_address_B0, erase_size);
TEST_ASSERT_EQUAL(0, err);
// Read written memory region in bank1 to verify it contains information
utest_printf("reading written memory region in bank1 when erase bank0\n");
err = block_device->read((void *)out_data_buf, start_address_B1, data_buf_size);
TEST_ASSERT_EQUAL(0, err);
delete[] out_data_buf;
delete[] data_buf;
}
#endif
void test_erase_functionality()
{
utest_printf("\nTest BlockDevice::get_erase_value()..\n");
@ -816,6 +899,9 @@ template_case_t template_cases[] = {
{"Testing BlockDevice erase functionality", test_erase_functionality, greentea_failure_handler},
{"Testing program read small data sizes", test_program_read_small_data_sizes, greentea_failure_handler},
{"Testing unaligned erase blocks", test_unaligned_erase_blocks, greentea_failure_handler},
#if defined(MX_FLASH_SUPPORT_RWW)
{"Testing read while write and read while erase", test_rww_rwe, greentea_failure_handler},
#endif
{"Testing Deinit block device", test_deinit_bd, greentea_failure_handler},
};

View File

@ -34,7 +34,7 @@
/* Max amount of flash size is 4Gbytes */
/* hence 2^(31+1), then FLASH_SIZE_DEFAULT = 1<<31 */
#define OSPI_FLASH_SIZE_DEFAULT 0x80000000
#define OSPI_FLASH_SIZE_DEFAULT 0x4000000 //512Mbits
static uint32_t get_alt_bytes_size(const uint32_t num_bytes)
{
@ -252,7 +252,7 @@ static ospi_status_t _ospi_init_direct(ospi_t *obj, const ospi_pinmap_t *pinmap,
obj->handle.Init.ClockPrescaler = 4; // default value, will be overwritten in ospi_frequency
obj->handle.Init.FifoThreshold = 4;
obj->handle.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
obj->handle.Init.DeviceSize = POSITION_VAL(OSPI_FLASH_SIZE_DEFAULT) - 1;
obj->handle.Init.DeviceSize = 32;
obj->handle.Init.ChipSelectHighTime = 3;
obj->handle.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
#if defined(HAL_OSPI_WRAP_NOT_SUPPORTED) // removed in STM32L4