From 097634351365b480ba1f64f6afff47c660520dd3 Mon Sep 17 00:00:00 2001 From: Jay Vasanth Date: Tue, 19 Apr 2022 18:13:59 -0400 Subject: [PATCH] drivers: SPI: MEC172x QMSPI clock fix Microchip MEC172x QMSPI expanded its clock divider register field from 8 to 16 bits. QMSPI source clock is on the fast peripheral domain therefore get the frequency from the clock control driver. Signed-off-by: Jay Vasanth --- drivers/spi/spi_xec_qmspi_ldma.c | 70 +++++++++++++------ dts/arm/microchip/mec172xnsz.dtsi | 1 + .../microchip_mec/mec172x/reg/mec172x_qspi.h | 5 +- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi_xec_qmspi_ldma.c b/drivers/spi/spi_xec_qmspi_ldma.c index 0a7aaa5b697d39..629549d24eb577 100644 --- a/drivers/spi/spi_xec_qmspi_ldma.c +++ b/drivers/spi/spi_xec_qmspi_ldma.c @@ -29,6 +29,8 @@ LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); #include #endif +/* common clock control device node for all Microchip XEC chips */ +#define MCHP_XEC_CLOCK_CONTROL_NODE DT_NODELABEL(pcr) /* spin loops waiting for HW to clear soft reset bit */ #define XEC_QMSPI_SRST_LOOPS 16 @@ -91,6 +93,7 @@ struct spi_qmspi_config { /* Device run time data */ struct spi_qmspi_data { struct spi_context ctx; + uint32_t base_freq_hz; uint32_t qstatus; uint8_t np; /* number of data pins: 1, 2, or 4 */ uint8_t *pd; @@ -159,36 +162,42 @@ static void qmspi_reset(struct qmspi_regs *regs) regs->TM_TAPS_CTRL = taps[2]; } -/* - * Calculate 8-bit QMSPI frequency divider register field value. - * QMSPI input clock is MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ. - * The 8-bit divider is encoded as: - * 0 is divide by 256 - * 1 through 255 is divide by this value. - */ -static uint32_t qmspi_encoded_fdiv(uint32_t freq_hz) +static uint32_t qmspi_encoded_fdiv(const struct device *dev, uint32_t freq_hz) { - uint32_t fdiv = 1; + struct spi_qmspi_data *qdata = dev->data; - if (freq_hz < (MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ / 256u)) { - fdiv = 0; /* HW fdiv of 0 -> divide by 256 */ - } else if (freq_hz < MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ) { - fdiv = MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ / freq_hz; + if (freq_hz == 0u) { + return 0u; /* maximum frequency divider */ } - return fdiv; + return (qdata->base_freq_hz / freq_hz); } -/* Program QMSPI frequency divider field in mode register */ -static void qmspi_set_frequency(struct qmspi_regs *regs, uint32_t freq_hz) +/* Program QMSPI frequency divider field in the mode register. + * MEC172x QMSPI input clock source is the Fast Peripheral domain whose + * clock is controlled by the PCR turbo clock. 96 MHz if turbo mode + * enabled else 48 MHz. Query the clock control driver to get clock + * rate of fast peripheral domain. MEC172x QMSPI clock divider has + * been expanded to a 16-bit field encoded as: + * 0 = divide by 0x10000 + * 1 to 0xffff = divide by this value. + */ +static int qmspi_set_frequency(struct qmspi_regs *regs, uint32_t freq_hz) { - uint32_t fdiv, qmode; + 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; + + if (!clock_control_get_rate(DEVICE_DT_GET(MCHP_XEC_CLOCK_CONTROL_NODE), + (clock_control_subsys_t)clkss, &clk)) { + fdiv = clk / freq_hz; + } - fdiv = qmspi_encoded_fdiv(freq_hz); + regs->MODE = ((regs->MODE & ~(MCHP_QMSPI_M_FDIV_MASK)) | + ((fdiv << MCHP_QMSPI_M_FDIV_POS) & MCHP_QMSPI_M_FDIV_MASK)); - qmode = regs->MODE & ~(MCHP_QMSPI_M_FDIV_MASK); - qmode |= (fdiv << MCHP_QMSPI_M_FDIV_POS) & MCHP_QMSPI_M_FDIV_MASK; - regs->MODE = qmode; + return 0; } /* @@ -365,7 +374,7 @@ static int qmspi_configure(const struct device *dev, /* CS1 alternate mode (frequency) */ regs->MODE_ALT1 = 0; if (cfg->cs1_freq) { - uint32_t fdiv = qmspi_encoded_fdiv(cfg->cs1_freq); + uint32_t fdiv = qmspi_encoded_fdiv(dev, cfg->cs1_freq); regs->MODE_ALT1 = (fdiv << MCHP_QMSPI_MA1_CS1_CDIV_POS) & MCHP_QMSPI_MA1_CS1_CDIV_MSK; @@ -1088,7 +1097,12 @@ 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); + + qdata->base_freq_hz = 0u; qdata->qstatus = 0; qdata->np = cfg->width; #ifdef CONFIG_SPI_ASYNC @@ -1098,6 +1112,11 @@ static int qmspi_xec_init(const struct device *dev) qdata->xfr_len = 0; #endif + if (!device_is_ready(pcr_dev)) { + LOG_ERR("%s PCR device not ready", pcr_dev->name); + return -ENODEV; + } + z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0); ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); @@ -1106,6 +1125,13 @@ static int qmspi_xec_init(const struct device *dev) return ret; } + ret = clock_control_get_rate(pcr_dev, (clock_control_subsys_t)clkss, + &qdata->base_freq_hz); + if (ret) { + LOG_ERR("QSPI clock control failed"); + return ret; + } + qmspi_reset(regs); mchp_xec_ecia_girq_src_clr(cfg->girq, cfg->girq_pos); diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 51f077a14ce498..c12155435c29a2 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -694,6 +694,7 @@ interrupts = <91 2>; girqs = < MCHP_XEC_ECIA(18, 1, 10, 91) >; pcrs = <4 8>; + clocks = <&pcr 1 0>; clock-frequency = <12000000>; lines = <1>; chip-select = <0>; diff --git a/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h b/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h index cb2be6eed421b2..496c0f5238c861 100644 --- a/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h +++ b/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h @@ -168,8 +168,8 @@ #define MCHP_QMSPI_M_CS(n) \ (((uint32_t)(n) & MCHP_QMSPI_M_CS_MASK0) << MCHP_QMSPI_M_CS_POS) #define MCHP_QMSPI_M_FDIV_POS 16u -#define MCHP_QMSPI_M_FDIV_MASK0 0xffu -#define MCHP_QMSPI_M_FDIV_MASK 0x00ff0000u +#define MCHP_QMSPI_M_FDIV_MASK0 0xffffu +#define MCHP_QMSPI_M_FDIV_MASK 0xffff0000u /* Control/Descriptors */ #define MCHP_QMSPI_C_IFM_MASK 0x03u @@ -197,6 +197,7 @@ #define MCHP_QMSPI_C_RX_DMA_1B SHLU32(1u, MCHP_QMSPI_C_RX_DMA_POS) #define MCHP_QMSPI_C_RX_DMA_2B SHLU32(2u, MCHP_QMSPI_C_RX_DMA_POS) #define MCHP_QMSPI_C_RX_DMA_4B SHLU32(3u, MCHP_QMSPI_C_RX_DMA_POS) + #define MCHP_QMSPI_C_CLOSE_POS 9u #define MCHP_QMSPI_C_NO_CLOSE 0u #define MCHP_QMSPI_C_CLOSE BIT(MCHP_QMSPI_C_CLOSE_POS)