Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions drivers/mspi/Kconfig.dw
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# Copyright (c) 2025 Tenstorrent AI ULC
# SPDX-License-Identifier: Apache-2.0

config MSPI_DW
Expand All @@ -7,3 +8,24 @@ config MSPI_DW
depends on DT_HAS_SNPS_DESIGNWARE_SSI_ENABLED
select PINCTRL if $(dt_compat_any_has_prop,$(DT_COMPAT_SNPS_DESIGNWARE_SSI),pinctrl-0)
imply MSPI_XIP
imply MSPI_TIMING

if MSPI_DW

config MSPI_DW_TXD_DIV
int "Designware SSI TX Drive edge divisor"
default 4
help
Division factor to apply to calculated BAUDR value when writing it
to the TXD_DRIVE_EDGE register in DDR mode. Note that the maximum
value of this register is (BAUDR / 2) - 1.

config MSPI_DW_TXD_MUL
int "Designware SSI TX Drive edge multiplier"
default 1
help
Multiplication factor to apply to calculated BAUDR value when writing
it to the TXD_DRIVE_EDGE register in DDR mode. Note that the maximum
value of this register is (BAUDR / 2) - 1.

endif # MSPI_DW
88 changes: 77 additions & 11 deletions drivers/mspi/mspi_dw.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
* Copyright (c) 2025 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -8,12 +9,15 @@

#include <zephyr/drivers/mspi.h>
#include <zephyr/drivers/gpio.h>
#if defined(CONFIG_PINCTRL)
#include <zephyr/drivers/pinctrl.h>
#endif
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/mspi/mspi_dw.h>

#include "mspi_dw.h"

Expand Down Expand Up @@ -45,6 +49,7 @@
uint32_t ctrlr0;
uint32_t spi_ctrlr0;
uint32_t baudr;
uint32_t rx_sample_dly;

#if defined(CONFIG_MSPI_XIP)
uint32_t xip_freq;
Expand Down Expand Up @@ -110,7 +115,9 @@
DEFINE_MM_REG_RD(isr, 0x30)
DEFINE_MM_REG_RD(risr, 0x34)
DEFINE_MM_REG_RD_WR(dr, 0x60)
DEFINE_MM_REG_WR(rx_sample_dly, 0xf0)
DEFINE_MM_REG_WR(spi_ctrlr0, 0xf4)

Check notice on line 119 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:119 -DEFINE_MM_REG_WR(rx_sample_dly, 0xf0) +DEFINE_MM_REG_WR(rx_sample_dly, 0xf0)
DEFINE_MM_REG_WR(txd_drive_edge, 0xf8)

#if defined(CONFIG_MSPI_XIP)
DEFINE_MM_REG_WR(xip_incr_inst, 0x100)
Expand Down Expand Up @@ -684,18 +691,30 @@
}

if (param_mask & MSPI_DEVICE_CONFIG_DATA_RATE) {
/* TODO: add support for DDR */
if (cfg->data_rate != MSPI_DATA_RATE_SINGLE) {
LOG_ERR("Only single data rate is supported.");
dev_data->spi_ctrlr0 &= ~(SPI_CTRLR0_SPI_DDR_EN_BIT |
SPI_CTRLR0_INST_DDR_EN_BIT);
switch (cfg->data_rate) {

Check notice on line 696 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:696 - dev_data->spi_ctrlr0 &= ~(SPI_CTRLR0_SPI_DDR_EN_BIT | - SPI_CTRLR0_INST_DDR_EN_BIT); + dev_data->spi_ctrlr0 &= ~(SPI_CTRLR0_SPI_DDR_EN_BIT | SPI_CTRLR0_INST_DDR_EN_BIT);
case MSPI_DATA_RATE_SINGLE:
break;
case MSPI_DATA_RATE_DUAL:
dev_data->spi_ctrlr0 |= SPI_CTRLR0_INST_DDR_EN_BIT;
/* Also need to set DDR_EN bit */
__fallthrough;
case MSPI_DATA_RATE_S_D_D:
dev_data->spi_ctrlr0 |= SPI_CTRLR0_SPI_DDR_EN_BIT;
break;
default:
LOG_ERR("Data rate %d not supported",
cfg->data_rate);
return -ENOTSUP;

Check notice on line 709 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:709 - LOG_ERR("Data rate %d not supported", - cfg->data_rate); + LOG_ERR("Data rate %d not supported", cfg->data_rate);
}
}

if (param_mask & MSPI_DEVICE_CONFIG_DQS) {
/* TODO: add support for DQS */
dev_data->spi_ctrlr0 &= ~SPI_CTRLR0_SPI_RXDS_EN_BIT;

if (cfg->dqs_enable) {
LOG_ERR("DQS line is not supported.");
return -ENOTSUP;
dev_data->spi_ctrlr0 |= SPI_CTRLR0_SPI_RXDS_EN_BIT;
}
}

Expand Down Expand Up @@ -817,9 +836,10 @@
dev_data->dummy_bytes = 0;
dev_data->bytes_to_discard = 0;

dev_data->ctrlr0 &= ~CTRLR0_TMOD_MASK
& ~CTRLR0_DFS_MASK;
dev_data->ctrlr0 &= ~(CTRLR0_TMOD_MASK)
& ~(CTRLR0_DFS_MASK)
& ~(CTRLR0_DFS32_MASK);

Check notice on line 842 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:842 - dev_data->ctrlr0 &= ~(CTRLR0_TMOD_MASK) - & ~(CTRLR0_DFS_MASK) - & ~(CTRLR0_DFS32_MASK); + dev_data->ctrlr0 &= ~(CTRLR0_TMOD_MASK) & ~(CTRLR0_DFS_MASK) & ~(CTRLR0_DFS32_MASK);
dev_data->spi_ctrlr0 &= ~SPI_CTRLR0_WAIT_CYCLES_MASK;

if (dev_data->standard_spi &&
Expand All @@ -827,16 +847,20 @@
dev_data->xfer.addr_length != 0)) {
dev_data->bytes_per_frame_exp = 0;
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 7);
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS32_MASK, 7);
} else {
if ((packet->num_bytes % 4) == 0) {
dev_data->bytes_per_frame_exp = 2;
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 31);
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS32_MASK, 31);
} else if ((packet->num_bytes % 2) == 0) {
dev_data->bytes_per_frame_exp = 1;
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 15);
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS32_MASK, 15);
} else {
dev_data->bytes_per_frame_exp = 0;
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 7);
dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS32_MASK, 7);
}
}

Expand Down Expand Up @@ -928,7 +952,16 @@
: 0);
write_spi_ctrlr0(dev, dev_data->spi_ctrlr0);
write_baudr(dev, dev_data->baudr);
write_ser(dev, BIT(dev_data->dev_id->dev_idx));
write_rx_sample_dly(dev, dev_data->rx_sample_dly);
if (dev_data->spi_ctrlr0 & (SPI_CTRLR0_SPI_DDR_EN_BIT |
SPI_CTRLR0_INST_DDR_EN_BIT)) {
int txd = (CONFIG_MSPI_DW_TXD_MUL * dev_data->baudr) /
CONFIG_MSPI_DW_TXD_DIV;

Check notice on line 960 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:960 - if (dev_data->spi_ctrlr0 & (SPI_CTRLR0_SPI_DDR_EN_BIT | - SPI_CTRLR0_INST_DDR_EN_BIT)) { - int txd = (CONFIG_MSPI_DW_TXD_MUL * dev_data->baudr) / - CONFIG_MSPI_DW_TXD_DIV; + if (dev_data->spi_ctrlr0 & (SPI_CTRLR0_SPI_DDR_EN_BIT | SPI_CTRLR0_INST_DDR_EN_BIT)) { + int txd = (CONFIG_MSPI_DW_TXD_MUL * dev_data->baudr) / CONFIG_MSPI_DW_TXD_DIV;
write_txd_drive_edge(dev, txd);
} else {
write_txd_drive_edge(dev, 0);
}

if (xip_enabled) {
write_ssienr(dev, SSIENR_SSIC_EN_BIT);
Expand Down Expand Up @@ -1015,8 +1048,17 @@
}
}

/* Prefill TX FIFO with any data we can */
if (dev_data->dummy_bytes && tx_dummy_bytes(dev)) {
imr = IMR_RXFIM_BIT;
} else if (packet->dir == MSPI_TX && packet->num_bytes) {
tx_data(dev, packet);
}

/* Enable interrupts now and wait until the packet is done. */
write_imr(dev, imr);
/* Write SER to start transfer */
write_ser(dev, BIT(dev_data->dev_id->dev_idx));

rc = k_sem_take(&dev_data->finished, timeout);
if (read_risr(dev) & RISR_RXOIR_BIT) {
Expand Down Expand Up @@ -1046,6 +1088,8 @@
} else {
write_ssienr(dev, 0);
}
/* Clear SER */
write_ser(dev, 0);

if (dev_data->dev_id->ce.port) {
int rc2;
Expand Down Expand Up @@ -1148,6 +1192,22 @@
return rc;
}

#if defined(CONFIG_MSPI_TIMING)
static int api_timing_config(const struct device *dev,
const struct mspi_dev_id *dev_id,
const uint32_t param_mask, void *cfg)

Check notice on line 1198 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:1198 -static int api_timing_config(const struct device *dev, - const struct mspi_dev_id *dev_id, +static int api_timing_config(const struct device *dev, const struct mspi_dev_id *dev_id,
{
struct mspi_dw_data *dev_data = dev->data;
struct mspi_dw_timing_cfg *config = cfg;

if (param_mask & MSPI_DW_RX_TIMING_CFG) {
dev_data->rx_sample_dly = config->rx_sample_dly;
return 0;
}
return -ENOTSUP;
}
#endif /* defined(CONFIG_MSPI_TIMING) */

#if defined(CONFIG_MSPI_XIP)
static int _api_xip_config(const struct device *dev,
const struct mspi_dev_id *dev_id,
Expand Down Expand Up @@ -1381,6 +1441,9 @@
}
}

/* Make sure controller is disabled. */
write_ssienr(dev, 0);

#if defined(CONFIG_PINCTRL)
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP);
Expand All @@ -1399,16 +1462,19 @@
.dev_config = api_dev_config,
.get_channel_status = api_get_channel_status,
.transceive = api_transceive,
#if defined(CONFIG_MSPI_TIMING)
.timing_config = api_timing_config,
#endif
#if defined(CONFIG_MSPI_XIP)
.xip_config = api_xip_config,
#endif
};

#define MSPI_DW_INST_IRQ(idx, inst) \
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \
IRQ_CONNECT(DT_INST_IRQN_BY_IDX(inst, idx), \
DT_INST_IRQ_BY_IDX(inst, idx, priority), \
mspi_dw_isr, DEVICE_DT_INST_GET(inst), 0); \
irq_enable(DT_INST_IRQ_BY_IDX(inst, idx, irq))
irq_enable(DT_INST_IRQN_BY_IDX(inst, idx))

Check notice on line 1477 in drivers/mspi/mspi_dw.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.c:1477 - .config = api_config, - .dev_config = api_dev_config, + .config = api_config, + .dev_config = api_dev_config, .get_channel_status = api_get_channel_status, - .transceive = api_transceive, + .transceive = api_transceive, #if defined(CONFIG_MSPI_TIMING) - .timing_config = api_timing_config, + .timing_config = api_timing_config, #endif #if defined(CONFIG_MSPI_XIP) - .xip_config = api_xip_config, + .xip_config = api_xip_config, #endif }; -#define MSPI_DW_INST_IRQ(idx, inst) \ - IRQ_CONNECT(DT_INST_IRQN_BY_IDX(inst, idx), \ - DT_INST_IRQ_BY_IDX(inst, idx, priority), \ - mspi_dw_isr, DEVICE_DT_INST_GET(inst), 0); \ +#define MSPI_DW_INST_IRQ(idx, inst) \ + IRQ_CONNECT(DT_INST_IRQN_BY_IDX(inst, idx), DT_INST_IRQ_BY_IDX(inst, idx, priority), \ + mspi_dw_isr, DEVICE_DT_INST_GET(inst), 0); \

#define MSPI_DW_MMIO_ROM_INIT(node_id) \
COND_CODE_1(DT_REG_HAS_NAME(node_id, core), \
Expand Down
22 changes: 16 additions & 6 deletions drivers/mspi/mspi_dw.h
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
* Copyright (c) 2025 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/

#if DT_HAS_COMPAT_STATUS_OKAY(snps_designware_ssi_v2)
/*
* Later versions of the SSI have different register offsets. Define a macro
* to use these.
*/
#define SSI_VERSION_2 1
#endif

/*
* This header is part of mspi_dw.c extracted only for clarity.
* It is not supposed to be included by any file other than mspi_dw.c.
*/

/* CTRLR0 - Control Register 0 */
#define CTRLR0_SPI_FRF_MASK GENMASK(23, 22)
#define CTRLR0_SPI_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(22, 21), GENMASK(23, 22))
#define CTRLR0_SPI_FRF_STANDARD 0UL
#define CTRLR0_SPI_FRF_DUAL 1UL
#define CTRLR0_SPI_FRF_QUAD 2UL
#define CTRLR0_SPI_FRF_OCTAL 3UL
#define CTRLR0_TMOD_MASK GENMASK(11, 10)
#define CTRLR0_TMOD_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(9, 8), GENMASK(11, 10))
#define CTRLR0_TMOD_TX_RX 0UL
#define CTRLR0_TMOD_TX 1UL
#define CTRLR0_TMOD_RX 2UL
#define CTRLR0_TMOD_EEPROM 3UL
#define CTRLR0_SCPOL_BIT BIT(9)
#define CTRLR0_SCPH_BIT BIT(8)
#define CTRLR0_FRF_MASK GENMASK(7, 6)
#define CTRLR0_SCPOL_BIT COND_CODE_1(SSI_VERSION_2, BIT(7), BIT(9))
#define CTRLR0_SCPH_BIT COND_CODE_1(SSI_VERSION_2, BIT(6), BIT(8))
#define CTRLR0_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(5, 4), GENMASK(7, 6))
#define CTRLR0_FRF_SPI 0UL
#define CTRLR0_FRF_SSP 1UL
#define CTRLR0_FRF_MICROWIRE 2UL
#define CTRLR0_DFS_MASK GENMASK(4, 0)
#define CTRLR0_DFS_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(3, 0), GENMASK(4, 0))
#define CTRLR0_DFS32_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(20, 16), (0))

Check notice on line 40 in drivers/mspi/mspi_dw.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mspi/mspi_dw.h:40 -#define CTRLR0_SPI_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(22, 21), GENMASK(23, 22)) +#define CTRLR0_SPI_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(22, 21), GENMASK(23, 22)) #define CTRLR0_SPI_FRF_STANDARD 0UL #define CTRLR0_SPI_FRF_DUAL 1UL #define CTRLR0_SPI_FRF_QUAD 2UL #define CTRLR0_SPI_FRF_OCTAL 3UL -#define CTRLR0_TMOD_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(9, 8), GENMASK(11, 10)) +#define CTRLR0_TMOD_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(9, 8), GENMASK(11, 10)) #define CTRLR0_TMOD_TX_RX 0UL #define CTRLR0_TMOD_TX 1UL #define CTRLR0_TMOD_RX 2UL #define CTRLR0_TMOD_EEPROM 3UL -#define CTRLR0_SCPOL_BIT COND_CODE_1(SSI_VERSION_2, BIT(7), BIT(9)) -#define CTRLR0_SCPH_BIT COND_CODE_1(SSI_VERSION_2, BIT(6), BIT(8)) -#define CTRLR0_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(5, 4), GENMASK(7, 6)) +#define CTRLR0_SCPOL_BIT COND_CODE_1(SSI_VERSION_2, BIT(7), BIT(9)) +#define CTRLR0_SCPH_BIT COND_CODE_1(SSI_VERSION_2, BIT(6), BIT(8)) +#define CTRLR0_FRF_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(5, 4), GENMASK(7, 6)) #define CTRLR0_FRF_SPI 0UL #define CTRLR0_FRF_SSP 1UL #define CTRLR0_FRF_MICROWIRE 2UL -#define CTRLR0_DFS_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(3, 0), GENMASK(4, 0)) -#define CTRLR0_DFS32_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(20, 16), (0)) +#define CTRLR0_DFS_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(3, 0), GENMASK(4, 0)) +#define CTRLR0_DFS32_MASK COND_CODE_1(SSI_VERSION_2, GENMASK(20, 16), (0))
/* CTRLR1- Control Register 1 */
#define CTRLR1_NDF_MASK GENMASK(15, 0)

Expand Down
38 changes: 38 additions & 0 deletions drivers/mspi/mspi_dw_vendor_specific.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
* Copyright (c) 2025 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -96,4 +97,41 @@ static inline int vendor_specific_xip_disable(const struct device *dev,
}
#endif /* defined(CONFIG_MSPI_XIP) */

#else
static inline void vendor_specific_init(const struct device *dev)
{
ARG_UNUSED(dev);
}
static inline void vendor_specific_suspend(const struct device *dev)
{
ARG_UNUSED(dev);
}
static inline void vendor_specific_resume(const struct device *dev)
{
ARG_UNUSED(dev);
}
static inline void vendor_specific_irq_clear(const struct device *dev)
{
ARG_UNUSED(dev);
}
static inline int vendor_specific_xip_enable(const struct device *dev,
const struct mspi_dev_id *dev_id,
const struct mspi_xip_cfg *cfg)
{
ARG_UNUSED(dev);
ARG_UNUSED(dev_id);
ARG_UNUSED(cfg);

return 0;
}
static inline int vendor_specific_xip_disable(const struct device *dev,
const struct mspi_dev_id *dev_id,
const struct mspi_xip_cfg *cfg)
{
ARG_UNUSED(dev);
ARG_UNUSED(dev_id);
ARG_UNUSED(cfg);

return 0;
}
#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_exmif) */
29 changes: 29 additions & 0 deletions include/zephyr/drivers/mspi/mspi_dw.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DRIVERS_MSPI_DW_H_
#define ZEPHYR_INCLUDE_DRIVERS_MSPI_DW_H_

#ifdef __cplusplus
extern "C" {
#endif

/**
* Designware MSPI configuration structure- this should be passed to the
* MSPI driver when calling mspi_timing_config
*/
struct mspi_dw_timing_cfg {
uint32_t rx_sample_dly; /* RX sample delay, written to RX_SAMPLE_DLY register */
};

/* Configure RX_SAMPLE_DLY register for MSPI DW SSI */
#define MSPI_DW_RX_TIMING_CFG BIT(0)

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_DRIVERS_MSPI_DW_H_ */
Loading