drivers: flash: flash_mcux_flexspi_nor: move device data to RAM

flexspi driver should not interact with flash whenever possible, and
should never use flash while in a critical write or erase section.
Move device data to RAM to prevent this read-while-write hazard.

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2022-03-21 15:07:50 -05:00 committed by David Leach
commit 61c3f0aa44

View file

@ -55,13 +55,17 @@ enum {
}; };
struct flash_flexspi_nor_config { struct flash_flexspi_nor_config {
const struct device *controller;
flexspi_port_t port; flexspi_port_t port;
flexspi_device_config_t config; flexspi_device_config_t config;
struct flash_pages_layout layout; struct flash_pages_layout layout;
struct flash_parameters flash_parameters; struct flash_parameters flash_parameters;
}; };
/* Device variables used in critical sections should be in this structure */
struct flash_flexspi_nor_data {
const struct device *controller;
};
static const uint32_t flash_flexspi_nor_lut[][4] = { static const uint32_t flash_flexspi_nor_lut[][4] = {
[READ_ID] = { [READ_ID] = {
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID, FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID,
@ -148,6 +152,7 @@ static int flash_flexspi_nor_get_vendor_id(const struct device *dev,
uint8_t *vendor_id) uint8_t *vendor_id)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
uint32_t buffer = 0; uint32_t buffer = 0;
int ret; int ret;
@ -163,7 +168,7 @@ static int flash_flexspi_nor_get_vendor_id(const struct device *dev,
LOG_DBG("Reading id"); LOG_DBG("Reading id");
ret = memc_flexspi_transfer(config->controller, &transfer); ret = memc_flexspi_transfer(data->controller, &transfer);
*vendor_id = buffer; *vendor_id = buffer;
return ret; return ret;
@ -173,6 +178,7 @@ static int flash_flexspi_nor_read_status(const struct device *dev,
uint32_t *status) uint32_t *status)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = 0, .deviceAddress = 0,
@ -186,13 +192,14 @@ static int flash_flexspi_nor_read_status(const struct device *dev,
LOG_DBG("Reading status register"); LOG_DBG("Reading status register");
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_write_status(const struct device *dev, static int flash_flexspi_nor_write_status(const struct device *dev,
uint32_t *status) uint32_t *status)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = 0, .deviceAddress = 0,
@ -206,12 +213,13 @@ static int flash_flexspi_nor_write_status(const struct device *dev,
LOG_DBG("Writing status register"); LOG_DBG("Writing status register");
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_write_enable(const struct device *dev) static int flash_flexspi_nor_write_enable(const struct device *dev)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = 0, .deviceAddress = 0,
@ -225,13 +233,14 @@ static int flash_flexspi_nor_write_enable(const struct device *dev)
LOG_DBG("Enabling write"); LOG_DBG("Enabling write");
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_erase_sector(const struct device *dev, static int flash_flexspi_nor_erase_sector(const struct device *dev,
off_t offset) off_t offset)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = offset, .deviceAddress = offset,
@ -245,12 +254,13 @@ static int flash_flexspi_nor_erase_sector(const struct device *dev,
LOG_DBG("Erasing sector at 0x%08zx", (ssize_t) offset); LOG_DBG("Erasing sector at 0x%08zx", (ssize_t) offset);
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_erase_chip(const struct device *dev) static int flash_flexspi_nor_erase_chip(const struct device *dev)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = 0, .deviceAddress = 0,
@ -264,13 +274,14 @@ static int flash_flexspi_nor_erase_chip(const struct device *dev)
LOG_DBG("Erasing chip"); LOG_DBG("Erasing chip");
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_page_program(const struct device *dev, static int flash_flexspi_nor_page_program(const struct device *dev,
off_t offset, const void *buffer, size_t len) off_t offset, const void *buffer, size_t len)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
flexspi_transfer_t transfer = { flexspi_transfer_t transfer = {
.deviceAddress = offset, .deviceAddress = offset,
@ -284,7 +295,7 @@ static int flash_flexspi_nor_page_program(const struct device *dev,
LOG_DBG("Page programming %d bytes to 0x%08zx", len, (ssize_t) offset); LOG_DBG("Page programming %d bytes to 0x%08zx", len, (ssize_t) offset);
return memc_flexspi_transfer(config->controller, &transfer); return memc_flexspi_transfer(data->controller, &transfer);
} }
static int flash_flexspi_nor_wait_bus_busy(const struct device *dev) static int flash_flexspi_nor_wait_bus_busy(const struct device *dev)
@ -306,12 +317,12 @@ static int flash_flexspi_nor_wait_bus_busy(const struct device *dev)
static int flash_flexspi_nor_enable_quad_mode(const struct device *dev) static int flash_flexspi_nor_enable_quad_mode(const struct device *dev)
{ {
const struct flash_flexspi_nor_config *config = dev->config; struct flash_flexspi_nor_data *data = dev->data;
uint32_t status = 0x40; uint32_t status = 0x40;
flash_flexspi_nor_write_status(dev, &status); flash_flexspi_nor_write_status(dev, &status);
flash_flexspi_nor_wait_bus_busy(dev); flash_flexspi_nor_wait_bus_busy(dev);
memc_flexspi_reset(config->controller); memc_flexspi_reset(data->controller);
return 0; return 0;
} }
@ -320,7 +331,8 @@ static int flash_flexspi_nor_read(const struct device *dev, off_t offset,
void *buffer, size_t len) void *buffer, size_t len)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
uint8_t *src = memc_flexspi_get_ahb_address(config->controller, struct flash_flexspi_nor_data *data = dev->data;
uint8_t *src = memc_flexspi_get_ahb_address(data->controller,
config->port, config->port,
offset); offset);
@ -333,16 +345,22 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset,
const void *buffer, size_t len) const void *buffer, size_t len)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
size_t size = len; size_t size = len;
uint8_t *src = (uint8_t *) buffer; uint8_t *src = (uint8_t *) buffer;
int i; int i;
unsigned int key = 0; unsigned int key = 0;
uint8_t *dst = memc_flexspi_get_ahb_address(config->controller, uint8_t *dst = memc_flexspi_get_ahb_address(data->controller,
config->port, config->port,
offset); offset);
if (memc_flexspi_is_running_xip(config->controller)) { if (memc_flexspi_is_running_xip(data->controller)) {
/*
* ==== ENTER CRITICAL SECTION ====
* No flash access should be performed in critical section. All
* code and data accessed must reside in ram.
*/
key = irq_lock(); key = irq_lock();
} }
@ -362,13 +380,14 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset,
flash_flexspi_nor_page_program(dev, offset, src, i); flash_flexspi_nor_page_program(dev, offset, src, i);
#endif #endif
flash_flexspi_nor_wait_bus_busy(dev); flash_flexspi_nor_wait_bus_busy(dev);
memc_flexspi_reset(config->controller); memc_flexspi_reset(data->controller);
src += i; src += i;
offset += i; offset += i;
len -= i; len -= i;
} }
if (memc_flexspi_is_running_xip(config->controller)) { if (memc_flexspi_is_running_xip(data->controller)) {
/* ==== EXIT CRITICAL SECTION ==== */
irq_unlock(key); irq_unlock(key);
} }
@ -383,11 +402,12 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset,
size_t size) size_t size)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
int num_sectors = size / SPI_NOR_SECTOR_SIZE; int num_sectors = size / SPI_NOR_SECTOR_SIZE;
int i; int i;
unsigned int key = 0; unsigned int key = 0;
uint8_t *dst = memc_flexspi_get_ahb_address(config->controller, uint8_t *dst = memc_flexspi_get_ahb_address(data->controller,
config->port, config->port,
offset); offset);
@ -401,7 +421,12 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset,
return -EINVAL; return -EINVAL;
} }
if (memc_flexspi_is_running_xip(config->controller)) { if (memc_flexspi_is_running_xip(data->controller)) {
/*
* ==== ENTER CRITICAL SECTION ====
* No flash access should be performed in critical section. All
* code and data accessed must reside in ram.
*/
key = irq_lock(); key = irq_lock();
} }
@ -409,18 +434,19 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset,
flash_flexspi_nor_write_enable(dev); flash_flexspi_nor_write_enable(dev);
flash_flexspi_nor_erase_chip(dev); flash_flexspi_nor_erase_chip(dev);
flash_flexspi_nor_wait_bus_busy(dev); flash_flexspi_nor_wait_bus_busy(dev);
memc_flexspi_reset(config->controller); memc_flexspi_reset(data->controller);
} else { } else {
for (i = 0; i < num_sectors; i++) { for (i = 0; i < num_sectors; i++) {
flash_flexspi_nor_write_enable(dev); flash_flexspi_nor_write_enable(dev);
flash_flexspi_nor_erase_sector(dev, offset); flash_flexspi_nor_erase_sector(dev, offset);
flash_flexspi_nor_wait_bus_busy(dev); flash_flexspi_nor_wait_bus_busy(dev);
memc_flexspi_reset(config->controller); memc_flexspi_reset(data->controller);
offset += SPI_NOR_SECTOR_SIZE; offset += SPI_NOR_SECTOR_SIZE;
} }
} }
if (memc_flexspi_is_running_xip(config->controller)) { if (memc_flexspi_is_running_xip(data->controller)) {
/* ==== EXIT CRITICAL SECTION ==== */
irq_unlock(key); irq_unlock(key);
} }
@ -453,28 +479,29 @@ static void flash_flexspi_nor_pages_layout(const struct device *dev,
static int flash_flexspi_nor_init(const struct device *dev) static int flash_flexspi_nor_init(const struct device *dev)
{ {
const struct flash_flexspi_nor_config *config = dev->config; const struct flash_flexspi_nor_config *config = dev->config;
struct flash_flexspi_nor_data *data = dev->data;
uint8_t vendor_id; uint8_t vendor_id;
if (!device_is_ready(config->controller)) { if (!device_is_ready(data->controller)) {
LOG_ERR("Controller device is not ready"); LOG_ERR("Controller device is not ready");
return -ENODEV; return -ENODEV;
} }
if (!memc_flexspi_is_running_xip(config->controller) && if (!memc_flexspi_is_running_xip(data->controller) &&
memc_flexspi_set_device_config(config->controller, &config->config, memc_flexspi_set_device_config(data->controller, &config->config,
config->port)) { config->port)) {
LOG_ERR("Could not set device configuration"); LOG_ERR("Could not set device configuration");
return -EINVAL; return -EINVAL;
} }
if (memc_flexspi_update_lut(config->controller, 0, if (memc_flexspi_update_lut(data->controller, 0,
(const uint32_t *) flash_flexspi_nor_lut, (const uint32_t *) flash_flexspi_nor_lut,
sizeof(flash_flexspi_nor_lut) / 4)) { sizeof(flash_flexspi_nor_lut) / 4)) {
LOG_ERR("Could not update lut"); LOG_ERR("Could not update lut");
return -EINVAL; return -EINVAL;
} }
memc_flexspi_reset(config->controller); memc_flexspi_reset(data->controller);
if (flash_flexspi_nor_get_vendor_id(dev, &vendor_id)) { if (flash_flexspi_nor_get_vendor_id(dev, &vendor_id)) {
LOG_ERR("Could not read vendor id"); LOG_ERR("Could not read vendor id");
@ -535,7 +562,6 @@ static const struct flash_driver_api flash_flexspi_nor_api = {
#define FLASH_FLEXSPI_NOR(n) \ #define FLASH_FLEXSPI_NOR(n) \
static const struct flash_flexspi_nor_config \ static const struct flash_flexspi_nor_config \
flash_flexspi_nor_config_##n = { \ flash_flexspi_nor_config_##n = { \
.controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
.port = DT_INST_REG_ADDR(n), \ .port = DT_INST_REG_ADDR(n), \
.config = FLASH_FLEXSPI_DEVICE_CONFIG(n), \ .config = FLASH_FLEXSPI_DEVICE_CONFIG(n), \
.layout = { \ .layout = { \
@ -547,12 +573,16 @@ static const struct flash_driver_api flash_flexspi_nor_api = {
.write_block_size = NOR_WRITE_SIZE, \ .write_block_size = NOR_WRITE_SIZE, \
.erase_value = NOR_ERASE_VALUE, \ .erase_value = NOR_ERASE_VALUE, \
}, \ }, \
}; \
static struct flash_flexspi_nor_data \
flash_flexspi_nor_data_##n = { \
.controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
}; \ }; \
\ \
DEVICE_DT_INST_DEFINE(n, \ DEVICE_DT_INST_DEFINE(n, \
flash_flexspi_nor_init, \ flash_flexspi_nor_init, \
NULL, \ NULL, \
NULL, \ &flash_flexspi_nor_data_##n, \
&flash_flexspi_nor_config_##n, \ &flash_flexspi_nor_config_##n, \
POST_KERNEL, \ POST_KERNEL, \
CONFIG_FLASH_INIT_PRIORITY, \ CONFIG_FLASH_INIT_PRIORITY, \