diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 649a13aca0186..a5d5142ae66f8 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -41,6 +41,8 @@ LOG_MODULE_REGISTER(spi_dw); #include #endif +#define DW_HSSI_VER_102A (0x3130322a) + static inline bool spi_dw_is_slave(struct spi_dw_data *spi) { return (IS_ENABLED(CONFIG_SPI_SLAVE) && @@ -213,6 +215,7 @@ static int spi_dw_configure(const struct device *dev, if ((config->operation & SPI_TRANSFER_LSB) || (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + !IS_ENABLED(CONFIG_SPI_DW_HSSI) && (config->operation & (SPI_LINES_DUAL | SPI_LINES_QUAD | SPI_LINES_OCTAL)))) { LOG_ERR("Unsupported configuration"); @@ -226,7 +229,7 @@ static int spi_dw_configure(const struct device *dev, } /* Word size */ - if (info->max_xfer_size == 32) { + if (!IS_ENABLED(CONFIG_SPI_DW_HSSI) && (info->max_xfer_size == 32)) { ctrlr0 |= DW_SPI_CTRLR0_DFS_32(SPI_WORD_SIZE_GET(config->operation)); } else { ctrlr0 |= DW_SPI_CTRLR0_DFS_16(SPI_WORD_SIZE_GET(config->operation)); @@ -248,6 +251,23 @@ static int spi_dw_configure(const struct device *dev, ctrlr0 |= DW_SPI_CTRLR0_SRL; } +#if defined(CONFIG_SPI_DW_HSSI) && defined(CONFIG_SPI_EXTENDED_MODES) + if (spi->version >= DW_HSSI_VER_102A) { + /* SPI frame format for Tx/Rx data */ + switch (SPI_LINES_GET(config->operation)) { + case SPI_LINES_DUAL: + ctrlr0 |= DW_SPI_CTRLR0_SPI_DUAL; + break; + case SPI_LINES_QUAD: + ctrlr0 |= DW_SPI_CTRLR0_SPI_QUAD; + break; + case SPI_LINES_OCTAL: + ctrlr0 |= DW_SPI_CTRLR0_SPI_OCTAL; + break; + } + } +#endif + /* Installing the configuration */ write_ctrlr0(dev, ctrlr0); @@ -323,6 +343,18 @@ static void spi_dw_update_txftlr(const struct device *dev, } else if (spi->ctx.tx_len < dw_spi_txftlr_dflt) { reg_data = spi->ctx.tx_len - 1; } + } else { +#if defined(CONFIG_SPI_DW_HSSI) && defined(CONFIG_SPI_EXTENDED_MODES) + /* + * TXFTLR field in the TXFTLR register is valid only for + * Controller mode operation + */ + if (!spi->ctx.tx_len) { + reg_data = 0U; + } else if (spi->ctx.tx_len < dw_spi_txftlr_dflt) { + reg_data = (spi->ctx.tx_len - 1) << DW_SPI_TXFTLR_TXFTLR_SHIFT; + } +#endif } LOG_DBG("TxFTLR: %u", reg_data); @@ -398,6 +430,23 @@ static int transceive(const struct device *dev, write_ctrlr0(dev, reg_data); +#if defined(CONFIG_SPI_DW_HSSI) && defined(CONFIG_SPI_EXTENDED_MODES) + if (spi->version >= DW_HSSI_VER_102A) { + /* Enhanced SPI operation */ + reg_data = read_spi_ctrlr0(dev); + reg_data &= ~DW_SPI_ESPI_CTRLR0_TRANS_TYPE_MASK; + reg_data |= FIELD_PREP(DW_SPI_ESPI_CTRLR0_TRANS_TYPE_MASK, + SPI_TRANS_TYPE_FIELD_GET(config->operation)); + reg_data &= ~DW_SPI_ESPI_CTRLR0_ADDR_L_MASK; + reg_data |= FIELD_PREP(DW_SPI_ESPI_CTRLR0_ADDR_L_MASK, + SPI_ADDR_L_FIELD_GET(config->operation)); + reg_data &= ~DW_SPI_ESPI_CTRLR0_INST_L_MASK; + reg_data |= FIELD_PREP(DW_SPI_ESPI_CTRLR0_INST_L_MASK, + SPI_INST_L_FIELD_GET(config->operation)); + write_spi_ctrlr0(dev, reg_data); + } +#endif + /* Set buffers info */ spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs); @@ -423,6 +472,15 @@ static int transceive(const struct device *dev, /* Rx Threshold */ write_rxftlr(dev, reg_data); + /* Rx sample delay */ + if (info->rx_sample_delay) { + reg_data = read_rx_sample_dly(dev); + reg_data &= ~DW_SPI_RX_SAMPLE_DELAY_MASK; + reg_data |= FIELD_PREP(DW_SPI_RX_SAMPLE_DELAY_MASK, + info->rx_sample_delay); + write_rx_sample_dly(dev, reg_data); + } + /* Enable interrupts */ reg_data = !rx_bufs ? DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX : @@ -554,6 +612,12 @@ int spi_dw_init(const struct device *dev) write_imr(dev, DW_SPI_IMR_MASK); clear_bit_ssienr(dev); + /* SSI component version */ + spi->version = read_ssi_comp_version(dev); + LOG_DBG("Version: %c.%c%c%c", (spi->version >> 24) & 0xff, + (spi->version >> 16) & 0xff, (spi->version >> 8) & 0xff, + spi->version & 0xff); + LOG_DBG("Designware SPI driver initialized on device: %p", dev); err = spi_context_cs_configure_all(&spi->ctx); @@ -647,6 +711,7 @@ COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \ .serial_target = DT_INST_PROP(inst, serial_target), \ .fifo_depth = DT_INST_PROP(inst, fifo_depth), \ .max_xfer_size = DT_INST_PROP(inst, max_xfer_size), \ + .rx_sample_delay = DT_INST_PROP(inst, rx_sample_delay), \ IF_ENABLED(CONFIG_PINCTRL, (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),)) \ COND_CODE_1(DT_INST_PROP(inst, aux_reg), \ (.read_func = aux_reg_read, \ diff --git a/drivers/spi/spi_dw.h b/drivers/spi/spi_dw.h index e1df26d1c14ef..711acc9c5c283 100644 --- a/drivers/spi/spi_dw.h +++ b/drivers/spi/spi_dw.h @@ -35,6 +35,7 @@ struct spi_dw_config { bool serial_target; uint8_t fifo_depth; uint8_t max_xfer_size; + uint8_t rx_sample_delay; #ifdef CONFIG_PINCTRL const struct pinctrl_dev_config *pcfg; #endif @@ -48,6 +49,7 @@ struct spi_dw_config { struct spi_dw_data { DEVICE_MMIO_RAM; struct spi_context ctx; + uint32_t version; /* ssi comp version */ uint8_t dfs; /* dfs in bytes: 1,2 or 4 */ uint8_t fifo_diff; /* cannot be bigger than FIFO depth */ }; @@ -194,6 +196,23 @@ static int reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off) #define DW_SPI_CTRLR0_SRL_BIT (13) #endif +#if defined(CONFIG_SPI_DW_HSSI) && defined(CONFIG_SPI_EXTENDED_MODES) +/* TXFTLR setting. Only valid for Controller operation mode. */ +#define DW_SPI_TXFTLR_TXFTLR_SHIFT (16) + +/* SPI Frame Format */ +#define DW_SPI_CTRLR0_SPI_FRF_SHIFT (22) +#define DW_SPI_CTRLR0_SPI_STANDARD (0 << DW_SPI_CTRLR0_SPI_FRF_SHIFT) +#define DW_SPI_CTRLR0_SPI_DUAL (1 << DW_SPI_CTRLR0_SPI_FRF_SHIFT) +#define DW_SPI_CTRLR0_SPI_QUAD (2 << DW_SPI_CTRLR0_SPI_FRF_SHIFT) +#define DW_SPI_CTRLR0_SPI_OCTAL (3 << DW_SPI_CTRLR0_SPI_FRF_SHIFT) + +/* SPI_CTRLR0 settings */ +#define DW_SPI_ESPI_CTRLR0_INST_L_MASK GENMASK(9, 8) +#define DW_SPI_ESPI_CTRLR0_ADDR_L_MASK GENMASK(5, 2) +#define DW_SPI_ESPI_CTRLR0_TRANS_TYPE_MASK GENMASK(1, 0) +#endif + #define DW_SPI_CTRLR0_SCPH BIT(DW_SPI_CTRLR0_SCPH_BIT) #define DW_SPI_CTRLR0_SCPOL BIT(DW_SPI_CTRLR0_SCPOL_BIT) #define DW_SPI_CTRLR0_SRL BIT(DW_SPI_CTRLR0_SRL_BIT) @@ -273,6 +292,9 @@ static int reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off) DW_SPI_IMR_RXOIM | \ DW_SPI_IMR_RXFIM)) +/* RX Sample Delay */ +#define DW_SPI_RX_SAMPLE_DELAY_MASK GENMASK(7, 0) + /* * Including the right register definition file * SoC SPECIFIC! diff --git a/drivers/spi/spi_dw_regs.h b/drivers/spi/spi_dw_regs.h index 711c6690091e7..1dc2f68422d8b 100644 --- a/drivers/spi/spi_dw_regs.h +++ b/drivers/spi/spi_dw_regs.h @@ -40,6 +40,7 @@ extern "C" { #define DW_SPI_REG_SSI_COMP_VERSION (0x5c) #define DW_SPI_REG_DR (0x60) #define DW_SPI_REG_RX_SAMPLE_DLY (0xf0) +#define DW_SPI_REG_SPI_CTRLR0 (0xf4) /* Register helpers */ DEFINE_MM_REG_WRITE(ctrlr0, DW_SPI_REG_CTRLR0, 32) @@ -51,6 +52,10 @@ DEFINE_MM_REG_READ(txftlr, DW_SPI_REG_TXFTLR, 32) DEFINE_MM_REG_WRITE(dr, DW_SPI_REG_DR, 32) DEFINE_MM_REG_READ(dr, DW_SPI_REG_DR, 32) DEFINE_MM_REG_READ(ssi_comp_version, DW_SPI_REG_SSI_COMP_VERSION, 32) +DEFINE_MM_REG_WRITE(rx_sample_dly, DW_SPI_REG_RX_SAMPLE_DLY, 32) +DEFINE_MM_REG_READ(rx_sample_dly, DW_SPI_REG_RX_SAMPLE_DLY, 32) +DEFINE_MM_REG_WRITE(spi_ctrlr0, DW_SPI_REG_SPI_CTRLR0, 32) +DEFINE_MM_REG_READ(spi_ctrlr0, DW_SPI_REG_SPI_CTRLR0, 32) #ifdef CONFIG_SPI_DW_ACCESS_WORD_ONLY DEFINE_MM_REG_WRITE(ctrlr1, DW_SPI_REG_CTRLR1, 32) diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index 01073f8d0039a..2c84f37172f2a 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -44,3 +44,12 @@ properties: enum: - 16 - 32 + + rx-sample-delay: + type: int + default: 0 + description: | + Receive Data(rxd) Sample Delay. This is used to delay + the sample of the rxd input port. Each value represents + a single ssi_clk delay on the sample of rxd. Default is + 0 and delay ranges from 0-255. diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 56d2cd3d92538..fa9a575f16e0f 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -146,6 +146,110 @@ extern "C" { #define SPI_LINES_OCTAL (3U << 16) /**< Octal lines */ #define SPI_LINES_MASK (0x3U << 16) /**< Mask for MISO lines in spi_operation_t */ +#define SPI_LINES_GET(_line_) \ + ((_line_) & SPI_LINES_MASK) + +/** @} */ + +/** + * @name SPI Instruction and Address transfer format + * @{ + * + * Some controllers support the enhanced SPI operations divided into multi + * phases - Instruction/Address/Data. + * The Instruction/Address transfer format will be either in Standard SPI mode + * or the SPI mode configured in CTRLR0 frame format. + * + * TT0: Instruction/Address in Standard SPI mode + * TT1: Instruction in Standard SPI mode, Address in the mode specified by + * CTRLR0 frame format + * TT2: Instruction/Address in the mode specified by CTRLR0 frame format field + * TT3: Dual Octal mode. Instruction/Address in octal mode, data is transferred + * on 16 data lines + * + * Supported only if @kconfig{CONFIG_SPI_EXTENDED_MODES} is enabled + */ + +#define SPI_TRANS_TYPE_SHIFT (18) +#define SPI_TRANS_TYPE_MASK (0x3U << SPI_TRANS_TYPE_SHIFT) +#define SPI_TRANS_TYPE_TT0 (0U << SPI_TRANS_TYPE_SHIFT) +#define SPI_TRANS_TYPE_TT1 (1U << SPI_TRANS_TYPE_SHIFT) +#define SPI_TRANS_TYPE_TT2 (2U << SPI_TRANS_TYPE_SHIFT) +#define SPI_TRANS_TYPE_TT3 (3U << SPI_TRANS_TYPE_SHIFT) +#define SPI_TRANS_TYPE_GET(_type_) \ + ((_type_) & SPI_TRANS_TYPE_MASK) +#define SPI_TRANS_TYPE_FIELD_GET(_type_) \ + (SPI_TRANS_TYPE_GET(_type_) >> SPI_TRANS_TYPE_SHIFT) + +/** @} */ + +/** + * @name SPI address length to be transmitted + * @{ + * + * Some controllers support the enhanced SPI operations divided into multi + * phases - Instruction/Address/Data. The address transfer begins only after + * this much bits are programmed into the FIFO. + * + * L0: No Address + * L4: 4 bit Address length + * L8: 8 bit Address length + * Ln: n bit Address length respectively + * + * Supported only if @kconfig{CONFIG_SPI_EXTENDED_MODES} is enabled + */ + +#define SPI_ADDR_L_SHIFT (20) +#define SPI_ADDR_L_MASK (0xFU << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L0 (0U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L4 (1U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L8 (2U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L12 (3U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L16 (4U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L20 (5U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L24 (6U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L28 (7U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L32 (8U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L36 (9U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L40 (10U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L44 (11U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L48 (12U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L52 (13U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L56 (14U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L60 (15U << SPI_ADDR_L_SHIFT) +#define SPI_ADDR_L_GET(_length_) \ + ((_length_) & SPI_ADDR_L_MASK) +#define SPI_ADDR_L_FIELD_GET(_length_) \ + (SPI_ADDR_L_GET(_length_) >> SPI_ADDR_L_SHIFT) + +/** @} */ + +/** + * @name SPI Instruction and Address transfer format. + * @{ + * + * Some controllers support the enhanced SPI operations divided into multi + * phases - Instruction/Address/Data. This specifies the instruction length + * in bits. + * + * L0: No Instruction + * L4: 4 bit Instruction length + * L8: 8 bit Instruction length + * L16: 16 bit Instruction length + * + * Supported only if @kconfig{CONFIG_SPI_EXTENDED_MODES} is enabled + */ + +#define SPI_INST_L_SHIFT (24) +#define SPI_INST_L_MASK (0x3U << SPI_INST_L_SHIFT) +#define SPI_INST_L0 (0U << SPI_INST_L_SHIFT) +#define SPI_INST_L4 (1U << SPI_INST_L_SHIFT) +#define SPI_INST_L8 (2U << SPI_INST_L_SHIFT) +#define SPI_INST_L12 (3U << SPI_INST_L_SHIFT) +#define SPI_INST_L_GET(_length_) \ + ((_length_) & SPI_INST_L_MASK) +#define SPI_INST_L_FIELD_GET(_length_) \ + (SPI_INST_L_GET(_length_) >> SPI_INST_L_SHIFT) /** @} */ @@ -319,7 +423,10 @@ struct spi_config { * If @kconfig{CONFIG_SPI_EXTENDED_MODES} is enabled: * * - 16..17: MISO lines (Single/Dual/Quad/Octal). - * - 18..31: Reserved for future use. + * - 18..19: Transfer Type (Address and instruction transfer format). + * - 20..23: Length of Address to be transmitted. + * - 24..25: Enhanced SPI mode instruction length in bits + * - 26..31: Reserved for future use. */ spi_operation_t operation; /** @brief Slave number from 0 to host controller slave limit. */