Commit cafa2881 authored by Andrzej Głąbek's avatar Andrzej Głąbek Committed by Benjamin Cabé
Browse files

drivers: flash_mspi_nor: Refactor handling of commands



- Use standard operation codes and parameters from SFDP for handling
  the used flash commands (allow to override some of them through dts
  with the `read-command`, `write-command`, and `rx-dummy` properties)
- Use all available erase types as specified by SFDP
- Allow using all IO modes
- Add support for switching to 4-byte addressing mode
- Use common functions for reading and writing of status registers
  and for enabling write operations
- Switch IO mode (between the target one and Single IO) in a common
  function that performs transfers and do it only when required for
  a given command
- Make checking of JEDEC ID at initialization optional

Signed-off-by: default avatarAndrzej Głąbek <andrzej.glabek@nordicsemi.no>
parent 29bc5bf1
Loading
Loading
Loading
Loading
+487 −284

File changed.

Preview size limit exceeded, changes collapsed.

+6 −193
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@ struct flash_mspi_nor_config {
	struct mspi_dev_id mspi_id;
	struct mspi_dev_cfg mspi_nor_cfg;
	struct mspi_dev_cfg mspi_nor_init_cfg;
	enum mspi_dev_cfg_mask mspi_nor_cfg_mask;
#if defined(CONFIG_MSPI_XIP)
	struct mspi_xip_cfg xip_cfg;
#endif
@@ -83,213 +82,27 @@ struct flash_mspi_nor_config {
	struct flash_pages_layout layout;
#endif
	uint8_t jedec_id[SPI_NOR_MAX_ID_LEN];
	const struct flash_mspi_nor_cmds *jedec_cmds;
	struct flash_mspi_nor_quirks *quirks;
	const struct jesd216_erase_type *default_erase_types;
	struct flash_mspi_nor_cmd_info default_cmd_info;
	struct flash_mspi_nor_switch_info default_switch_info;
	bool jedec_id_specified  : 1;
	bool rx_dummy_specified  : 1;
	bool multiperipheral_bus : 1;
	bool multi_io_cmd        : 1;
	bool single_io_addr      : 1;
};

struct flash_mspi_nor_data {
	struct k_sem acquired;
	struct mspi_xfer_packet packet;
	struct mspi_xfer xfer;
	struct mspi_dev_cfg *curr_cfg;
	struct jesd216_erase_type erase_types[JESD216_NUM_ERASE_TYPES];
	struct flash_mspi_nor_cmd_info cmd_info;
	struct flash_mspi_nor_switch_info switch_info;
	bool in_target_io_mode;
};

struct flash_mspi_nor_cmd {
	enum mspi_xfer_direction dir;
	uint32_t cmd;
	uint16_t tx_dummy;
	uint16_t rx_dummy;
	uint8_t cmd_length;
	uint8_t addr_length;
	bool force_single;
};

struct flash_mspi_nor_cmds {
	struct flash_mspi_nor_cmd id;
	struct flash_mspi_nor_cmd write_en;
	struct flash_mspi_nor_cmd read;
	struct flash_mspi_nor_cmd status;
	struct flash_mspi_nor_cmd config;
	struct flash_mspi_nor_cmd page_program;
	struct flash_mspi_nor_cmd sector_erase;
	struct flash_mspi_nor_cmd chip_erase;
	struct flash_mspi_nor_cmd sfdp;
};

const struct flash_mspi_nor_cmds commands_single = {
	.id = {
		.dir = MSPI_RX,
		.cmd = JESD216_CMD_READ_ID,
		.cmd_length = 1,
	},
	.write_en = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_WREN,
		.cmd_length = 1,
	},
	.read = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_READ_FAST,
		.cmd_length = 1,
		.addr_length = 3,
		.rx_dummy = 8,
	},
	.status = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_RDSR,
		.cmd_length = 1,
	},
	.config = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_RDCR,
		.cmd_length = 1,
	},
	.page_program = {
		.dir  = MSPI_TX,
		.cmd = SPI_NOR_CMD_PP,
		.cmd_length = 1,
		.addr_length = 3,
	},
	.sector_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_SE,
		.cmd_length = 1,
		.addr_length = 3,
	},
	.chip_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_CE,
		.cmd_length = 1,
	},
	.sfdp = {
		.dir = MSPI_RX,
		.cmd = JESD216_CMD_READ_SFDP,
		.cmd_length = 1,
		.addr_length = 3,
		.rx_dummy = 8,
	},
};

const struct flash_mspi_nor_cmds commands_quad_1_4_4 = {
	.id = {
		.dir = MSPI_RX,
		.cmd = JESD216_CMD_READ_ID,
		.cmd_length = 1,
		.force_single = true,
	},
	.write_en = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_WREN,
		.cmd_length = 1,
	},
	.read = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_4READ,
		.cmd_length = 1,
		.addr_length = 3,
		.rx_dummy = 6,
	},
	.status = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_RDSR,
		.cmd_length = 1,
		.force_single = true,
	},
	.config = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_RDCR,
		.cmd_length = 1,
		.force_single = true,
	},
	.page_program = {
		.dir  = MSPI_TX,
		.cmd = SPI_NOR_CMD_PP_1_4_4,
		.cmd_length = 1,
		.addr_length = 3,
	},
	.sector_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_SE,
		.cmd_length = 1,
		.addr_length = 3,
		.force_single = true,
	},
	.chip_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_CE,
		.cmd_length = 1,
	},
	.sfdp = {
		.dir = MSPI_RX,
		.cmd = JESD216_CMD_READ_SFDP,
		.cmd_length = 1,
		.addr_length = 3,
		.rx_dummy = 8,
		.force_single = true,
	},
};

const struct flash_mspi_nor_cmds commands_octal = {
	.id = {
		.dir = MSPI_RX,
		.cmd = JESD216_OCMD_READ_ID,
		.cmd_length = 2,
		.addr_length = 4,
		.rx_dummy = 4
	},
	.write_en = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_OCMD_WREN,
		.cmd_length = 2,
	},
	.read = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_OCMD_RD,
		.cmd_length = 2,
		.addr_length = 4,
		.rx_dummy = 20,
	},
	.status = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_OCMD_RDSR,
		.cmd_length = 2,
		.addr_length = 4,
		.rx_dummy = 4,
	},
	.page_program = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_OCMD_PAGE_PRG,
		.cmd_length = 2,
		.addr_length = 4,
	},
	.sector_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_OCMD_SE,
		.cmd_length = 2,
		.addr_length = 4,
	},
	.chip_erase = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_OCMD_CE,
		.cmd_length = 2,
	},
	.sfdp = {
		.dir = MSPI_RX,
		.cmd = JESD216_OCMD_READ_SFDP,
		.cmd_length = 2,
		.addr_length = 4,
		.rx_dummy = 20,
	},
};

void flash_mspi_command_set(const struct device *dev, const struct flash_mspi_nor_cmd *cmd);

#ifdef __cplusplus
}
#endif
+19 −49
Original line number Diff line number Diff line
@@ -71,45 +71,29 @@ static inline int mxicy_mx25r_post_switch_mode(const struct device *dev)
	}

	/* Wait for previous write to finish */
	do {
		flash_mspi_command_set(dev, &dev_config->jedec_cmds->status);
		dev_data->packet.data_buf  = &status;
		dev_data->packet.num_bytes = sizeof(status);
		rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
	rc = wait_until_ready(dev, K_USEC(1));
	if (rc < 0) {
		return rc;
	}
	} while (status & SPI_NOR_WIP_BIT);

	/* Write enable */
	flash_mspi_command_set(dev, &commands_single.write_en);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id,
			     &dev_data->xfer);
	rc = cmd_wren(dev);
	if (rc < 0) {
		return rc;
	}

	/* Write status and config registers */
	const struct flash_mspi_nor_cmd cmd_status = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_WRSR,
		.cmd_length = 1,
	};

	flash_mspi_command_set(dev, &cmd_status);
	set_up_xfer(dev, MSPI_TX);
	dev_data->packet.data_buf  = mxicy_mx25r_hp_payload;
	dev_data->packet.num_bytes = sizeof(mxicy_mx25r_hp_payload);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
	rc = perform_xfer(dev, SPI_NOR_CMD_WRSR, false);
	if (rc < 0) {
		return rc;
	}

	/* Wait for write to end and verify status register */
	do {
		flash_mspi_command_set(dev, &dev_config->jedec_cmds->status);
		dev_data->packet.data_buf  = &status;
		dev_data->packet.num_bytes = sizeof(status);
		rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
		rc = cmd_rdsr(dev, SPI_NOR_CMD_RDSR, &status);
		if (rc < 0) {
			return rc;
		}
@@ -120,10 +104,10 @@ static inline int mxicy_mx25r_post_switch_mode(const struct device *dev)
	}

	/* Verify configuration registers */
	flash_mspi_command_set(dev, &dev_config->jedec_cmds->config);
	dev_data->packet.data_buf  = config;
	set_up_xfer(dev, MSPI_RX);
	dev_data->packet.num_bytes = sizeof(config);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
	dev_data->packet.data_buf  = config;
	rc = perform_xfer(dev, SPI_NOR_CMD_RDCR, false);
	if (rc < 0) {
		return rc;
	}
@@ -161,26 +145,18 @@ static inline int mxicy_mx25u_post_switch_mode(const struct device *dev)
	}

	/* Write enable */
	flash_mspi_command_set(dev, &commands_single.write_en);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id,
			     &dev_data->xfer);
	rc = cmd_wren(dev);
	if (rc < 0) {
		return rc;
	}

	/* Write config register 2 */
	const struct flash_mspi_nor_cmd cmd_status = {
		.dir = MSPI_TX,
		.cmd = SPI_NOR_CMD_WR_CFGREG2,
		.cmd_length = 1,
		.addr_length = 4,
	};

	flash_mspi_command_set(dev, &cmd_status);
	set_up_xfer(dev, MSPI_TX);
	dev_data->xfer.addr_length = 4;
	dev_data->packet.address   = 0;
	dev_data->packet.data_buf  = &mxicy_mx25u_oe_payload;
	dev_data->packet.num_bytes = sizeof(mxicy_mx25u_oe_payload);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
	return rc;
	return perform_xfer(dev, SPI_NOR_CMD_WR_CFGREG2, false);
}

static int mxicy_mx25u_pre_init(const struct device *dev)
@@ -208,18 +184,12 @@ static int mxicy_mx25u_pre_init(const struct device *dev)
	 */

	/* Read configured number of dummy cycles for memory reading commands. */
	const struct flash_mspi_nor_cmd cmd_rd_cr2 = {
		.dir = MSPI_RX,
		.cmd = SPI_NOR_CMD_RD_CFGREG2,
		.cmd_length = 1,
		.addr_length = 4,
	};

	flash_mspi_command_set(dev, &cmd_rd_cr2);
	set_up_xfer(dev, MSPI_RX);
	dev_data->xfer.addr_length = 4;
	dev_data->packet.address   = 0x300;
	dev_data->packet.data_buf  = &cfg_reg;
	dev_data->packet.num_bytes = sizeof(cfg_reg);
	rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer);
	rc = perform_xfer(dev, SPI_NOR_CMD_RD_CFGREG2, false);
	if (rc < 0) {
		LOG_ERR("Failed to read Dummy Cycle from CFGREG2");
		return rc;
+16 −1
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@

#define USES_4BYTE_ADDR(inst) \
	(USES_OCTAL_IO(inst) || \
	 DT_INST_PROP(inst, use_4byte_addressing) || \
	 BFP_DW1_ADDRESS_BYTES(inst) == JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B)

#define BFP_ENTER_4BYTE_ADDR_METHODS(inst) \
@@ -345,12 +346,26 @@
	BUILD_ASSERT(!USES_8D_8D_8D(inst) || \
		     BFP_DW18_CMD_EXT(inst) <= BFP_DW18_CMD_EXT_INV, \
		"Unsupported Octal Command Extension mode in " \
			DT_NODE_FULL_NAME(DT_DRV_INST(inst))); \
	BUILD_ASSERT(!DT_INST_PROP(inst, use_4byte_addressing) || \
		     (BFP_DW1_ADDRESS_BYTES(inst) \
		      != JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B), \
		"Cannot use 4-byte addressing for " \
			DT_NODE_FULL_NAME(DT_DRV_INST(inst))); \
	BUILD_ASSERT(!DT_INST_PROP(inst, use_4byte_addressing) || \
		     (BFP_ENTER_4BYTE_ADDR_METHODS(inst) \
		      & (BFP_DW16_4B_ADDR_ENTER_B7 | \
			 BFP_DW16_4B_ADDR_ENTER_06_B7 | \
			 BFP_DW16_4B_ADDR_PER_CMD | \
			 BFP_DW16_4B_ADDR_ALWAYS)), \
		"No supported method of entering 4-byte addressing mode for " \
			DT_NODE_FULL_NAME(DT_DRV_INST(inst)))

#else

#define USES_4BYTE_ADDR(inst) \
	(DT_INST_ENUM_IDX(inst, mspi_io_mode) == MSPI_IO_MODE_OCTAL)
	(DT_INST_ENUM_IDX(inst, mspi_io_mode) == MSPI_IO_MODE_OCTAL || \
	 DT_INST_PROP(inst, use_4byte_addressing))

#define DEFAULT_CMD_INFO(inst) { \
	.pp_cmd = USES_4BYTE_ADDR(inst) \
+23 −1
Original line number Diff line number Diff line
@@ -5,7 +5,20 @@ description: Generic NOR flash on MSPI bus

compatible: "jedec,mspi-nor"

include: [mspi-device.yaml, "jedec,spi-nor-common.yaml"]
include:
  - name: mspi-device.yaml
  - name: jedec,spi-nor-common.yaml
    property-allowlist:
      - jedec-id
      - size
      - sfdp-bfp
      - sfdp-ff05
      - sfdp-ff84
      - quad-enable-requirements
      - has-dpd
      - dpd-wakeup-sequence
      - t-enter-dpd
      - t-exit-dpd

properties:
  reset-gpios:
@@ -30,3 +43,12 @@ properties:
      Maximum time, in milliseconds, allowed for a single transfer on the MSPI
      bus in communication with the flash chip. The default value is the one
      that was previously hard-coded in the flash_mspi_nor driver.

  use-4byte-addressing:
    type: boolean
    description: |
      Indicates that 4-byte addressing is to be used in communication with
      the flash chip. The driver will use dedicated 4-byte address instruction
      codes for commands that require addresses (like Read, Page Program,
      or Erase) if those are supported by the flash chip, or if necessary,
      it will switch the chip to 4-byte addressing mode.