diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts index b8f4d264812..104c0170740 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -212,7 +212,6 @@ clock-frequency = <4000000>; lines = <4>; chip-select = <0>; - port-sel = <0>; /* Shared SPI */ pinctrl-0 = < &shd_cs0_n_gpio055 &shd_clk_gpio056 diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 337b192fcea..b889c0213d5 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -28,7 +28,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_PSOC6 spi_psoc6.c) zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_FIU spi_npcx_fiu.c) zephyr_library_sources_ifdef(CONFIG_SPI_BITBANG spi_bitbang.c) zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_LDMA spi_xec_qmspi_ldma.c) -zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_FULL_DUPLEX spi_xec_qmspi_full_duplex.c) zephyr_library_sources_ifdef(CONFIG_SPI_GD32 spi_gd32.c) zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_QSPI spi_mchp_mss_qspi.c) zephyr_library_sources_ifdef(CONFIG_SPI_PL022 spi_pl022.c) diff --git a/drivers/spi/Kconfig.xec_qmspi b/drivers/spi/Kconfig.xec_qmspi index 97528634ee8..08c059e41b7 100644 --- a/drivers/spi/Kconfig.xec_qmspi +++ b/drivers/spi/Kconfig.xec_qmspi @@ -17,11 +17,3 @@ config SPI_XEC_QMSPI_LDMA depends on DT_HAS_MICROCHIP_XEC_QMSPI_LDMA_ENABLED help Enable support for Microchip MEC17xx QMSPI with local DMA driver. - -config SPI_XEC_QMSPI_FULL_DUPLEX - bool "Microchip XEC MEC17xx QMSPI Full Duplex driver" - default y - depends on DT_HAS_MICROCHIP_XEC_QMSPI_FULL_DUPLEX_ENABLED - help - Enable support for Microchip MEC17xx QMSPI full duplex driver - to work with Zephyr NOR driver diff --git a/drivers/spi/spi_xec_qmspi_full_duplex.c b/drivers/spi/spi_xec_qmspi_full_duplex.c deleted file mode 100644 index 5beaba95dc0..00000000000 --- a/drivers/spi/spi_xec_qmspi_full_duplex.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright (c) 2022 Microchip Technology Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT microchip_xec_qmspi_full_duplex - -#include -LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "spi_context.h" -#include "spi_xec_qmspi_full_duplex.h" - -#if XEC_QSPI_TX_FIFO_SIZE < XEC_QSPI_RX_FIFO_SIZE -#define XEC_QSPI_CHUNK_SIZE XEC_QSPI_TX_FIFO_SIZE -#else -#define XEC_QSPI_CHUNK_SIZE XEC_QSPI_RX_FIFO_SIZE -#endif - -/* spin loops waiting for HW to clear soft reset bit */ -#define XEC_QSPI_SRST_LOOPS 16 - -/* microseconds for busy wait and total wait interval */ -#define XEC_QSPI_WAIT_INTERVAL 8 -#define XEC_QSPI_WAIT_COUNT 64 -#define XEC_QSPI_WAIT_FULL_FIFO 1024 - -/* 3 Tap Regs - Tap, Tap Ctrl, Tap Adjust */ -#define TAP_REGS_MAX 3 - -#define CLOCK_DIV_0_VALUE 0x10000 - -/* - * Maximum number of units to generate clocks with data lines - * tri-stated depends upon bus width. Maximum bus width is 4. - */ -#define XEC_QSPI_MAX_TSCLK_UNITS (MCHP_QMSPI_C_MAX_UNITS / 4) - -#define XEC_QSPI_HALF_DUPLEX 0 -#define XEC_QSPI_FULL_DUPLEX 1 -#define XEC_QSPI_DUAL 2 -#define XEC_QSPI_QUAD 4 - -#define XEC_QSPI_STS_ERRORS (BIT(XEC_QSPI_STS_TXB_ERR_POS) | \ - BIT(XEC_QSPI_STS_RXB_ERR_POS) | \ - BIT(XEC_QSPI_STS_PROG_ERR_POS) | \ - BIT(XEC_QSPI_STS_LDMA_RX_ERR_POS) | \ - BIT(XEC_QSPI_STS_LDMA_TX_ERR_POS)) - -#define XEC_QSPI_IEN_DONE_ERR (BIT(XEC_QSPI_IEN_XFR_DONE_POS) | \ - BIT(XEC_QSPI_IEN_TXB_ERR_POS) | \ - BIT(XEC_QSPI_IEN_RXB_ERR_POS) | \ - BIT(XEC_QSPI_IEN_PROG_ERR_POS) | \ - BIT(XEC_QSPI_IEN_LDMA_RX_ERR_POS) | \ - BIT(XEC_QSPI_IEN_LDMA_TX_ERR_POS)); - -/* Device constant configuration parameters */ -struct spi_xec_qspi_config { - struct qmspi_regs *regs; - uint32_t cs1_freq; - uint32_t cs_timing; - uint16_t taps_adj; - uint8_t girq; - uint8_t girq_pos; - uint8_t girq_nvic_aggr; - uint8_t girq_nvic_direct; - uint8_t irq_pri; - uint8_t pcr_idx; - uint8_t pcr_pos; - uint8_t chip_sel; - uint8_t width; /* 0(half) 1(single), 2(dual), 4(quad) */ - uint8_t unused[2]; - const struct pinctrl_dev_config *pcfg; -}; - -#define XEC_QMSPI_XFR_FLAG_TX BIT(0) -#define XEC_QMSPI_XFR_FLAG_STARTED BIT(1) - -/* Device run time data */ -struct spi_xec_qspi_data { - struct spi_context ctx; - uint32_t qstatus; - uint8_t np; /* number of data pins: 1, 2, or 4 */ -}; - -static int xec_qspi_spin_yield(int *counter, int max_count) -{ - *counter = *counter + 1; - - if (*counter > max_count) { - return -ETIMEDOUT; - } - - k_busy_wait(XEC_QSPI_WAIT_INTERVAL); - - return 0; -} - -/* - * reset QMSPI controller with save/restore of timing registers. - * Some QMSPI timing register may be modified by the Boot-ROM OTP - * values. - */ -static void xec_qspi_reset(struct qmspi_regs *regs) -{ - uint32_t taps[TAP_REGS_MAX]; - uint32_t malt1; - uint32_t cstm; - uint32_t mode; - uint32_t cnt = XEC_QSPI_SRST_LOOPS; - - taps[0] = regs->TM_TAPS; - taps[1] = regs->TM_TAPS_ADJ; - taps[2] = regs->TM_TAPS_CTRL; - malt1 = regs->MODE_ALT1; - cstm = regs->CSTM; - mode = regs->MODE; - regs->MODE = MCHP_QMSPI_M_SRST; - while (regs->MODE & MCHP_QMSPI_M_SRST) { - if (cnt == 0) { - break; - } - cnt--; - } - regs->MODE = 0; - regs->MODE = mode & ~MCHP_QMSPI_M_ACTIVATE; - regs->CSTM = cstm; - regs->MODE_ALT1 = malt1; - regs->TM_TAPS = taps[0]; - regs->TM_TAPS_ADJ = taps[1]; - regs->TM_TAPS_CTRL = taps[2]; -} - -static uint32_t qspi_source_clock_freq(void) -{ - struct pcr_regs const *pcr = - (struct pcr_regs *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0)); - - if (pcr->TURBO_CLK & MCHP_PCR_TURBO_CLK_96M) { - return MEC172X_QSPI_TURBO_SRC_CLOCK_HZ; - } - return MEC172X_QSPI_SRC_CLOCK_HZ; -} - -/* - * Calculate QMSPI frequency divider register field value based upon - * the configured QMSPI input frequency: 48 or 96 MHz. - * The hardware divider is encoded as: - * 0 is divide by full divider range: 256 or 65536. - * Non-zero is divide by that value: 1 to 256 or 655356. - */ -static uint32_t qspi_encoded_fdiv(uint32_t freq_hz) -{ - uint32_t fdiv = 1; - uint32_t src_clk = qspi_source_clock_freq(); - - if (freq_hz < (src_clk / 256u)) { - fdiv = 0; /* HW fdiv = 0 is divide by 256 */ - } else if (freq_hz < src_clk) { - /* truncated integer division may result in lower freq. */ - fdiv = src_clk / freq_hz; - } - - return fdiv; -} - -/* Program QMSPI frequency divider field in mode register */ -static void qspi_set_frequency(struct qmspi_regs *regs, uint32_t freq_hz) -{ - uint32_t fdiv, mode; - - fdiv = qspi_encoded_fdiv(freq_hz); - mode = regs->MODE & ~(XEC_QSPI_M_CLK_DIV_MASK); - mode |= ((fdiv << XEC_QSPI_M_CLK_DIV_POS) & XEC_QSPI_M_CLK_DIV_MASK); - regs->MODE = mode; -} - -static uint32_t qspi_get_frequency(struct qmspi_regs *regs) -{ - uint32_t src_clk = qspi_source_clock_freq(); - uint32_t fdiv = (regs->MODE & XEC_QSPI_M_CLK_DIV_MASK) - >> XEC_QSPI_M_CLK_DIV_POS; - - if (fdiv == 0) { - fdiv = CLOCK_DIV_0_VALUE; - } - - return (src_clk / fdiv); -} - -/* - * SPI signalling mode: CPOL and CPHA - * CPOL = 0 is clock idle state is low, 1 is clock idle state is high - * CPHA = 0 Transmitter changes data on trailing of preceding clock cycle. - * Receiver samples data on leading edge of clock cyle. - * 1 Transmitter changes data on leading edge of current clock cycle. - * Receiver samples data on the trailing edge of clock cycle. - * SPI Mode nomenclature: - * Mode CPOL CPHA - * 0 0 0 - * 1 0 1 - * 2 1 0 - * 3 1 1 - * QMSPI has three controls, CPOL, CPHA for output and CPHA for input. - * SPI frequency < 48MHz - * Mode 0: CPOL=0 CHPA=0 (CHPA_MISO=0 and CHPA_MOSI=0) - * Mode 3: CPOL=1 CHPA=1 (CHPA_MISO=1 and CHPA_MOSI=1) - * Data sheet recommends when QMSPI set at >= 48MHz, sample and change data - * on the same edge. - * Mode 0: CPOL=0 CPHA=0 (CHPA_MISO=1 and CHPA_MOSI=0) - * Mode 3: CPOL=1 CPHA=1 (CHPA_MISO=0 and CHPA_MOSI=1) - * - * smode_tbl and smode48_tbl has the byte values for Mode 0, 1, 2, 3 - * - * Byte values correspond to bits 8. 9. 10 in QMSPI Mode Register - * Bit 8 - CPOL - * Bit 9 - CHPA MOSI - * Bit 10 - CHPA MISO - */ -const uint8_t smode_tbl[4] = { - 0x00u, 0x06u, 0x01u, 0x07u -}; - -const uint8_t smode48_tbl[4] = { - 0x04u, 0x02u, 0x05u, 0x03u -}; - -static void qspi_set_signalling_mode(struct qmspi_regs *regs, uint32_t smode) -{ - const uint8_t *ptbl; - uint32_t m; - - ptbl = smode_tbl; - if (qspi_get_frequency(regs) >= MHZ(48)) { - ptbl = smode48_tbl; - } - - m = (uint32_t)ptbl[smode & GENMASK(1, 0)]; - regs->MODE = (regs->MODE & ~(XEC_QSPI_M_CP_MSK)) | - (m << XEC_QSPI_M_CPOL_POS); -} - -static uint8_t npins_from_spi_config(const struct spi_config *config) -{ - uint8_t lines = 1u; - - if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES)) { - switch (config->operation & SPI_LINES_MASK) { - case SPI_LINES_DUAL: - lines = 2u; - break; - case SPI_LINES_QUAD: - lines = 4u; - break; - default: - lines = 1u; - break; - } - } - - return lines; -} - -/* - * Configure QSPI. - * NOTE: QSPI Port 0 has two chip selects available. Ports 1 & 2 - * support only CS0#. - */ -static int qspi_configure(const struct device *dev, - const struct spi_config *spi_conf) -{ - const struct spi_xec_qspi_config * const cfg = dev->config; - struct spi_xec_qspi_data * const qdata = dev->data; - struct qmspi_regs * const regs = cfg->regs; - struct spi_context *ctx = &qdata->ctx; - uint32_t smode; - - if (spi_context_configured(ctx, spi_conf)) { - return 0; - } - - if (spi_conf->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE - | SPI_MODE_LOOP)) { - return -ENOTSUP; - } - - if ((IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && - ((spi_conf->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE))) { - LOG_ERR("Single(full-duplex) only"); - return -EINVAL; - } - - if (spi_conf->operation & SPI_CS_ACTIVE_HIGH) { - LOG_ERR("CS active high not supported"); - return -ENOTSUP; - } - - if (SPI_WORD_SIZE_GET(spi_conf->operation) != 8) { - LOG_ERR("Word size != 8 not supported"); - return -ENOTSUP; - } - - smode = SPI_LINES_SINGLE; - qdata->np = npins_from_spi_config(spi_conf); - regs->CTRL = smode; - - /* Use the requested or next highest possible frequency */ - qspi_set_frequency(regs, spi_conf->frequency); - - smode = 0; - if ((spi_conf->operation & SPI_MODE_CPHA) != 0U) { - smode |= (BIT(0)); - } - - if ((spi_conf->operation & SPI_MODE_CPOL) != 0U) { - smode |= (BIT(1)); - } - - qspi_set_signalling_mode(regs, smode); - - /* chip select */ - smode = regs->MODE & ~(XEC_QSPI_M_CS_SEL_MSK); - if (cfg->chip_sel == 0) { - smode |= XEC_QSPI_M_CS0_SEL; - } else { - smode |= XEC_QSPI_M_CS1_SEL; - } - regs->MODE = smode; - - /* chip select timing */ - regs->CSTM = cfg->cs_timing; - - regs->TM_TAPS_ADJ = cfg->taps_adj; - /* CS1 alternate mode (frequency) */ - regs->MODE_ALT1 = 0; - if (cfg->cs1_freq) { - uint32_t fdiv = qspi_encoded_fdiv(cfg->cs1_freq); - - regs->MODE_ALT1 = (fdiv << XEC_QSPI_MALT1_CLK_DIV_POS) & - XEC_QSPI_MALT1_CLK_DIV_MSK; - regs->MODE_ALT1 |= BIT(XEC_QSPI_MALT1_EN_POS); - } - - ctx->config = spi_conf; - - regs->MODE |= BIT(XEC_QSPI_M_ACTV_POS); - - return 0; -} - -static uint32_t encode_npins(uint8_t npins) -{ - uint32_t encoding = XEC_QSPI_C_IFC_1X; - - if (npins == 4) { - encoding = XEC_QSPI_C_IFC_4X; - } else if (npins == 2) { - encoding = XEC_QSPI_C_IFC_2X; - } else { - encoding = XEC_QSPI_C_IFC_1X; - } - - return encoding; -} - -/* Allocate QMSPI HW descriptor registers to process the given number of bytes - * or until all descriptors are allocated. Returns the number of remaining - * bytes not in allocation. Updates the word pointed to by ndescr with the - * number of descriptors allocated. Descriptor allocation always begins with - * descriptor 0. Descriptor QMSPI unit size, number of units, and next - * descriptor fields are programmed other fields in descr_base are preserved. - */ -static size_t descr_alloc(struct qmspi_regs * const regs, size_t nbytes, - uint32_t descr_base, uint32_t *ndescr) -{ - size_t nb = nbytes; - uint32_t idx = 0u; - uint32_t descr = 0u; - - descr_base &= ~(XEC_QSPI_C_Q_XFR_UNITS_MSK | XEC_QSPI_C_Q_NUNITS_MSK | - XEC_QSPI_C_FN_DESCR_MSK); - - while (nb && (idx < 16)) { - if (nb <= XEC_QSPI_C_Q_NUNITS_MAX) { - descr = nb; - descr <<= XEC_QSPI_C_Q_NUNITS_POS; - descr |= XEC_QSPI_C_Q_XFR_UNITS_1B; - nb = 0u; - } else { - descr = (nb >> 4); - nb -= (descr << 4); - descr <<= XEC_QSPI_C_Q_NUNITS_POS; - descr |= XEC_QSPI_C_Q_XFR_UNITS_16B; - } - - descr |= (XEC_QSPI_C_IFC_1X | XEC_QSPI_C_TX_EN_DATA | - BIT(XEC_QSPI_C_RX_EN_POS)); - descr |= XEC_QSPI_C_FN_DESCR((idx + 1u)); - - regs->DESCR[idx++] = descr_base | descr; - } - - if (idx) { - regs->DESCR[idx - 1u] |= BIT(XEC_QSPI_D_DESCR_LAST_POS); - } - - if (ndescr) { - *ndescr = idx; - } - - return nb; -} - -/* Polling full-duplex transfer using QMSPI descriptors and FIFO's. - * Allocate hardware descriptors for maximum total transfer size. - * Descriptors configured for both transmit and receive. - * If TX context has no data, transmit 0 bytes. - * If RX context has no buffer, throw away received bytes. - * If user set SPI_HOLD_ON_CS flag configure to not de-assert chip select - * when the last descriptor is completed. When transfer is completed without - * error mark context complete. - */ -static int xec_qspi_fd_descr(const struct device *dev, - const struct spi_config *spi_conf, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) -{ - const struct spi_xec_qspi_config *cfg = dev->config; - struct spi_xec_qspi_data * const qdata = dev->data; - struct qmspi_regs * const regs = cfg->regs; - struct spi_context *ctx = &qdata->ctx; - uint32_t descr_base, nd; - size_t len, ntx, nrx, rem, xfr_len; - uint8_t txb, rxb; - bool close = true; - - xfr_len = MAX(spi_context_total_tx_len(ctx), spi_context_total_rx_len(ctx)); - if (!xfr_len) { - return 0; - } - - regs->CTRL = 0; - regs->EXE = BIT(XEC_QSPI_EXE_CLR_FIFOS_POS); - regs->STS |= regs->STS; - regs->CTRL = BIT(XEC_QSPI_C_DESCR_MODE_EN_POS); - - descr_base = encode_npins(qdata->np); - descr_base |= (XEC_QSPI_C_TX_EN_DATA | BIT(XEC_QSPI_C_RX_EN_POS) | - BIT(XEC_QSPI_C_CLOSE_POS)); - - if (spi_conf->operation & SPI_HOLD_ON_CS) { - close = false; - } - - len = xfr_len; - while (len) { - nd = 0u; - rem = descr_alloc(regs, len, descr_base, &nd); - - __ASSERT_NO_MSG(nd != 0); - __ASSERT_NO_MSG(rem < len); - - if ((rem == 0) && close) { - regs->DESCR[nd - 1u] |= BIT(XEC_QSPI_C_CLOSE_POS); - } - - /* NOTE: start with TX FIFO empty causes read-only TX stall - * status to be set. - */ - regs->EXE = BIT(XEC_QSPI_EXE_START_POS); - - ntx = len - rem; - nrx = ntx; - while (ntx || nrx) { - if (regs->STS & XEC_QSPI_STS_ERRORS) { - LOG_ERR("QMSPI errors(sts): 0x%08x\n", regs->STS); - return -EIO; - } - if (ntx && !(regs->STS & BIT(XEC_QSPI_STS_TXB_FULL_POS))) { - txb = 0u; - if (ctx->tx_buf) { - txb = *(uint8_t *)(ctx->tx_buf); - } - sys_write8(txb, (mem_addr_t)®s->TX_FIFO); - spi_context_update_tx(ctx, 1, 1); - ntx--; - } - if (nrx && !(regs->STS & BIT(XEC_QSPI_STS_RXB_EMPTY_POS))) { - rxb = sys_read8((mem_addr_t)®s->RX_FIFO); - if (ctx->rx_buf) { - *(uint8_t *)(ctx->rx_buf) = rxb; - } - spi_context_update_rx(ctx, 1, 1); - nrx--; - } - } - - len = rem; - } - - spi_context_complete(ctx, dev, 0); - - return 0; -} - -static int xec_qspi_xfr(const struct device *dev, - const struct spi_config *spi_conf, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - bool asynchronous) -{ - const struct spi_xec_qspi_config *cfg = dev->config; - struct spi_xec_qspi_data * const qdata = dev->data; - struct qmspi_regs * const regs = cfg->regs; - struct spi_context *ctx = &qdata->ctx; - int ret = 0; - - spi_context_lock(ctx, asynchronous, NULL, NULL, spi_conf); - - ret = qspi_configure(dev, spi_conf); - if (ret != 0) { - spi_context_release(ctx, ret); - return ret; - } - - spi_context_cs_control(&qdata->ctx, true); - spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); - - ret = xec_qspi_fd_descr(dev, spi_conf, tx_bufs, rx_bufs); - if (ret) { - regs->EXE = BIT(XEC_QSPI_EXE_STOP_POS); - spi_context_unlock_unconditionally(&qdata->ctx); - return ret; - } - - if (!(spi_conf->operation & SPI_HOLD_ON_CS)) { - spi_context_cs_control(ctx, false); - } - - /* Attempts to take semaphore with timeout. Descriptor transfer - * routine completes the context giving the semaphore. - */ - ret = spi_context_wait_for_completion(ctx); - /* gives semaphore */ - spi_context_release(ctx, ret); - - return ret; -} - -static int xec_qspi_transceive(const struct device *dev, - const struct spi_config *spi_conf, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) -{ - return xec_qspi_xfr(dev, spi_conf, tx_bufs, rx_bufs, false); -} - -#ifdef CONFIG_SPI_ASYNC -static int xec_qspi_transceive_async(const struct device *dev, - const struct spi_config *spi_conf, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - struct k_poll_signal *async) -{ - return -ENOTSUP; -} -#endif - -static int xec_qspi_release(const struct device *dev, - const struct spi_config *spi_conf) -{ - struct spi_xec_qspi_data * const qdata = dev->data; - const struct spi_xec_qspi_config *cfg = dev->config; - struct qmspi_regs * const regs = cfg->regs; - struct spi_context *ctx = &qdata->ctx; - int ret = 0; - int counter = 0; - - if (regs->STS & BIT(XEC_QSPI_STS_XFR_ACTIVE_POS)) { - /* Force CS# to de-assert on next unit boundary */ - regs->EXE = BIT(XEC_QSPI_EXE_STOP_POS); - while (regs->STS & BIT(XEC_QSPI_STS_XFR_ACTIVE_POS)) { - ret = xec_qspi_spin_yield(&counter, - XEC_QSPI_WAIT_COUNT); - if (ret != 0) { - break; - } - } - } - - spi_context_unlock_unconditionally(ctx); - - return ret; -} - -/* - * Called for each QMSPI controller instance - * Initialize QMSPI controller. - * Disable sleep control. - * Disable and clear interrupt status. - * Initialize SPI context. - * QMSPI will be fully configured and enabled when the transceive API - * is called. - */ -static int xec_qspi_init(const struct device *dev) -{ - const struct spi_xec_qspi_config *cfg = dev->config; - struct spi_xec_qspi_data * const qdata = dev->data; - struct qmspi_regs * const regs = cfg->regs; - int ret = 0; - - qdata->qstatus = 0; - qdata->np = cfg->width; - - z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0); - - ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); - if (ret != 0) { - LOG_ERR("QSPI pinctrl setup failed (%d)", ret); - return ret; - } - - xec_qspi_reset(regs); - - spi_context_unlock_unconditionally(&qdata->ctx); - - return 0; -} - -static const struct spi_driver_api spi_xec_qspi_driver_api = { - .transceive = xec_qspi_transceive, - .release = xec_qspi_release, -#ifdef CONFIG_SPI_ASYNC - .transceive_async = xec_qspi_transceive_async, -#endif -}; - -#define XEC_QSPI_CS_TIMING_VAL(a, b, c, d) (((a) & 0xFu) \ - | (((b) & 0xFu) << 8) \ - | (((c) & 0xFu) << 16) \ - | (((d) & 0xFu) << 24)) - -#define XEC_QSPI_TAPS_ADJ_VAL(a, b) (((a) & 0xffu) | (((b) & 0xffu) << 8)) - -#define XEC_QSPI_CS_TIMING(i) XEC_QSPI_CS_TIMING_VAL( \ - DT_INST_PROP_OR(i, dcsckon, 6), \ - DT_INST_PROP_OR(i, dckcsoff, 4), \ - DT_INST_PROP_OR(i, dldh, 6), \ - DT_INST_PROP_OR(i, dcsda, 6)) - -#define XEC_QSPI_TAPS_ADJ(i) XEC_QSPI_TAPS_ADJ_VAL( \ - DT_INST_PROP_OR(i, tctradj, 0), \ - DT_INST_PROP_OR(i, tsckadj, 0)) - -#define XEC_QSPI_GIRQ(i) \ - MCHP_XEC_ECIA_GIRQ(DT_INST_PROP_BY_IDX(i, girqs, 0)) - -#define XEC_QSPI_GIRQ_POS(i) \ - MCHP_XEC_ECIA_GIRQ_POS(DT_INST_PROP_BY_IDX(i, girqs, 0)) - -#define XEC_QSPI_NVIC_AGGR(i) \ - MCHP_XEC_ECIA_NVIC_AGGR(DT_INST_PROP_BY_IDX(i, girqs, 0)) - -#define XEC_QSPI_NVIC_DIRECT(i) \ - MCHP_XEC_ECIA_NVIC_DIRECT(DT_INST_PROP_BY_IDX(i, girqs, 0)) - -/* - * The instance number, i is not related to block ID's rather the - * order the DT tools process all DT files in a build. - */ -#define XEC_QSPI_DEVICE(i) \ - \ - PINCTRL_DT_INST_DEFINE(i); \ - \ - static struct spi_xec_qspi_data xec_qspi_data_##i = { \ - SPI_CONTEXT_INIT_LOCK(xec_qspi_data_##i, ctx), \ - SPI_CONTEXT_INIT_SYNC(xec_qspi_data_##i, ctx), \ - }; \ - static const struct spi_xec_qspi_config xec_qspi_config_##i = { \ - .regs = (struct qmspi_regs *) DT_INST_REG_ADDR(i), \ - .cs1_freq = DT_INST_PROP_OR(i, cs1_freq, 0), \ - .cs_timing = XEC_QSPI_CS_TIMING(i), \ - .taps_adj = XEC_QSPI_TAPS_ADJ(i), \ - .girq = XEC_QSPI_GIRQ(i), \ - .girq_pos = XEC_QSPI_GIRQ_POS(i), \ - .girq_nvic_aggr = XEC_QSPI_NVIC_AGGR(i), \ - .girq_nvic_direct = XEC_QSPI_NVIC_DIRECT(i), \ - .irq_pri = DT_INST_IRQ(i, priority), \ - .pcr_idx = DT_INST_PROP_BY_IDX(i, pcrs, 0), \ - .pcr_pos = DT_INST_PROP_BY_IDX(i, pcrs, 1), \ - .chip_sel = DT_INST_PROP_OR(i, chip_select, 0), \ - .width = DT_INST_PROP_OR(i, lines, 1), \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \ - }; \ - DEVICE_DT_INST_DEFINE(i, &xec_qspi_init, NULL, \ - &xec_qspi_data_##i, &xec_qspi_config_##i, \ - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ - &spi_xec_qspi_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(XEC_QSPI_DEVICE) diff --git a/drivers/spi/spi_xec_qmspi_full_duplex.h b/drivers/spi/spi_xec_qmspi_full_duplex.h deleted file mode 100644 index 3fa12818ab4..00000000000 --- a/drivers/spi/spi_xec_qmspi_full_duplex.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2022 Microchip Technology Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SPI_XEC_QMSPI_V2_H -#define _SPI_XEC_QMSPI_V2_H - -#define MEC152X_QSPI_SRC_CLOCK_HZ 48000000u -#define MEC172X_QSPI_SRC_CLOCK_HZ 48000000u -#define MEC172X_QSPI_TURBO_SRC_CLOCK_HZ 96000000u - -#define XEC_QSPI_TX_FIFO_SIZE 8 -#define XEC_QSPI_RX_FIFO_SIZE 8 - -#define XEC_QSPI_DESCR_MAX 16 - -/* mode register */ -#define XEC_QSPI_M_ACTV_POS 0 -#define XEC_QSPI_M_SRST_POS 1 -#define XEC_QSPI_M_RX_LDMA_EN_POS 3 -#define XEC_QSPI_M_TX_LDMA_EN_POS 4 -#define XEC_QSPI_M_CPOL_POS 8 -#define XEC_QSPI_M_CPHA_MOSI_POS 9 -#define XEC_QSPI_M_CPHA_MISO_POS 10 -#define XEC_QSPI_M_CP_MSK (0x7u << XEC_QSPI_M_CPOL_POS) -#define XEC_QSPI_M_CS_SEL_POS 12 -#define XEC_QSPI_M_CS_SEL_MSK (0x3u << XEC_QSPI_M_CS_SEL_POS) -#define XEC_QSPI_M_CS0_SEL 0 -#define XEC_QSPI_M_CS1_SEL (1u << XEC_QSPI_M_CS_SEL_POS) -#define XEC_QSPI_M_CLK_DIV_POS 16 -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_M_CLK_DIV_MASK 0xffff0000u -#else -#define XEC_QSPI_M_CLK_DIV_MASK 0xff000000u -#endif - -/* control register */ -#define XEC_QSPI_C_IFC_POS 0 -#define XEC_QSPI_C_IFC_MSK 0x3u -#define XEC_QSPI_C_IFC_1X 0 -#define XEC_QSPI_C_IFC_2X 0x1u -#define XEC_QSPI_C_IFC_4X 0x2u -#define XEC_QSPI_C_TX_EN_POS 2 -#define XEC_QSPI_C_TX_EN_MSK (0x3u << XEC_QSPI_C_TX_EN_POS) -#define XEC_QSPI_C_TX_EN_DATA (0x1u << XEC_QSPI_C_TX_EN_POS) -#define XEC_QSPI_C_TX_EN_ZEROS (0x2u << XEC_QSPI_C_TX_EN_POS) -#define XEC_QSPI_C_TX_EN_ONES (0x3u << XEC_QSPI_C_TX_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_POS 4 -#define XEC_QSPI_C_TX_DMA_EN_MSK (0x3u << XEC_QSPI_C_TX_DMA_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_1B (0x1u << XEC_QSPI_C_TX_DMA_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_2B (0x2u << XEC_QSPI_C_TX_DMA_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_4B (0x3u << XEC_QSPI_C_TX_DMA_EN_POS) -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_C_TX_DMA_EN_LDCH0 (0x1u << XEC_QSPI_C_TX_DMA_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_LDCH1 (0x2u << XEC_QSPI_C_TX_DMA_EN_POS) -#define XEC_QSPI_C_TX_DMA_EN_LDCH2 (0x3u << XEC_QSPI_C_TX_DMA_EN_POS) -#endif -#define XEC_QSPI_C_RX_EN_POS 6 -#define XEC_QSPI_C_RX_DMA_EN_POS 7 -#define XEC_QSPI_C_RX_DMA_EN_MSK (0x3u << XEC_QSPI_C_RX_DMA_EN_POS) -#define XEC_QSPI_C_RX_DMA_EN_1B (0x1u << XEC_QSPI_C_RX_DMA_EN_POS) -#define XEC_QSPI_C_RX_DMA_EN_2B (0x2u << XEC_QSPI_C_RX_DMA_EN_POS) -#define XEC_QSPI_C_RX_DMA_EN_4B (0x3u << XEC_QSPI_C_RX_DMA_EN_POS) -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_C_RX_DMA_EN_LDCH0 (0x1u << XEC_QSPI_C_RX_DMA_EN_POS) -#define XEC_QSPI_C_RX_DMA_EN_LDCH1 (0x2u << XEC_QSPI_C_RX_DMA_EN_POS) -#define XEC_QSPI_C_RX_DMA_EN_LDCH2 (0x3u << XEC_QSPI_C_RX_DMA_EN_POS) -#endif -#define XEC_QSPI_C_CLOSE_POS 9 -#define XEC_QSPI_C_Q_XFR_UNITS_POS 10 -#define XEC_QSPI_C_Q_XFR_UNITS_MSK (0x3u << XEC_QSPI_C_Q_XFR_UNITS_POS) -#define XEC_QSPI_C_Q_XFR_UNITS_BITS 0 -#define XEC_QSPI_C_Q_XFR_UNITS_1B (0x1u << XEC_QSPI_C_Q_XFR_UNITS_POS) -#define XEC_QSPI_C_Q_XFR_UNITS_4B (0x2u << XEC_QSPI_C_Q_XFR_UNITS_POS) -#define XEC_QSPI_C_Q_XFR_UNITS_16B (0x3u << XEC_QSPI_C_Q_XFR_UNITS_POS) -#define XEC_QSPI_C_FN_DESCR_POS 12 -#define XEC_QSPI_C_FN_DESCR_MSK (0xfu << XEC_QSPI_C_FN_DESCR_POS) -#define XEC_QSPI_C_FN_DESCR(n) \ - (((uint32_t)(n) & 0xfu) << XEC_QSPI_C_FN_DESCR_POS) -/* control register enable descriptor mode */ -#define XEC_QSPI_C_DESCR_MODE_EN_POS 16 -/* descriptor specifies last descriptor to be processed */ -#define XEC_QSPI_D_DESCR_LAST_POS 16 -#define XEC_QSPI_C_Q_NUNITS_POS 17 -#define XEC_QSPI_C_Q_NUNITS_MAX 0x7fffu -#define XEC_QSPI_C_Q_NUNITS_MSK (0x7fffu << XEC_QSPI_C_Q_NUNITS_POS) -#define XEC_QSPI_C_NUNITS(n) \ - (((uint32_t)(n) & 0x7fffu) << XEC_QSPI_C_Q_NUNITS_POS) - -/* execute register (WO). Set one bit at a time! */ -#define XEC_QSPI_EXE_START_POS 0 -#define XEC_QSPI_EXE_STOP_POS 1 -#define XEC_QSPI_EXE_CLR_FIFOS_POS 2 - -/* status register */ -#define XEC_QSPI_STS_MSK 0x0f01ff7fu -#define XEC_QSPI_STS_MSK_RW1C 0x0000cc1fu -#define XEC_QSPI_STS_XFR_DONE_POS 0 -#define XEC_QSPI_STS_DMA_DONE_POS 1 -#define XEC_QSPI_STS_TXB_ERR_POS 2 -#define XEC_QSPI_STS_RXB_ERR_POS 3 -#define XEC_QSPI_STS_PROG_ERR_POS 4 -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_STS_LDMA_RX_ERR_POS 5 -#define XEC_QSPI_STS_LDMA_TX_ERR_POS 6 -#endif -#define XEC_QSPI_STS_TXB_FULL_POS 8 -#define XEC_QSPI_STS_TXB_EMPTY_POS 9 -#define XEC_QSPI_STS_TXB_REQ_POS 10 -#define XEC_QSPI_STS_TXB_STALL_POS 11 -#define XEC_QSPI_STS_RXB_FULL_POS 12 -#define XEC_QSPI_STS_RXB_EMPTY_POS 13 -#define XEC_QSPI_STS_RXB_REQ_POS 14 -#define XEC_QSPI_STS_RXB_STALL_POS 15 -#define XEC_QSPI_STS_XFR_ACTIVE_POS 16 -#define XEC_QSPI_STS_CURR_DESCR_POS 24 -#define XEC_QSPI_STS_CURR_DESCR_MSK (0xfu << XEC_QSPI_STS_CURR_DESCR_POS) - -#define XEC_QSPI_STS_ALL_ERR (BIT(XEC_QSPI_STS_TXB_ERR_POS) | \ - BIT(XEC_QSPI_STS_RXB_ERR_POS) | \ - BIT(XEC_QSPI_STS_PROG_ERR_POS)) - -/* buffer count status (RO) */ -#define XEC_QSPI_BCNT_STS_TX_POS 0 -#define XEC_QSPI_BCNT_STS_TX_MSK 0xffffu -#define XEC_QSPI_BCNT_STS_RX_POS 16 -#define XEC_QSPI_BCNT_STS_RX_MSK (0xffffu << XEC_QSPI_BCNT_STS_RX_POS) - -/* interrupt enable */ -#define XEC_QSPI_IEN_XFR_DONE_POS 0 -#define XEC_QSPI_IEN_DMA_DONE_POS 1 -#define XEC_QSPI_IEN_TXB_ERR_POS 2 -#define XEC_QSPI_IEN_RXB_ERR_POS 3 -#define XEC_QSPI_IEN_PROG_ERR_POS 4 -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_IEN_LDMA_RX_ERR_POS 5 -#define XEC_QSPI_IEN_LDMA_TX_ERR_POS 6 -#endif -#define XEC_QSPI_IEN_TXB_FULL_POS 8 -#define XEC_QSPI_IEN_TXB_EMPTY_POS 9 -#define XEC_QSPI_IEN_TXB_REQ_POS 10 -#define XEC_QSPI_IEN_RXB_FULL_POS 12 -#define XEC_QSPI_IEN_RXB_EMPTY_POS 13 -#define XEC_QSPI_IEN_RXB_REQ_POS 14 - -/* chip select timing */ -#define XEC_QSPI_CSTM_DLY_CS_TO_START_POS 0 -#define XEC_QSPI_CSTM_DLY_CS_TO_START_MSK 0xfu -#define XEC_QSPI_CSTM_DLY_CLK_OFF_TO_CS_OFF_POS 8 -#define XEC_QSPI_CSTM_DLY_CLK_OFF_TO_CS_OFF_MSK 0xf00u -#define XEC_QSPI_CSTM_DLY_LAST_DATA_HOLD_POS 16 -#define XEC_QSPI_CSTM_DLY_LAST_DATA_HOLD_MSK 0xf0000u -#define XEC_QSPI_CSTM_DLY_CS_OFF_TO_CS_ON_POS 24 -#define XEC_QSPI_CSTM_DLY_CS_OFF_TO_CS_ON_MSK 0xff000000u - -#ifdef CONFIG_SOC_SERIES_MEC172X -#define XEC_QSPI_MALT1_EN_POS 0 -#define XEC_QSPI_MALT1_CLK_DIV_POS 16 -#define XEC_QSPI_MALT1_CLK_DIV_MSK 0xffff0000u - -#define XEC_QSPI_LDCH_CTRL_EN_POS 0 -#define XEC_QSPI_LDCH_CTRL_RESTART_EN_POS 1 -#define XEC_QSPI_LDCH_CTRL_RESTART_ADDR_EN_POS 2 -#define XEC_QSPI_LDCH_CTRL_OVRLEN_POS 3 -#define XEC_QSPI_LDCH_CTRL_ACCSZ_POS 4 -#define XEC_QSPI_LDCH_CTRL_ACCSZ_MSK 0x30u -#define XEC_QSPI_LDCH_CTRL_ACCSZ_1B 0u -#define XEC_QSPI_LDCH_CTRL_ACCSZ_2B 1u -#define XEC_QSPI_LDCH_CTRL_ACCSZ_4B 2u -#define XEC_QSPI_LDCH_CTRL_INCR_ADDR_POS 6 - -struct qspi_ldma_chan { - volatile uint32_t ldctrl; - volatile uint32_t mstart; - volatile uint32_t nbytes; - uint32_t rsvd[1]; -}; -#endif /* CONFIG_SOC_SERIES_MEC172X */ - -#endif /* _SPI_XEC_QMSPI_V2_H */ diff --git a/drivers/spi/spi_xec_qmspi_ldma.c b/drivers/spi/spi_xec_qmspi_ldma.c index a58b81235f3..1b365c599ab 100644 --- a/drivers/spi/spi_xec_qmspi_ldma.c +++ b/drivers/spi/spi_xec_qmspi_ldma.c @@ -6,28 +6,35 @@ #define DT_DRV_COMPAT microchip_xec_qmspi_ldma -#include -LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); - #include +#include + #include +#include #include #include #include #include #include +#include #include +#include +#include #include #include -#include -#include +#include +LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" -/* #define XEC_QMSPI_DEBUG */ -#ifdef XEC_QMSPI_DEBUG -#include -#endif +/* #define MCHP_XEC_QMSPI_DEBUG 1 */ + +/* MEC172x QMSPI controller SPI Mode 3 signalling has an anomaly where + * received data is shifted off the input line(s) improperly. Received + * data bytes will be left shifted by 1. Work-around for SPI Mode 3 is + * to sample input line(s) on same edge as output data is ready. + */ +#define XEC_QMSPI_SPI_MODE_3_ANOMALY 1 /* common clock control device node for all Microchip XEC chips */ #define MCHP_XEC_CLOCK_CONTROL_NODE DT_NODELABEL(pcr) @@ -38,7 +45,9 @@ LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); /* microseconds for busy wait and total wait interval */ #define XEC_QMSPI_WAIT_INTERVAL 8 #define XEC_QMSPI_WAIT_COUNT 64 -#define XEC_QMSPI_WAIT_FULL_FIFO 1024 + +/* QSPI transfer and DMA done */ +#define XEC_QSPI_HW_XFR_DMA_DONE (MCHP_QMSPI_STS_DONE | MCHP_QMSPI_STS_DMA_DONE) /* QSPI hardware error status * Misprogrammed control or descriptors (software error) @@ -55,20 +64,14 @@ LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); #define XEC_QSPI_HW_ERRORS_ALL (XEC_QSPI_HW_ERRORS | \ XEC_QSPI_HW_ERRORS_LDMA) -/* - * Maximum number of units to generate clocks with data lines - * tri-stated depends upon bus width. Maximum bus width is 4. - */ -#define XEC_QSPI_MAX_TSCLK_UNITS (MCHP_QMSPI_C_MAX_UNITS / 4) - -#define XEC_QMSPI_HALF_DUPLEX 0 -#define XEC_QMSPI_FULL_DUPLEX 1 -#define XEC_QMSPI_DUAL 2 -#define XEC_QMSPI_QUAD 4 +#define XEC_QSPI_TIMEOUT_US (100 * 1000) /* 100 ms */ /* Device constant configuration parameters */ struct spi_qmspi_config { struct qmspi_regs *regs; + const struct device *clk_dev; + struct mchp_xec_pcr_clk_ctrl clksrc; + uint32_t clock_freq; uint32_t cs1_freq; uint32_t cs_timing; uint16_t taps_adj; @@ -77,43 +80,40 @@ struct spi_qmspi_config { uint8_t girq_nvic_aggr; uint8_t girq_nvic_direct; uint8_t irq_pri; - uint8_t pcr_idx; - uint8_t pcr_pos; - uint8_t port_sel; uint8_t chip_sel; uint8_t width; /* 0(half) 1(single), 2(dual), 4(quad) */ - uint8_t unused[2]; + uint8_t unused[1]; const struct pinctrl_dev_config *pcfg; void (*irq_config_func)(void); }; #define XEC_QMSPI_XFR_FLAG_TX BIT(0) -#define XEC_QMSPI_XFR_FLAG_STARTED BIT(1) +#define XEC_QMSPI_XFR_FLAG_RX BIT(1) /* Device run time data */ struct spi_qmspi_data { struct spi_context ctx; uint32_t base_freq_hz; + uint32_t spi_freq_hz; uint32_t qstatus; uint8_t np; /* number of data pins: 1, 2, or 4 */ - uint8_t *pd; - uint32_t dlen; - uint32_t consumed; #ifdef CONFIG_SPI_ASYNC - uint16_t xfr_flags; - uint8_t ldma_chan; - uint8_t in_isr; + spi_callback_t cb; + void *userdata; size_t xfr_len; #endif -}; + uint32_t tempbuf[2]; +#ifdef MCHP_XEC_QMSPI_DEBUG + uint32_t bufcnt_status; + uint32_t rx_ldma_ctrl0; + uint32_t tx_ldma_ctrl0; + uint32_t qunits; + uint32_t qxfru; + uint32_t xfrlen; -struct xec_qmspi_pin { - const struct device *dev; - uint8_t pin; - uint32_t attrib; +#endif }; - static int xec_qmspi_spin_yield(int *counter, int max_count) { *counter = *counter + 1; @@ -182,21 +182,32 @@ static uint32_t qmspi_encoded_fdiv(const struct device *dev, uint32_t freq_hz) * 0 = divide by 0x10000 * 1 to 0xffff = divide by this value. */ -static int qmspi_set_frequency(struct qmspi_regs *regs, uint32_t freq_hz) +static int qmspi_set_frequency(struct spi_qmspi_data *qdata, struct qmspi_regs *regs, + uint32_t freq_hz) { - clock_control_subsys_t clkss = - (clock_control_subsys_t)(MCHP_XEC_PCR_CLK_PERIPH_FAST); uint32_t clk = MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ; - uint32_t fdiv = 0u; + uint32_t fdiv = 0u; /* maximum divider */ - if (!clock_control_get_rate(DEVICE_DT_GET(MCHP_XEC_CLOCK_CONTROL_NODE), - (clock_control_subsys_t)clkss, &clk)) { - fdiv = clk / freq_hz; + if (qdata->base_freq_hz) { + clk = qdata->base_freq_hz; + } + + if (freq_hz) { + fdiv = 1u; + if (freq_hz < clk) { + fdiv = clk / freq_hz; + } } regs->MODE = ((regs->MODE & ~(MCHP_QMSPI_M_FDIV_MASK)) | ((fdiv << MCHP_QMSPI_M_FDIV_POS) & MCHP_QMSPI_M_FDIV_MASK)); + if (!fdiv) { + fdiv = 0x10000u; + } + + qdata->spi_freq_hz = clk / fdiv; + return 0; } @@ -221,24 +232,32 @@ static int qmspi_set_frequency(struct qmspi_regs *regs, uint32_t freq_hz) * SPI frequency == 48MHz sample and change data on same edge. * Mode 0: CPOL=0 CHPA=0 (CHPA_MISO=1 and CHPA_MOSI=0) * Mode 3: CPOL=1 CHPA=1 (CHPA_MISO=0 and CHPA_MOSI=1) + * + * There is an anomaly in MEC172x for SPI signalling mode 3. We must + * set CHPA_MISO=0 for SPI Mode 3 at all frequencies. */ const uint8_t smode_tbl[4] = { - 0x00u, 0x06u, 0x01u, 0x07u + 0x00u, 0x06u, 0x01u, +#ifdef XEC_QMSPI_SPI_MODE_3_ANOMALY + 0x03u, /* CPOL=1, CPHA_MOSI=1, CPHA_MISO=0 */ +#else + 0x07u, /* CPOL=1, CPHA_MOSI=1, CPHA_MISO=1 */ +#endif }; const uint8_t smode48_tbl[4] = { 0x04u, 0x02u, 0x05u, 0x03u }; -static void qmspi_set_signalling_mode(struct qmspi_regs *regs, uint32_t smode) +static void qmspi_set_signalling_mode(struct spi_qmspi_data *qdata, + struct qmspi_regs *regs, uint32_t smode) { const uint8_t *ptbl; uint32_t m; ptbl = smode_tbl; - if (((regs->MODE >> MCHP_QMSPI_M_FDIV_POS) & - MCHP_QMSPI_M_FDIV_MASK0) == 1) { + if (qdata->spi_freq_hz >= MHZ(48)) { ptbl = smode48_tbl; } @@ -247,6 +266,7 @@ static void qmspi_set_signalling_mode(struct qmspi_regs *regs, uint32_t smode) | (m << MCHP_QMSPI_M_SIG_POS); } +#ifdef CONFIG_SPI_EXTENDED_MODES /* * QMSPI HW support single, dual, and quad. * Return QMSPI Control/Descriptor register encoded value. @@ -287,26 +307,12 @@ static uint8_t npins_from_spi_config(const struct spi_config *config) return 1u; } } +#endif /* CONFIG_SPI_EXTENDED_MODES */ -/* - * Configure QMSPI. - * NOTE: QMSPI Port 0 has two chip selects available. Ports 1 & 2 - * support only CS0#. - */ -static int qmspi_configure(const struct device *dev, - const struct spi_config *config) +static int spi_feature_support(const struct spi_config *config) { - const struct spi_qmspi_config *cfg = dev->config; - struct spi_qmspi_data *qdata = dev->data; - struct qmspi_regs *regs = cfg->regs; - uint32_t smode; - - if (spi_context_configured(&qdata->ctx, config)) { - return 0; - } - - if (config->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE - | SPI_MODE_LOOP)) { + if (config->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE | SPI_MODE_LOOP)) { + LOG_ERR("Driver does not support LSB first, slave, or loop back"); return -ENOTSUP; } @@ -320,43 +326,72 @@ static int qmspi_configure(const struct device *dev, return -ENOTSUP; } - if (config->operation & SPI_TRANSFER_LSB) { - LOG_ERR("LSB first not supported"); - return -ENOTSUP; - } - - if (config->operation & SPI_OP_MODE_SLAVE) { - LOG_ERR("Slave mode not supported"); - return -ENOTSUP; - } - if (SPI_WORD_SIZE_GET(config->operation) != 8) { LOG_ERR("Word size != 8 not supported"); return -ENOTSUP; } + return 0; +} + +/* Configure QMSPI. + * NOTE: QMSPI Shared SPI port has two chip selects. + * Private SPI and internal SPI ports support one chip select. + * Hardware supports dual and quad I/O. Dual and quad are allowed + * if SPI extended mode is enabled at build time. User must + * provide pin configuration via DTS. + */ +static int qmspi_configure(const struct device *dev, + const struct spi_config *config) +{ + const struct spi_qmspi_config *cfg = dev->config; + struct spi_qmspi_data *qdata = dev->data; + const struct spi_config *curr_cfg = qdata->ctx.config; + struct qmspi_regs *regs = cfg->regs; + uint32_t smode; + int ret; + + if (!config) { + return -EINVAL; + } + + if (curr_cfg->frequency != config->frequency) { + qmspi_set_frequency(qdata, regs, config->frequency); + } + + if (curr_cfg->operation == config->operation) { + return 0; /* no change required */ + } + + /* check new configuration */ + ret = spi_feature_support(config); + if (ret) { + return ret; + } + +#ifdef CONFIG_SPI_EXTENDED_MODES smode = encode_lines(config); if (smode == 0xff) { LOG_ERR("Requested lines mode not supported"); return -ENOTSUP; } - qdata->np = npins_from_spi_config(config); +#else + smode = MCHP_QMSPI_C_IFM_1X; + qdata->np = 1u; +#endif regs->CTRL = smode; - /* Use the requested or next highest possible frequency */ - qmspi_set_frequency(regs, config->frequency); - smode = 0; if ((config->operation & SPI_MODE_CPHA) != 0U) { - smode |= (1ul << 0); + smode |= BIT(0); } if ((config->operation & SPI_MODE_CPOL) != 0U) { - smode |= (1ul << 1); + smode |= BIT(1); } - qmspi_set_signalling_mode(regs, smode); + qmspi_set_signalling_mode(qdata, regs, smode); /* chip select */ smode = regs->MODE & ~(MCHP_QMSPI_M_CS_MASK); @@ -399,341 +434,347 @@ static uint32_t encode_npins(uint8_t npins) } } -static int qmspi_tx_tsd_clks(struct qmspi_regs *regs, uint8_t npins, - uint32_t nclks, bool tx_close) -{ - uint32_t descr = 0; - uint32_t nu = 0; - uint32_t qsts = 0; - int counter = 0; - int ret = 0; - - LOG_DBG("Sync TSD CLKS: nclks = %u close = %d", nclks, tx_close); - - if (nclks == 0) { - return 0; - } - - regs->CTRL = MCHP_QMSPI_C_DESCR_EN | MCHP_QMSPI_C_DESCR(0); - regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - - descr |= encode_npins(npins); - descr |= MCHP_QMSPI_C_TX_DIS | MCHP_QMSPI_C_DESCR_LAST; - - /* number of clocks to generate */ - while (nclks) { - nu = nclks; - if (nu > XEC_QSPI_MAX_TSCLK_UNITS) { - nu = XEC_QSPI_MAX_TSCLK_UNITS; - } - nclks -= nu; - - /* XEC_QSPI_MAX_TSCLK_UNITS guarantees no overflow - * for valid npins [1, 2, 4] - */ - nu *= npins; - if (nu % 8) { - descr |= MCHP_QMSPI_C_XFR_UNITS_BITS; - } else { /* byte units */ - descr |= MCHP_QMSPI_C_XFR_UNITS_1; - nu /= 8; - } - - descr |= ((nu << MCHP_QMSPI_C_XFR_NUNITS_POS) & - MCHP_QMSPI_C_XFR_NUNITS_MASK); - - LOG_DBG("Sync TSD CLKS: descr = 0x%08x", descr); - - regs->DESCR[0] = descr; - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - regs->EXE = MCHP_QMSPI_EXE_START; - - counter = 0; - qsts = regs->STS; - while ((qsts & (MCHP_QMSPI_STS_DONE | - MCHP_QMSPI_STS_TXBE_RO)) != - (MCHP_QMSPI_STS_DONE | MCHP_QMSPI_STS_TXBE_RO)) { - if (qsts & (MCHP_QMSPI_STS_PROG_ERR | - MCHP_QMSPI_STS_TXB_ERR)) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return -EIO; - } - ret = xec_qmspi_spin_yield(&counter, XEC_QMSPI_WAIT_FULL_FIFO); - if (ret != 0) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return ret; - } - qsts = regs->STS; - } - } - - return 0; -} - -static int qmspi_tx(struct qmspi_regs *regs, uint8_t npins, - const struct spi_buf *tx_buf, bool close) -{ - const uint8_t *p = tx_buf->buf; - uint32_t tlen = tx_buf->len; - uint32_t nu = 0; - uint32_t descr = 0; - uint32_t qsts = 0; - uint8_t data_byte = 0; - int i = 0; - int ret = 0; - int counter = 0; - - LOG_DBG("Sync TX: p=%p len = %u close = %d", p, tlen, close); - - if (tlen == 0) { - return 0; - } - - regs->CTRL = MCHP_QMSPI_C_DESCR_EN | MCHP_QMSPI_C_DESCR(0); - regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - - descr |= encode_npins(npins); - descr |= MCHP_QMSPI_C_DESCR_LAST; - - if (p) { - descr |= MCHP_QMSPI_C_TX_DATA | MCHP_QMSPI_C_XFR_UNITS_1; - } else { /* length with no data is number of tri-state clocks */ - descr |= MCHP_QMSPI_C_XFR_UNITS_BITS; - tlen *= npins; - if ((tlen == 0) || (tlen > MCHP_QMSPI_C_MAX_UNITS)) { - return -EDOM; - } - } - - while (tlen) { - descr &= ~MCHP_QMSPI_C_XFR_NUNITS_MASK; - - nu = tlen; - if (p && (nu > MCHP_QMSPI_TX_FIFO_LEN)) { - nu = MCHP_QMSPI_TX_FIFO_LEN; - } - - descr |= (nu << MCHP_QMSPI_C_XFR_NUNITS_POS) & - MCHP_QMSPI_C_XFR_NUNITS_MASK; - - tlen -= nu; - if ((tlen == 0) && close) { - descr |= MCHP_QMSPI_C_CLOSE; - } - - LOG_DBG("Sync TX: descr=0x%08x", descr); - - regs->DESCR[0] = descr; - - if (p) { - for (i = 0; i < nu; i++) { - data_byte = *p++; - LOG_DBG("Sync TX: TX FIFO 0x%02x", data_byte); - sys_write8(data_byte, - (mm_reg_t)®s->TX_FIFO); - } - } - - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - regs->EXE = MCHP_QMSPI_EXE_START; - - counter = 0; - qsts = regs->STS; - while ((qsts & (MCHP_QMSPI_STS_DONE | - MCHP_QMSPI_STS_TXBE_RO)) != - (MCHP_QMSPI_STS_DONE | MCHP_QMSPI_STS_TXBE_RO)) { - if (qsts & (MCHP_QMSPI_STS_PROG_ERR | - MCHP_QMSPI_STS_TXB_ERR)) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return -EIO; - } - ret = xec_qmspi_spin_yield(&counter, XEC_QMSPI_WAIT_FULL_FIFO); - if (ret != 0) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return ret; - } - qsts = regs->STS; - } - } - - return 0; -} - -static int qmspi_rx(struct qmspi_regs *regs, uint8_t npins, - const struct spi_buf *rx_buf, bool close) -{ - uint8_t *p = rx_buf->buf; - size_t rlen = rx_buf->len; - uint32_t descr = 0; - uint32_t nu = 0; - uint32_t nrxb = 0; - uint32_t qsts = 0; - int ret = 0; - int counter = 0; - uint8_t data_byte = 0; - uint8_t np = npins; - - LOG_DBG("Sync RX: len = %u close = %d", rlen, close); - - if (rlen == 0) { - return 0; - } - - descr |= encode_npins(np); - descr |= MCHP_QMSPI_C_RX_EN | MCHP_QMSPI_C_XFR_UNITS_1 | - MCHP_QMSPI_C_DESCR_LAST; - - regs->CTRL = MCHP_QMSPI_C_DESCR_EN | MCHP_QMSPI_C_DESCR(0); - regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - - while (rlen) { - descr &= ~MCHP_QMSPI_C_XFR_NUNITS_MASK; - - nu = MCHP_QMSPI_RX_FIFO_LEN; - if (rlen < MCHP_QMSPI_RX_FIFO_LEN) { - nu = rlen; - } - - descr |= (nu << MCHP_QMSPI_C_XFR_NUNITS_POS) & - MCHP_QMSPI_C_XFR_NUNITS_MASK; - - rlen -= nu; - if ((rlen == 0) && close) { - descr |= MCHP_QMSPI_C_CLOSE; - } - - LOG_DBG("Sync RX descr = 0x%08x", descr); - regs->DESCR[0] = descr; - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - regs->EXE = MCHP_QMSPI_EXE_START; - - nrxb = (regs->BCNT_STS & MCHP_QMSPI_RX_BUF_CNT_STS_MASK) >> - MCHP_QMSPI_RX_BUF_CNT_STS_POS; - - LOG_DBG("Sync RX start buf count = 0x%08x", nrxb); - - while (nrxb < nu) { - qsts = regs->STS; - if (qsts & (MCHP_QMSPI_STS_RXB_ERR | - MCHP_QMSPI_STS_PROG_ERR)) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return -EIO; - } - ret = xec_qmspi_spin_yield(&counter, - XEC_QMSPI_WAIT_FULL_FIFO); - if (ret != 0) { - regs->EXE = MCHP_QMSPI_EXE_STOP; - return ret; - } - - nrxb = (regs->BCNT_STS & - MCHP_QMSPI_RX_BUF_CNT_STS_MASK) >> - MCHP_QMSPI_RX_BUF_CNT_STS_POS; - - LOG_DBG("Sync RX loop buf count = 0x%08x", nrxb); - } - - LOG_DBG("Sync RX rem buf count = 0x%08x", nrxb); - - while (nrxb) { - data_byte = sys_read8((mm_reg_t)®s->RX_FIFO); - if (p) { - *p++ = data_byte; - } - nrxb--; - } - } - - return 0; -} - -/* does the buffer set contain data? */ -static bool is_buf_set(const struct spi_buf_set *bufs) -{ - if (!bufs) { - return false; - } - - if (bufs->count) { - return true; - } - - return false; -} - -/* - * can we use struct spi_qmspi_data to hold information - * about number of pins to use for transmit/receive? +/* Common controller transfer initialziation using Local-DMA. + * Full-duplex: controller configured to transmit and receive simultaneouly. + * Half-duplex(dual/quad): User may only specify TX or RX buffer sets. + * Passing both buffers sets is reported as an error. */ +static inline int qmspi_xfr_cm_init(const struct device *dev, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct spi_qmspi_config *devcfg = dev->config; + struct spi_qmspi_data *qdata = dev->data; + struct qmspi_regs *regs = devcfg->regs; + + regs->IEN = 0; + regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; + regs->LDMA_RX_DESCR_BM = 0; + regs->LDMA_TX_DESCR_BM = 0; + regs->MODE &= ~(MCHP_QMSPI_M_LDMA_TX_EN | MCHP_QMSPI_M_LDMA_RX_EN); + regs->STS = 0xffffffffu; + regs->CTRL = encode_npins(qdata->np); + + qdata->qstatus = 0; + +#ifdef CONFIG_SPI_EXTENDED_MODES + if (qdata->np != 1) { + if (tx_bufs && rx_bufs) { + LOG_ERR("Cannot specify both TX and RX buffers in half-duplex(dual/quad)"); + return -EPROTONOSUPPORT; + } + } +#endif + + return 0; +} + +/* QMSPI Local-DMA transfer configuration: + * Support full and half(dual/quad) duplex transfers. + * Requires caller to have checked that only one direction was setup + * in the SPI context: TX or RX not both. (refer to qmspi_xfr_cm_init) + * Supports spi_buf's where data pointer is NULL and length non-zero. + * These buffers are used as TX tri-state I/O clock only generation or + * RX data discard for certain SPI command protocols using dual/quad I/O. + * 1. Get largest contiguous data size from SPI context. + * 2. If the SPI TX context has a non-zero length configure Local-DMA TX + * channel 1 for contigous data size. If TX context has valid buffer + * configure channel to use context buffer with address increment. + * If the TX buffer pointer is NULL interpret byte length as the number + * of clocks to generate with output line(s) tri-stated. NOTE: The controller + * must be configured with TX disabled to not drive output line(s) during + * clock generation. Also, no data should be written to TX FIFO. The unit + * size can be set to bits. The number of units to transfer must be computed + * based upon the number of output pins in the IOM field: full-duplex is one + * bit per clock, dual is 2 bits per clock, and quad is 4 bits per clock. + * For example, if I/O lines is 4 (quad) meaning 4 bits per clock and the + * user wants 7 clocks then the number of bit units is 4 * 7 = 28. + * 3. If instead, the SPI RX context has a non-zero length configure Local-DMA + * RX channel 1 for the contigous data size. If RX context has a valid + * buffer configure channel to use buffer with address increment else + * configure channel for driver data temporary buffer without address + * increment. + * 4. Update QMSPI Control register. + */ +static uint32_t qmspi_ldma_encode_unit_size(uint32_t maddr, size_t len) +{ + uint8_t temp = (maddr | (uint32_t)len) & 0x3u; + + if (temp == 0) { + return MCHP_QMSPI_LDC_ASZ_4; + } else if (temp == 2) { + return MCHP_QMSPI_LDC_ASZ_2; + } else { + return MCHP_QMSPI_LDC_ASZ_1; + } +} + +static uint32_t qmspi_unit_size(size_t xfrlen) +{ + if ((xfrlen & 0xfu) == 0u) { + return 16u; + } else if ((xfrlen & 0x3u) == 0u) { + return 4u; + } else { + return 1u; + } +} + +static uint32_t qmspi_encode_unit_size(uint32_t units_in_bytes) +{ + if (units_in_bytes == 16u) { + return MCHP_QMSPI_C_XFR_UNITS_16; + } else if (units_in_bytes == 4u) { + return MCHP_QMSPI_C_XFR_UNITS_4; + } else { + return MCHP_QMSPI_C_XFR_UNITS_1; + } +} + +static size_t q_ldma_cfg(const struct device *dev) +{ + const struct spi_qmspi_config *devcfg = dev->config; + struct spi_qmspi_data *qdata = dev->data; + struct spi_context *ctx = &qdata->ctx; + struct qmspi_regs *regs = devcfg->regs; + + size_t ctx_xfr_len = spi_context_max_continuous_chunk(ctx); + uint32_t ctrl, ldctrl, mstart, qunits, qxfru, xfrlen; + + regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; + regs->MODE &= ~(MCHP_QMSPI_M_LDMA_RX_EN | MCHP_QMSPI_M_LDMA_TX_EN); + regs->LDRX[0].CTRL = 0; + regs->LDRX[0].MSTART = 0; + regs->LDRX[0].LEN = 0; + regs->LDTX[0].CTRL = 0; + regs->LDTX[0].MSTART = 0; + regs->LDTX[0].LEN = 0; + + if (ctx_xfr_len == 0) { + return 0; + } + + qunits = qmspi_unit_size(ctx_xfr_len); + ctrl = qmspi_encode_unit_size(qunits); + qxfru = ctx_xfr_len / qunits; + if (qxfru > 0x7fffu) { + qxfru = 0x7fffu; + } + ctrl |= (qxfru << MCHP_QMSPI_C_XFR_NUNITS_POS); + xfrlen = qxfru * qunits; + +#ifdef MCHP_XEC_QMSPI_DEBUG + qdata->qunits = qunits; + qdata->qxfru = qxfru; + qdata->xfrlen = xfrlen; +#endif + if (spi_context_tx_buf_on(ctx)) { + mstart = (uint32_t)ctx->tx_buf; + ctrl |= MCHP_QMSPI_C_TX_DATA | MCHP_QMSPI_C_TX_LDMA_CH0; + ldctrl = qmspi_ldma_encode_unit_size(mstart, xfrlen); + ldctrl |= MCHP_QMSPI_LDC_INCR_EN | MCHP_QMSPI_LDC_EN; + regs->MODE |= MCHP_QMSPI_M_LDMA_TX_EN; + regs->LDTX[0].LEN = xfrlen; + regs->LDTX[0].MSTART = mstart; + regs->LDTX[0].CTRL = ldctrl; + } + + if (spi_context_rx_buf_on(ctx)) { + mstart = (uint32_t)ctx->rx_buf; + ctrl |= MCHP_QMSPI_C_RX_LDMA_CH0 | MCHP_QMSPI_C_RX_EN; + ldctrl = MCHP_QMSPI_LDC_EN | MCHP_QMSPI_LDC_INCR_EN; + ldctrl |= qmspi_ldma_encode_unit_size(mstart, xfrlen); + regs->MODE |= MCHP_QMSPI_M_LDMA_RX_EN; + regs->LDRX[0].LEN = xfrlen; + regs->LDRX[0].MSTART = mstart; + regs->LDRX[0].CTRL = ldctrl; + } + + regs->CTRL = (regs->CTRL & 0x3u) | ctrl; + + return xfrlen; +} + +/* Start and wait for QMSPI synchronous transfer(s) to complete. + * Initialize QMSPI controller for Local-DMA operation. + * Iterate over SPI context with non-zero TX or RX data lengths. + * 1. Configure QMSPI Control register and Local-DMA channel(s) + * 2. Clear QMSPI status + * 3. Start QMSPI transfer + * 4. Poll QMSPI status for transfer done and DMA done with timeout. + * 5. Hardware anomaly work-around: Poll with timeout QMSPI Local-DMA + * TX and RX channels until hardware clears both channel enables. + * This indicates hardware is really done with transfer to/from memory. + * 6. Update SPI context with amount of data transmitted and received. + * If SPI configuration hold chip select on flag is not set then instruct + * QMSPI to de-assert chip select. + * Set SPI context as complete + */ +static int qmspi_xfr_sync(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct spi_qmspi_config *devcfg = dev->config; + struct spi_qmspi_data *qdata = dev->data; + struct spi_context *ctx = &qdata->ctx; + struct qmspi_regs *regs = devcfg->regs; + size_t xfr_len; + + int ret = qmspi_xfr_cm_init(dev, tx_bufs, rx_bufs); + + if (ret) { + return ret; + } + + while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) { + xfr_len = q_ldma_cfg(dev); + regs->STS = 0xffffffffu; + regs->EXE = MCHP_QMSPI_EXE_START; + +#ifdef MCHP_XEC_QMSPI_DEBUG + uint32_t temp = regs->STS; + + while (!(temp & MCHP_QMSPI_STS_DONE)) { + temp = regs->STS; + } + qdata->qstatus = temp; + qdata->bufcnt_status = regs->BCNT_STS; + qdata->rx_ldma_ctrl0 = regs->LDRX[0].CTRL; + qdata->tx_ldma_ctrl0 = regs->LDTX[0].CTRL; +#else + uint32_t wcnt = 0; + + qdata->qstatus = regs->STS; + while (!(qdata->qstatus & MCHP_QMSPI_STS_DONE)) { + k_busy_wait(1u); + if (++wcnt > XEC_QSPI_TIMEOUT_US) { + regs->EXE = MCHP_QMSPI_EXE_STOP; + return -ETIMEDOUT; + } + qdata->qstatus = regs->STS; + } +#endif + spi_context_update_tx(ctx, 1, xfr_len); + spi_context_update_rx(ctx, 1, xfr_len); + } + + if (!(spi_cfg->operation & SPI_HOLD_ON_CS)) { + regs->EXE = MCHP_QMSPI_EXE_STOP; + } + + spi_context_complete(ctx, dev, 0); + + return 0; +} + +#ifdef CONFIG_SPI_ASYNC +/* Configure QMSPI such that QMSPI transfer FSM and LDMA FSM are synchronized. + * Transfer length must be programmed into control/descriptor register(s) and + * LDMA register(s). LDMA override length bit must NOT be set. + */ +static int qmspi_xfr_start_async(const struct device *dev, const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct spi_qmspi_config *devcfg = dev->config; + struct spi_qmspi_data *qdata = dev->data; + struct qmspi_regs *regs = devcfg->regs; + int ret; + + ret = qmspi_xfr_cm_init(dev, tx_bufs, rx_bufs); + if (ret) { + return ret; + } + + qdata->xfr_len = q_ldma_cfg(dev); + if (!qdata->xfr_len) { + return 0; /* nothing to do */ + } + + regs->STS = 0xffffffffu; + regs->EXE = MCHP_QMSPI_EXE_START; + regs->IEN = MCHP_QMSPI_IEN_XFR_DONE | MCHP_QMSPI_IEN_PROG_ERR + | MCHP_QMSPI_IEN_LDMA_RX_ERR | MCHP_QMSPI_IEN_LDMA_TX_ERR; + + return 0; +} + +/* Wrapper to start asynchronous (interrupts enabled) SPI transction */ +static int qmspi_xfr_async(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + struct spi_qmspi_data *qdata = dev->data; + int err = 0; + + qdata->qstatus = 0; + qdata->xfr_len = 0; + + err = qmspi_xfr_start_async(dev, tx_bufs, rx_bufs); + + return err; +} +#endif /* CONFIG_SPI_ASYNC */ + +/* Start (a)synchronous transaction using QMSPI Local-DMA */ static int qmspi_transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) + const struct spi_buf_set *rx_bufs, + bool asynchronous, + spi_callback_t cb, + void *user_data) { - const struct spi_qmspi_config *cfg = dev->config; struct spi_qmspi_data *qdata = dev->data; - struct qmspi_regs *regs = cfg->regs; - const struct spi_buf *pb; - bool tx_close = false; - bool rx_close = false; - size_t nb = 0; + struct spi_context *ctx = &qdata->ctx; int err = 0; - spi_context_lock(&qdata->ctx, false, NULL, NULL, config); + if (!config) { + return -EINVAL; + } + + if (!tx_bufs && !rx_bufs) { + return 0; + } + + spi_context_lock(&qdata->ctx, asynchronous, cb, user_data, config); err = qmspi_configure(dev, config); if (err != 0) { - spi_context_release(&qdata->ctx, err); + spi_context_release(ctx, err); return err; } - spi_context_cs_control(&qdata->ctx, true); + spi_context_cs_control(ctx, true); + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); - if (tx_bufs != NULL) { - pb = tx_bufs->buffers; - nb = tx_bufs->count; - while (nb--) { - if (!(config->operation & SPI_HOLD_ON_CS) && !nb && - !is_buf_set(rx_bufs)) { - tx_close = true; - } - - if (pb->buf) { - err = qmspi_tx(regs, qdata->np, pb, tx_close); - } else { - err = qmspi_tx_tsd_clks(regs, qdata->np, - pb->len, tx_close); - } - if (err != 0) { - spi_context_cs_control(&qdata->ctx, false); - spi_context_release(&qdata->ctx, err); - return err; - } - pb++; - } +#ifdef CONFIG_SPI_ASYNC + if (asynchronous) { + qdata->cb = cb; + qdata->userdata = user_data; + err = qmspi_xfr_async(dev, config, tx_bufs, rx_bufs); + } else { + err = qmspi_xfr_sync(dev, config, tx_bufs, rx_bufs); + } +#else + err = qmspi_xfr_sync(dev, config, tx_bufs, rx_bufs); +#endif + if (err) { /* de-assert CS# and give semaphore */ + spi_context_unlock_unconditionally(ctx); + return err; } - if (rx_bufs != NULL) { - pb = rx_bufs->buffers; - nb = rx_bufs->count; - while (nb--) { - if (!(config->operation & SPI_HOLD_ON_CS) && !nb) { - rx_close = true; - } - - err = qmspi_rx(regs, qdata->np, pb, rx_close); - if (err != 0) { - break; - } - pb++; - } + if (asynchronous) { + return err; } - spi_context_cs_control(&qdata->ctx, false); - spi_context_release(&qdata->ctx, err); + err = spi_context_wait_for_completion(ctx); + if (!(config->operation & SPI_HOLD_ON_CS)) { + spi_context_cs_control(ctx, false); + } + spi_context_release(ctx, err); + return err; } @@ -742,212 +783,11 @@ static int qmspi_transceive_sync(const struct device *dev, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs) { - return qmspi_transceive(dev, config, tx_bufs, rx_bufs); + return qmspi_transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL); } #ifdef CONFIG_SPI_ASYNC -static uint32_t ldma_units(const uint8_t *buf, size_t len) -{ - uint32_t mask = ((uint32_t)buf | len) & 0x03u; - - if (!mask) { - return MCHP_QMSPI_LDC_ASZ_4; - } - return MCHP_QMSPI_LDC_ASZ_1; -} - -static size_t descr_data_size(uint32_t *descr, const uint8_t *buf, size_t len) -{ - uint32_t qlen = len; - uint32_t mask = (uint32_t)buf | qlen; - uint32_t dlen = 0; - - if ((mask & 0x0f) == 0) { /* 16-byte units */ - dlen = (qlen / 16) & MCHP_QMSPI_C_XFR_NUNITS_MASK0; - *descr = dlen << MCHP_QMSPI_C_XFR_NUNITS_POS; - *descr |= MCHP_QMSPI_C_XFR_UNITS_16; - dlen *= 16; - } else if ((mask & 0x03) == 0) { /* 4 byte units */ - dlen = (qlen / 4) & MCHP_QMSPI_C_XFR_NUNITS_MASK0; - *descr = dlen << MCHP_QMSPI_C_XFR_NUNITS_POS; - *descr |= MCHP_QMSPI_C_XFR_UNITS_4; - dlen *= 4; - } else { /* QMSPI xfr length units = 1 bytes */ - dlen = qlen & MCHP_QMSPI_C_XFR_NUNITS_MASK0; - *descr = dlen << MCHP_QMSPI_C_XFR_NUNITS_POS; - *descr |= MCHP_QMSPI_C_XFR_UNITS_1; - } - - return dlen; -} - -static size_t tx_fifo_fill(struct qmspi_regs *regs, const uint8_t *pdata, - size_t ndata) -{ - size_t n = 0; - - while (n < ndata) { - if (n >= MCHP_QMSPI_TX_FIFO_LEN) { - break; - } - sys_write8(*pdata, (mm_reg_t)®s->TX_FIFO); - pdata++; - n++; - } - - return n; -} - -static size_t rx_fifo_get(struct qmspi_regs *regs, uint8_t *pdata, size_t ndata) -{ - size_t n = 0; - size_t nrxb = ((regs->BCNT_STS & MCHP_QMSPI_RX_BUF_CNT_STS_MASK) >> - MCHP_QMSPI_RX_BUF_CNT_STS_POS); - - while ((n < ndata) && (n < nrxb)) { - *pdata++ = sys_read8((mm_reg_t)®s->RX_FIFO); - n++; - } - - return n; -} - -/* - * Do we close the transaction (de-assert CS#) for transmit? - * NOTE: driver always performs all TX before RX. - * For trasmit we close if caller did not request holding CS# active, - * and we are on last TX buffer and no RX buffers. - */ -static bool is_tx_close(struct spi_context *ctx) -{ - if (!(ctx->owner->operation & SPI_HOLD_ON_CS) && - (ctx->tx_count == 1) && !ctx->rx_count) { - return true; - } - return false; -} - -/* - * Do we close the transaction (de-assert CS#) for receive. - * For receive we close if caller did not request holding CS# active - * and we are on last RX buffer. - */ -static bool is_rx_close(struct spi_context *ctx) -{ - if (!(ctx->owner->operation & SPI_HOLD_ON_CS) && - (ctx->rx_count == 1)) { - return true; - } - return false; -} - -static bool spi_qmspi_async_start(const struct device *dev) -{ - const struct spi_qmspi_config *cfg = dev->config; - struct spi_qmspi_data *qdata = dev->data; - struct spi_context *ctx = &qdata->ctx; - struct qmspi_regs *regs = cfg->regs; - uint32_t descr = 0; - size_t dlen = 0; - uint8_t npins = qdata->np; /* was cfg->width; */ - - qdata->xfr_flags = 0; - qdata->ldma_chan = 0; - regs->CTRL = (regs->CTRL & MCHP_QMSPI_C_IFM_MASK) | - MCHP_QMSPI_C_DESCR_EN; - regs->EXE = MCHP_QMSPI_EXE_CLR_FIFOS; - regs->MODE &= ~(MCHP_QMSPI_M_LDMA_RX_EN | MCHP_QMSPI_M_LDMA_TX_EN); - regs->LDMA_RX_DESCR_BM = 0; - regs->LDMA_TX_DESCR_BM = 0; - - /* buffer is not NULL and length is not 0 */ - if (spi_context_tx_buf_on(ctx)) { - dlen = descr_data_size(&descr, ctx->tx_buf, ctx->tx_len); - qdata->xfr_len = dlen; - qdata->xfr_flags |= XEC_QMSPI_XFR_FLAG_TX; - descr |= MCHP_QMSPI_C_DESCR_LAST; - if (is_tx_close(ctx)) { - descr |= MCHP_QMSPI_C_CLOSE; - } - - if (dlen) { - descr |= MCHP_QMSPI_C_TX_DATA; - if (dlen <= MCHP_QMSPI_TX_FIFO_LEN) { - /* Load data into TX FIFO */ - tx_fifo_fill(regs, ctx->tx_buf, dlen); - } else { - /* LDMA TX channel 0 */ - descr |= (1u << MCHP_QMSPI_C_TX_DMA_POS); - regs->LDTX[0].CTRL = - ldma_units(ctx->tx_buf, dlen) | - MCHP_QMSPI_LDC_INCR_EN; - regs->LDTX[0].MSTART = (uint32_t)ctx->tx_buf; - regs->LDTX[0].LEN = dlen; - regs->LDTX[0].CTRL |= MCHP_QMSPI_LDC_EN; - regs->LDMA_TX_DESCR_BM |= BIT(0); - regs->MODE |= MCHP_QMSPI_M_LDMA_TX_EN; - qdata->ldma_chan = 1; - } - } - } else if (spi_context_tx_on(ctx)) { - /* buffer is NULL and length is not 0. Tri-state clocks */ - qdata->xfr_len = ctx->tx_len; - qdata->xfr_flags |= XEC_QMSPI_XFR_FLAG_TX; - dlen = ctx->tx_len * npins; - descr = dlen << MCHP_QMSPI_C_XFR_NUNITS_POS; - descr |= MCHP_QMSPI_C_DESCR_LAST; - if (is_tx_close(ctx)) { - descr |= MCHP_QMSPI_C_CLOSE; - } - } else if (spi_context_rx_buf_on(ctx)) { - dlen = descr_data_size(&descr, ctx->rx_buf, ctx->rx_len); - qdata->xfr_len = dlen; - qdata->xfr_flags &= ~XEC_QMSPI_XFR_FLAG_TX; - descr |= MCHP_QMSPI_C_RX_EN; - descr |= MCHP_QMSPI_C_DESCR_LAST; - if (is_rx_close(ctx)) { - descr |= MCHP_QMSPI_C_CLOSE; - } - if (dlen > MCHP_QMSPI_RX_FIFO_LEN) { - /* LDMA RX channel 0 */ - descr |= (1u << MCHP_QMSPI_C_RX_DMA_POS); - regs->LDRX[0].CTRL = - ldma_units(ctx->rx_buf, dlen) | - MCHP_QMSPI_LDC_INCR_EN; - regs->LDRX[0].MSTART = (uint32_t)ctx->rx_buf; - regs->LDRX[0].LEN = dlen; - regs->LDRX[0].CTRL |= MCHP_QMSPI_LDC_EN; - regs->LDMA_RX_DESCR_BM |= BIT(0); - regs->MODE |= MCHP_QMSPI_M_LDMA_RX_EN; - qdata->ldma_chan = 1; - } - } - - if (descr == 0) { - return false; - } - - descr |= encode_npins(npins); - - LOG_DBG("Async descr = 0x%08x", descr); - - regs->DESCR[0] = descr; - - /* clear status */ - regs->STS = MCHP_QMSPI_STS_RW1C_MASK; - - /* enable interrupt */ - regs->IEN = MCHP_QMSPI_IEN_XFR_DONE | MCHP_QMSPI_IEN_PROG_ERR | - MCHP_QMSPI_IEN_LDMA_RX_ERR | MCHP_QMSPI_IEN_LDMA_TX_ERR; - - /* start */ - qdata->xfr_flags |= XEC_QMSPI_XFR_FLAG_STARTED; - regs->EXE = MCHP_QMSPI_EXE_START; - - return true; -} - static int qmspi_transceive_async(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -955,32 +795,9 @@ static int qmspi_transceive_async(const struct device *dev, spi_callback_t cb, void *userdata) { - struct spi_qmspi_data *data = dev->data; - - spi_context_lock(&data->ctx, true, cb, userdata, config); - - int ret = qmspi_configure(dev, config); - - if (ret != 0) { - spi_context_release(&data->ctx, ret); - return ret; - } - - spi_context_cs_control(&data->ctx, true); - - spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1); - - if (spi_qmspi_async_start(dev)) { - return 0; /* QMSPI started */ - } - - /* error path */ - spi_context_cs_control(&data->ctx, false); - spi_context_release(&data->ctx, ret); - - return -EIO; + return qmspi_transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata); } -#endif +#endif /* CONFIG_SPI_ASYNC */ static int qmspi_release(const struct device *dev, const struct spi_config *config) @@ -995,8 +812,7 @@ static int qmspi_release(const struct device *dev, /* Force CS# to de-assert on next unit boundary */ regs->EXE = MCHP_QMSPI_EXE_STOP; while (regs->STS & MCHP_QMSPI_STS_ACTIVE_RO) { - ret = xec_qmspi_spin_yield(&counter, - XEC_QMSPI_WAIT_COUNT); + ret = xec_qmspi_spin_yield(&counter, XEC_QMSPI_WAIT_COUNT); if (ret != 0) { break; } @@ -1008,6 +824,12 @@ static int qmspi_release(const struct device *dev, return ret; } +/* QMSPI interrupt handler called by Zephyr ISR + * All transfers use QMSPI Local-DMA specified by the Control register. + * QMSPI descriptor mode not used. + * Full-duplex always uses LDMA TX channel 0 and RX channel 0 + * Half-duplex(dual/quad) use one of TX channel 0 or RX channel 0 + */ void qmspi_xec_isr(const struct device *dev) { const struct spi_qmspi_config *cfg = dev->config; @@ -1017,7 +839,6 @@ void qmspi_xec_isr(const struct device *dev) #ifdef CONFIG_SPI_ASYNC struct spi_context *ctx = &data->ctx; int xstatus = 0; - size_t nrx = 0; #endif regs->IEN = 0; @@ -1026,63 +847,74 @@ void qmspi_xec_isr(const struct device *dev) mchp_xec_ecia_girq_src_clr(cfg->girq, cfg->girq_pos); #ifdef CONFIG_SPI_ASYNC - data->in_isr = 1; - if (qstatus & XEC_QSPI_HW_ERRORS_ALL) { + xstatus = -EIO; data->qstatus |= BIT(7); - xstatus = (int)qstatus; - spi_context_cs_control(&data->ctx, false); - spi_context_complete(&data->ctx, dev, xstatus); + regs->EXE = MCHP_QMSPI_EXE_STOP; + spi_context_cs_control(ctx, false); + spi_context_complete(ctx, dev, xstatus); + if (data->cb) { + data->cb(dev, xstatus, data->userdata); + } + return; } - if (data->xfr_flags & BIT(0)) { /* is TX ? */ - data->xfr_flags &= ~BIT(0); - /* if last buffer ctx->tx_len should be 0 and this - * routine sets ctx->tx_buf to NULL. - * If we have another buffer ctx->tx_buf points to it - * and ctx->tx_len is set to new size. - * ISSUE: If we use buffer pointer = NULL and len != 0 - * for tri-state clocks then spi_context_tx_buf_on - * will return false because it checks both! - */ - spi_context_update_tx(&data->ctx, 1, data->xfr_len); - if (spi_context_tx_buf_on(&data->ctx)) { - spi_qmspi_async_start(dev); - return; - } + /* Clear Local-DMA enables in Mode and Control registers */ + regs->MODE &= ~(MCHP_QMSPI_M_LDMA_RX_EN | MCHP_QMSPI_M_LDMA_TX_EN); + regs->CTRL &= MCHP_QMSPI_C_IFM_MASK; - if (spi_context_rx_buf_on(&data->ctx)) { - spi_qmspi_async_start(dev); - return; - } - } else { - /* Handle RX */ - if ((data->ldma_chan == 0) && - (regs->BCNT_STS & MCHP_QMSPI_RX_BUF_CNT_STS_MASK)) { - /* RX FIFO mode */ - nrx = rx_fifo_get(regs, data->ctx.rx_buf, - data->xfr_len); - } else { - nrx = data->xfr_len; - } + spi_context_update_tx(ctx, 1, data->xfr_len); + spi_context_update_rx(ctx, 1, data->xfr_len); - spi_context_update_rx(&data->ctx, 1, nrx); - if (spi_context_rx_buf_on(&data->ctx)) { - spi_qmspi_async_start(dev); - return; - } + data->xfr_len = q_ldma_cfg(dev); + if (data->xfr_len) { + regs->STS = 0xffffffffu; + regs->EXE = MCHP_QMSPI_EXE_START; + regs->IEN = MCHP_QMSPI_IEN_XFR_DONE | MCHP_QMSPI_IEN_PROG_ERR + | MCHP_QMSPI_IEN_LDMA_RX_ERR | MCHP_QMSPI_IEN_LDMA_TX_ERR; + return; } if (!(ctx->owner->operation & SPI_HOLD_ON_CS)) { + regs->EXE = MCHP_QMSPI_EXE_STOP; spi_context_cs_control(&data->ctx, false); } spi_context_complete(&data->ctx, dev, xstatus); - data->in_isr = 0; -#endif + if (data->cb) { + data->cb(dev, xstatus, data->userdata); + } +#endif /* CONFIG_SPI_ASYNC */ } +#ifdef CONFIG_PM_DEVICE +/* If the application wants the QMSPI pins to be disabled in suspend it must + * define pinctr-1 values for each pin in the app/project DT overlay. + */ +static int qmspi_xec_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct spi_qmspi_config *devcfg = dev->config; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + break; + case PM_DEVICE_ACTION_SUSPEND: + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP); + if (ret == -ENOENT) { /* pinctrl-1 does not exist */ + ret = 0; + } + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + /* * Called for each QMSPI controller instance * Initialize QMSPI controller. @@ -1097,44 +929,56 @@ static int qmspi_xec_init(const struct device *dev) const struct spi_qmspi_config *cfg = dev->config; struct spi_qmspi_data *qdata = dev->data; struct qmspi_regs *regs = cfg->regs; - const struct device *pcr_dev = DEVICE_DT_GET(MCHP_XEC_CLOCK_CONTROL_NODE); - int ret; - clock_control_subsys_t clkss = - (clock_control_subsys_t)(MCHP_XEC_PCR_CLK_PERIPH_FAST); + clock_control_subsys_t clkss = (clock_control_subsys_t)MCHP_XEC_PCR_CLK_PERIPH_FAST; + int ret = 0; qdata->base_freq_hz = 0u; qdata->qstatus = 0; qdata->np = cfg->width; #ifdef CONFIG_SPI_ASYNC - qdata->xfr_flags = 0; - qdata->ldma_chan = 0; - qdata->in_isr = 0; qdata->xfr_len = 0; #endif - if (!device_is_ready(pcr_dev)) { - LOG_ERR("%s PCR device not ready", pcr_dev->name); - return -ENODEV; + if (!cfg->clk_dev) { + LOG_ERR("XEC QMSPI-LDMA clock device not configured"); + return -EINVAL; } - z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0); + ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&cfg->clksrc); + if (ret < 0) { + LOG_ERR("XEC QMSPI-LDMA enable clock source error %d", ret); + return ret; + } + + ret = clock_control_get_rate(cfg->clk_dev, clkss, &qdata->base_freq_hz); + if (ret) { + LOG_ERR("XEC QMSPI-LDMA clock get rate error %d", ret); + return ret; + } + + /* controller in known state before enabling pins */ + qmspi_reset(regs); + mchp_xec_ecia_girq_src_clr(cfg->girq, cfg->girq_pos); ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (ret != 0) { - LOG_ERR("QSPI pinctrl setup failed (%d)", ret); + LOG_ERR("XEC QMSPI-LDMA pinctrl setup failed (%d)", ret); return ret; } - ret = clock_control_get_rate(pcr_dev, (clock_control_subsys_t)clkss, - &qdata->base_freq_hz); + /* default SPI Mode 0 signalling */ + const struct spi_config spi_cfg = { + .frequency = cfg->clock_freq, + .operation = SPI_LINES_SINGLE | SPI_WORD_SET(8), + .cs = NULL, + }; + + ret = qmspi_configure(dev, &spi_cfg); if (ret) { - LOG_ERR("QSPI clock control failed"); + LOG_ERR("XEC QMSPI-LDMA init configure failed (%d)", ret); return ret; } - qmspi_reset(regs); - mchp_xec_ecia_girq_src_clr(cfg->girq, cfg->girq_pos); - #ifdef CONFIG_SPI_ASYNC cfg->irq_config_func(); mchp_xec_ecia_enable(cfg->girq, cfg->girq_pos); @@ -1182,6 +1026,11 @@ static const struct spi_driver_api spi_qmspi_xec_driver_api = { #define XEC_QMSPI_NVIC_DIRECT(i) \ MCHP_XEC_ECIA_NVIC_DIRECT(DT_INST_PROP_BY_IDX(i, girqs, 0)) +#define XEC_QMSPI_PCR_INFO(i) \ + MCHP_XEC_PCR_SCR_ENCODE(DT_INST_CLOCKS_CELL(i, regidx), \ + DT_INST_CLOCKS_CELL(i, bitpos), \ + DT_INST_CLOCKS_CELL(i, domain)) + /* * The instance number, i is not related to block ID's rather the * order the DT tools process all DT files in a build. @@ -1205,7 +1054,10 @@ static const struct spi_driver_api spi_qmspi_xec_driver_api = { }; \ static const struct spi_qmspi_config qmspi_xec_config_##i = { \ .regs = (struct qmspi_regs *) DT_INST_REG_ADDR(i), \ - .cs1_freq = DT_INST_PROP_OR(i, cs1-freq, 0), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(i)), \ + .clksrc = { .pcr_info = XEC_QMSPI_PCR_INFO(i), }, \ + .clock_freq = DT_INST_PROP_OR(i, clock_frequency, MHZ(12)), \ + .cs1_freq = DT_INST_PROP_OR(i, cs1_freq, 0), \ .cs_timing = XEC_QMSPI_CS_TIMING(i), \ .taps_adj = XEC_QMSPI_TAPS_ADJ(i), \ .girq = XEC_QMSPI_GIRQ(i), \ @@ -1213,15 +1065,14 @@ static const struct spi_driver_api spi_qmspi_xec_driver_api = { .girq_nvic_aggr = XEC_QMSPI_NVIC_AGGR(i), \ .girq_nvic_direct = XEC_QMSPI_NVIC_DIRECT(i), \ .irq_pri = DT_INST_IRQ(i, priority), \ - .pcr_idx = DT_INST_PROP_BY_IDX(i, pcrs, 0), \ - .pcr_pos = DT_INST_PROP_BY_IDX(i, pcrs, 1), \ - .port_sel = DT_INST_PROP_OR(i, port_sel, 0), \ .chip_sel = DT_INST_PROP_OR(i, chip_select, 0), \ .width = DT_INST_PROP_OR(0, lines, 1), \ .irq_config_func = qmspi_xec_irq_config_func_##i, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \ }; \ - DEVICE_DT_INST_DEFINE(i, &qmspi_xec_init, NULL, \ + PM_DEVICE_DT_INST_DEFINE(i, qmspi_xec_pm_action); \ + DEVICE_DT_INST_DEFINE(i, &qmspi_xec_init, \ + PM_DEVICE_DT_INST_GET(i), \ &qmspi_xec_data_##i, &qmspi_xec_config_##i, \ POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &spi_qmspi_xec_driver_api); diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 8a7511dea38..27cb15f9079 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -720,7 +720,7 @@ reg = <0x40070000 0x400>; interrupts = <91 2>; girqs = < MCHP_XEC_ECIA(18, 1, 10, 91) >; - pcrs = <4 8>; + clocks = <&pcr 4 8 MCHP_XEC_PCR_CLK_PERIPH>; clock-frequency = <12000000>; lines = <1>; chip-select = <0>; diff --git a/dts/bindings/spi/microchip,xec-qmspi-full-duplex.yaml b/dts/bindings/spi/microchip,xec-qmspi-full-duplex.yaml deleted file mode 100644 index bc8ab321e5b..00000000000 --- a/dts/bindings/spi/microchip,xec-qmspi-full-duplex.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Google LLC. -# Copyright (c) 2022, Microchip Technology Inc. -# SPDX-License-Identifier: Apache-2.0 - -description: Microchip XEC QMSPI controller with local DMA - -compatible: "microchip,xec-qmspi-full-duplex" - -include: [microchip-xec-qmspi-v2.yaml] diff --git a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml index cc5baee22a0..7654612229a 100644 --- a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml +++ b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml @@ -6,4 +6,93 @@ description: Microchip XEC QMSPI controller with local DMA compatible: "microchip,xec-qmspi-ldma" -include: [microchip-xec-qmspi-v2.yaml] +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + clocks: + required: true + + interrupts: + required: true + + girqs: + type: array + required: true + description: | + An array of integers encoding each interrupt signal connection. + This information includes the aggregated GIRQ number, GIRQ bit + position, aggregated GIRQ NVIC connection, and direct NVIC + connection of the GIRQ bit. + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + lines: + type: int + description: | + QMSPI data lines 1, 2, or 4. 1 data line is full-duplex + MOSI and MISO or half-duplex on MOSI only. Lines set to 2 + or 4 indicate dual or quad I/O modes. + Defaults to 1 for full duplex driver's support for full-duplex spi. + enum: + - 1 + - 2 + - 4 + + chip-select: + type: int + description: | + Use QMSPI CS0# or CS1#. Port 0 supports both chip selects. + Ports 1 and 2 implement CS0# only. Defaults to CS0#. + + dcsckon: + type: int + description: | + Delay in QMSPI main clocks from CS# assertion to first clock edge. + If not present use hardware default value. Refer to chip documention + for QMSPI input clock frequency. + + dckcsoff: + type: int + description: | + Delay in QMSPI main clocks from last clock edge to CS# de-assertion. + If not present use hardware default value. Refer to chip documention + for QMSPI input clock frequency. + + dldh: + type: int + description: | + Delay in QMSPI main clocks from CS# de-assertion to driving HOLD# + and WP#. If not present use hardware default value. Refer to chip + documentation for QMSPI input clock frequency. + + dcsda: + type: int + description: | + Delay in QMSPI main clocks from CS# de-assertion to CS# assertion. + If not present use hardware default value. Refer to chip documention + for QMSPI input clock frequency. + + cs1-freq: + type: int + description: | + Allows different frequencies for CS#0 and CS1# devices. This applies + to ports implementing CS1#. + + tctradj: + type: int + description: | + An optional signed 8-bit value for adjusting the QMSPI control signal + timing tap. + + tsckadj: + type: int + description: | + An optional signed 8-bit value for adjusting the QMSPI clock signal + timing tap. diff --git a/dts/bindings/spi/microchip-xec-qmspi-v2.yaml b/dts/bindings/spi/microchip-xec-qmspi-v2.yaml deleted file mode 100644 index 940a6966e69..00000000000 --- a/dts/bindings/spi/microchip-xec-qmspi-v2.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2018, Google LLC. -# Copyright (c) 2022, Microchip Technology Inc. -# SPDX-License-Identifier: Apache-2.0 - -description: Microchip XEC QMSPI controller V2 - -include: [spi-controller.yaml, pinctrl-device.yaml] - -properties: - reg: - required: true - - girqs: - type: array - required: true - description: | - An array of integers encoding each interrupt signal connection. - This information includes the aggregated GIRQ number, GIRQ bit - position, aggregated GIRQ NVIC connection, and direct NVIC - connection of the GIRQ bit. - - pcrs: - type: array - required: true - description: | - A two entry integer array containing the QMSPI PCR sleep register - index and bit position. - - pinctrl-0: - required: true - - pinctrl-names: - required: true - - lines: - type: int - description: | - QMSPI data lines 1, 2, or 4. 1 data line is full-duplex - MOSI and MISO or half-duplex on MOSI only. Lines set to 2 - or 4 indicate dual or quad I/O modes. - Defaults to 1 for full duplex driver's support for full-duplex spi. - enum: - - 1 - - 2 - - 4 - - port-sel: - type: int - description: | - SPI Port 0, 1, or 2. Port 0 is the shared SPI, port 1 is - the private SPI, and port 2 is the internal SPI port for - chip configurations with an embedded SPI flash. Defaults - to port 0 (shared SPI port). - - chip-select: - type: int - description: | - Use QMSPI CS0# or CS1#. Port 0 supports both chip selects. - Ports 1 and 2 implement CS0# only. Defaults to CS0#. - - dcsckon: - type: int - description: | - Delay in QMSPI main clocks from CS# assertion to first clock edge. - If not present use hardware default value. Refer to chip documention - for QMSPI input clock frequency. - - dckcsoff: - type: int - description: | - Delay in QMSPI main clocks from last clock edge to CS# de-assertion. - If not presetn use hardware default value. Refer to chip documention - for QMSPI input clock frequency. - - dldh: - type: int - description: | - Delay in QMSPI main clocks from CS# de-assertion to driving HOLD# - and WP#. If not present use hardware default value. Refer to chip - documention for QMSPI input clock frequency. - - dcsda: - type: int - description: | - Delay in QMSPI main clocks from CS# de-assertion to CS# assertion. - If not present use hardware default value. Refer to chip documention - for QMSPI input clock frequency. - - cs1-freq: - type: int - description: | - Allows different frequencies for CS#0 and CS1# devices. This applies - to ports implementing CS1#. - - tctradj: - type: int - description: | - An optional signed 8-bit value for adjusting the QMSPI control signal - timing tap. - - tsckadj: - type: int - description: | - An optional signed 8-bit value for adjusting the QMSPI clock signal - timing tap. diff --git a/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf b/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf new file mode 100644 index 00000000000..38f06a0c0f8 --- /dev/null +++ b/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2022 Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/mec172xevb_assy6906.overlay b/samples/drivers/spi_flash/boards/mec172xevb_assy6906.overlay new file mode 100644 index 00000000000..f9fdc2e5368 --- /dev/null +++ b/samples/drivers/spi_flash/boards/mec172xevb_assy6906.overlay @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + spi-flash0 = &spi1_cs0_flash; + }; +}; + +&spi0 { + status = "okay"; + compatible = "microchip,xec-qmspi-ldma"; + clock-frequency = <24000000>; + lines = <4>; + chip-select = <0>; + + pinctrl-0 = < &shd_cs0_n_gpio055 + &shd_clk_gpio056 + &shd_io0_gpio223 + &shd_io1_gpio224 + &shd_io2_gpio227 + &shd_io3_gpio016 >; + pinctrl-names = "default"; + + spi1_cs0_flash: w25q128@0 { + compatible = "jedec,spi-nor"; + /* 134217728 bits = 16 Mbytes */ + size = <0x8000000>; + reg = <0>; + spi-max-frequency = <24000000>; + jedec-id = [ef 40 18]; + status = "okay"; + }; +}; + +&shd_cs0_n_gpio055 { + drive-open-drain; + output-high; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/mec172xevb_assy6906.overlay b/tests/drivers/spi/spi_loopback/boards/mec172xevb_assy6906.overlay new file mode 100644 index 00000000000..4a28ac24706 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mec172xevb_assy6906.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi0 { + status = "okay"; + compatible = "microchip,xec-qmspi-ldma"; + clock-frequency = <12000000>; + lines = <1>; + chip-select = <0>; + + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <500000>; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <16000000>; + }; +};