Skip to content

Commit

Permalink
drivers: flash: mspi NOR flash driver polling the status REG
Browse files Browse the repository at this point in the history
Add a function to poll the NOR flash status register with a MSPI_REG
set as direction and bit mask/value se to the packet structure
This info is going to the MSPI driver through mspi_transceive function

Signed-off-by: Francois Ramu <francois.ramu@st.com>
  • Loading branch information
FRASTM committed Sep 23, 2024
1 parent e7fe714 commit 689de6c
Showing 1 changed file with 115 additions and 73 deletions.
188 changes: 115 additions & 73 deletions drivers/flash/flash_mspi_nor_mx.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
* SPDX-License-Identifier: Apache-2.0
*/

/*
* **************************************************************************
* MSPI flash device driver for Macronix mx25lm51245 (or compatible)
* This driver is working with the drivers/mspi/mspi_stm32.c driver
* Flash device with compatible = "mspi-nor-mx25" in the DTS NODE
* **************************************************************************
*/
#define DT_DRV_COMPAT mspi_nor_mx25

#include <zephyr/kernel.h>
Expand All @@ -22,8 +29,18 @@ LOG_MODULE_REGISTER(flash_mspi_nor_mx, CONFIG_FLASH_LOG_LEVEL);
typedef struct mspi_timing_cfg mspi_timing_cfg;
typedef enum mspi_timing_param mspi_timing_param;

#define NOR_WRITE_SIZE 1
#define NOR_ERASE_VALUE 0xff
#define NOR_MX_WRITE_SIZE 1
#define NOR_MX_ERASE_VALUE 0xff

#define NOR_MX_STATUS_MEM_RDY 1
#define NOR_MX_STATUS_MEM_WREN 2
#define NOR_MX_STATUS_MEM_ERASED 3

#define NOR_MX_RESET_MAX_TIME 100U
#define NOR_MX_BULK_ERASE_MAX_TIME 460000U
#define NOR_MX_SECTOR_ERASE_MAX_TIME 1000U
#define NOR_MX_SUBSECTOR_4K_ERASE_MAX_TIME 400U
#define NOR_MX_WRITE_REG_MAX_TIME 40U

enum nor_mx_dummy_clock {
NOR_MX_DC_8,
Expand Down Expand Up @@ -136,73 +153,103 @@ static int flash_mspi_nor_mx_command_write(const struct device *flash, uint8_t c

ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
if (ret) {
LOG_ERR("MSPI write transaction failed with code: %d", ret);
LOG_ERR("MSPI Tx transaction failed with code: %d", ret);
return -EIO;
}

LOG_DBG("MSPI Tx transaction (cmd = 0x%x)", data->packet.cmd);

return ret;
}

/* Command to the flash for reading status register */
static int flash_mspi_nor_mx_status_read(const struct device *flash, uint8_t cmd, uint8_t *status)
/* Command to the flash for reading parameters */
static int flash_mspi_nor_mx_command_read(const struct device *flash, uint8_t cmd, uint32_t addr,
uint16_t addr_len, uint32_t rx_dummy, uint8_t *rdata,
uint32_t length)
{
const struct flash_mspi_nor_mx_config *cfg = flash->config;
struct flash_mspi_nor_mx_data *data = flash->data;
int ret;

data->packet.dir = MSPI_RX;
data->packet.cmd = cmd;
data->packet.address = 0;
data->packet.data_buf = status;
data->packet.num_bytes = 1;
data->packet.address = addr;
data->packet.data_buf = rdata;
data->packet.num_bytes = length;

data->trans.async = false; /* meaning : timeout mode */
data->trans.xfer_mode = MSPI_REG; /* command_read is always in PIO mode */
data->trans.rx_dummy = 0;
data->trans.xfer_mode = MSPI_PIO; /* command_read is always in PIO mode */
data->trans.rx_dummy = rx_dummy;
data->trans.cmd_length = 1;
data->trans.addr_length = 0;
data->trans.addr_length = addr_len;
data->trans.hold_ce = false;
data->trans.packets = &data->packet;
data->trans.num_packet = 1;
data->trans.timeout = 10;

ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
if (ret) {
LOG_ERR("MSPI read transaction failed with code: %d", ret);
LOG_ERR("MSPI Rx transaction failed with code: %d", ret);
return -EIO;
}

LOG_DBG("MSPI Rx transaction (cmd = %d)", data->packet.cmd);

return ret;
}

/* Command to the flash for reading parameters */
static int flash_mspi_nor_mx_command_read(const struct device *flash, uint8_t cmd, uint32_t addr,
uint16_t addr_len, uint32_t rx_dummy, uint8_t *rdata,
uint32_t length)
/* Command to the flash for reading status register */
static int flash_mspi_nor_mx_status_read(const struct device *flash, uint8_t status)
{
const struct flash_mspi_nor_mx_config *cfg = flash->config;
struct flash_mspi_nor_mx_data *data = flash->data;
int ret;
uint8_t status_config[2];/* index 0 for Match, index 1 for MASK */

data->packet.dir = MSPI_RX;
data->packet.cmd = cmd;
data->packet.address = addr;
data->packet.data_buf = rdata;
data->packet.num_bytes = length;
data->packet.dir = MSPI_TX; /* a command to be sent */
data->packet.cmd = SPI_NOR_CMD_RDSR; /* SPI/STR */
data->packet.address = 0;

data->trans.async = false; /* meaning : timeout mode */
data->trans.xfer_mode = MSPI_PIO; /* command_read is always in PIO mode */
data->trans.rx_dummy = rx_dummy;
data->trans.num_packet = 1; /* 1 in STR; 2 in DTR */
data->trans.async = true; /* IT mode */
data->trans.xfer_mode = MSPI_REG; /* command is always in PIO mode */
data->trans.tx_dummy = 0;
data->trans.cmd_length = 1;
data->trans.addr_length = addr_len;
data->trans.addr_length = 0;
data->trans.hold_ce = false;
data->trans.packets = &data->packet;
data->trans.num_packet = 1;
data->trans.timeout = 10;

/* Send the Read status Reg command and the autopolling with matching bit */
switch (status) {
case NOR_MX_STATUS_MEM_RDY:
status_config[0] = SPI_NOR_MEM_RDY_MATCH;
status_config[1] = SPI_NOR_MEM_RDY_MASK;
data->trans.timeout = HAL_XSPI_TIMEOUT_DEFAULT_VALUE;
break;
case NOR_MX_STATUS_MEM_ERASED:
status_config[0] = SPI_NOR_WEL_MATCH;
status_config[1] = SPI_NOR_WEL_MASK;
data->trans.timeout = NOR_MX_BULK_ERASE_MAX_TIME;
break;
case NOR_MX_STATUS_MEM_WREN:
status_config[0] = SPI_NOR_WREN_MATCH;
status_config[1] = SPI_NOR_WREN_MASK;
data->trans.timeout = HAL_XSPI_TIMEOUT_DEFAULT_VALUE;
break;
default:
LOG_ERR("Flash MSPI read status %d not supported", status);
return -EIO;
}
data->packet.data_buf = status_config;
data->packet.num_bytes = sizeof(status_config);

ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
if (ret) {
LOG_ERR("MSPI read transaction failed with code: %d", ret);
LOG_ERR("Flash MSPI read transaction failed with code: %d", ret);
return -EIO;
}

LOG_DBG("Flash MSPI status transaction (mode = %d)", data->trans.xfer_mode);

return ret;
}

Expand Down Expand Up @@ -236,6 +283,7 @@ static void release(const struct device *flash)
k_sem_give(&data->lock);
}

/* Enables writing to the memory sending a Write Enable and wait it is effective */
static int flash_mspi_nor_mx_write_enable(const struct device *flash)
{
int ret;
Expand All @@ -244,8 +292,11 @@ static int flash_mspi_nor_mx_write_enable(const struct device *flash)

/* Initialize the write enable command */
ret = flash_mspi_nor_mx_command_write(flash, SPI_NOR_CMD_WREN, 0, 4, 0, NULL, 0);

/* Wait for auto-polling bit */
if (ret) {
return ret;
}
/* Followed by the polling on bit WREN */
ret = flash_mspi_nor_mx_status_read(flash, NOR_MX_STATUS_MEM_WREN);

return ret;
}
Expand All @@ -257,7 +308,7 @@ static int flash_mspi_nor_mx_write_disable(const struct device *flash)
LOG_DBG("Disabling write");
ret = flash_mspi_nor_mx_command_write(flash, SPI_NOR_CMD_WRDI, 0, 4, 0, NULL, 0);

// return ret;
return ret;
}

static int flash_mspi_nor_mx_reset(const struct device *flash)
Expand Down Expand Up @@ -331,6 +382,22 @@ static int flash_mspi_nor_mx_erase_sector(const struct device *flash, off_t addr
return ret;
}

static int flash_mspi_nor_mx_erased(const struct device *flash)
{
int ret;

LOG_DBG("Wait for mem erased");

/* Wait polling the WEL (write enable latch) bit to become to 0
* When the Chip Erase Cycle is completed, the Write Enable Latch (WEL) bit is cleared.
* in cfg_mode SPI/OPI and cfg_rate transfer STR/DTR
*/
ret = flash_mspi_nor_mx_status_read(flash, NOR_MX_STATUS_MEM_ERASED);

return ret;
}


static int flash_mspi_nor_mx_erase_block(const struct device *flash, off_t addr)
{
int ret;
Expand Down Expand Up @@ -403,35 +470,19 @@ static int flash_mspi_nor_mx_mem_ready(const struct device *flash)
uint32_t instruction;
int ret;

if (data->dev_cfg.io_mode == MSPI_IO_MODE_SINGLE) {
rx_dummy = 0;
instruction = SPI_NOR_CMD_RDSR;
} else {
rx_dummy = SPI_NOR_DUMMY_REG_OCTAL;
instruction = SPI_NOR_OCMD_RDSR;
// TIMING_CFG_SET_RX_DUMMY(&data->timing_cfg, 4);
if (mspi_timing_config(cfg->bus, &cfg->dev_id, cfg->timing_cfg_mask,
(void *)&data->timing_cfg)) {
LOG_ERR("Failed to config mspi controller");;
return -EIO;
}
LOG_DBG("Reading status register");
ret = flash_mspi_nor_mx_status_read(flash, NOR_MX_STATUS_MEM_RDY);
if (ret) {
LOG_ERR("Could not read status");
return ret;
}

// do {
LOG_DBG("Reading status register");
ret = flash_mspi_nor_mx_status_read(flash, instruction, (uint8_t *)&status);
if (ret) {
LOG_ERR("Could not read status");
return ret;
}
// } while (status & SPI_NOR_WIP_BIT);


if (data->dev_cfg.io_mode != MSPI_IO_MODE_SINGLE) {
data->timing_cfg = bkp;
if (mspi_timing_config(cfg->bus, &cfg->dev_id, cfg->timing_cfg_mask,
(void *)&data->timing_cfg)) {
LOG_ERR("Failed to config mspi controller");;
LOG_ERR("Failed to config mspi controller");
return -EIO;
}
}
Expand All @@ -458,7 +509,7 @@ static int flash_mspi_nor_mx_read(const struct device *flash, off_t offset, void
return -EINVAL;
}

LOG_DBG("Flash : read %d Bytes at x%08zx", size, offset);
LOG_DBG("Flash : read %d Bytes at 0x%lx", size, (long)offset);
acquire(flash);

/* During the MemoryMapped, read with a memcopy */
Expand All @@ -469,7 +520,7 @@ static int flash_mspi_nor_mx_read(const struct device *flash, off_t offset, void

memcpy(rdata, (void *)mmap_addr, size);

LOG_DBG("Read %d bytes from 0x%08zx", size, (ssize_t)offset);
LOG_DBG("Read %d bytes from 0x%lx", size, (long)offset);
goto read_end;
}

Expand Down Expand Up @@ -526,7 +577,7 @@ static int flash_mspi_nor_mx_write(const struct device *flash, off_t offset, con
return -EINVAL;
}

LOG_DBG("Flash : write %d Bytes at x%08zx", size, offset);
LOG_DBG("Flash : write %d Bytes at 0x%lx", size, (long)offset);

acquire(flash);

Expand Down Expand Up @@ -558,7 +609,7 @@ static int flash_mspi_nor_mx_write(const struct device *flash, off_t offset, con
goto write_end;
}

ret = flash_mspi_nor_mx_mem_ready(flash);
ret = flash_mspi_nor_mx_status_read(flash, NOR_MX_STATUS_MEM_RDY);
if (ret) {
goto write_end;
}
Expand Down Expand Up @@ -643,24 +694,21 @@ static int flash_mspi_nor_mx_erase(const struct device *flash, off_t offset, siz
if (ret) {
goto erase_end;
}

ret = flash_mspi_nor_mx_mem_ready(flash);
/* Chip (Bulk) erase started, wait until WEL becomes 0 */
ret = flash_mspi_nor_mx_erased(flash);
if (ret) {
goto erase_end;
}

} else if ((0 == (offset % SPI_NOR_BLOCK_SIZE)) && (0 == (size % SPI_NOR_BLOCK_SIZE))) {
for (i = 0; i < num_blocks; i++) {
/* Check if write enable on each sector or for the whole device */
ret = flash_mspi_nor_mx_write_enable(flash);
if (ret) {
goto erase_end;
}

ret = flash_mspi_nor_mx_unprotect_sector(flash, offset);

LOG_DBG("Flash : erase block %d", 1 + (offset % SPI_NOR_BLOCK_SIZE));

ret = flash_mspi_nor_mx_write_enable(flash);
if (ret) {
goto erase_end;
}
Expand All @@ -684,18 +732,12 @@ static int flash_mspi_nor_mx_erase(const struct device *flash, off_t offset, siz
if (ret) {
goto erase_end;
}*/
/* Check if write enable on each sector or for the whole device */
ret = flash_mspi_nor_mx_write_enable(flash);
if (ret) {
goto erase_end;
}

ret = flash_mspi_nor_mx_mem_ready(flash);
if (ret) {
goto erase_end;
}

LOG_DBG("Flash : erase sector %d", 1 + (offset % SPI_NOR_SECTOR_SIZE));

ret = flash_mspi_nor_mx_erase_sector(flash, offset);
if (ret) {
goto erase_end;
Expand Down Expand Up @@ -976,8 +1018,8 @@ static const struct flash_mspi_nor_mx_config flash_mspi_nor_mx_cfg = {
.mem_size = DT_INST_PROP(0, size), /* in Bytes */
.flash_param =
{
.write_block_size = NOR_WRITE_SIZE,
.erase_value = NOR_ERASE_VALUE,
.write_block_size = NOR_MX_WRITE_SIZE,
.erase_value = NOR_MX_ERASE_VALUE,
},
.page_layout =
{
Expand Down

0 comments on commit 689de6c

Please sign in to comment.