You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by da...@apache.org on 2020/03/19 12:59:26 UTC
[incubator-nuttx] branch master updated: stm32h7_qspi: support for
custom clock (not just HCLK) and support for DUAL/QUAD commands (#582)
This is an automated email from the ASF dual-hosted git repository.
davids5 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 73b655f stm32h7_qspi: support for custom clock (not just HCLK) and support for DUAL/QUAD commands (#582)
73b655f is described below
commit 73b655f3b2cee52e3fc2227ec18cac9755828f4b
Author: Andrey Zabolotnyi <za...@ya.ru>
AuthorDate: Thu Mar 19 15:59:18 2020 +0300
stm32h7_qspi: support for custom clock (not just HCLK) and support for DUAL/QUAD commands (#582)
* stm32h7_qspi: Board.h now may define the BOARD_QSPI_CLK macro to select one of
RCC_D1CCIPR_QSPISEL_{HCLK,PLL1,PLL2,PER} clocks to use with QUADSPI peripherial.
Defaults to HCLK for backward compatibility.
New macros in qspi.h: QSPICMD_IDUAL and QSPICMD_IQUAD for selecting the bit
width for instruction code (1,2 or 4 bits) of a qspi_cmdinfo_s, and
QSPIMEM_IDUAL and QSPIMEM_IQUAD for selecting the bit width of a qspi_meminfo_s.
* NX style fixes
---
arch/arm/src/stm32h7/stm32_qspi.c | 123 ++++++++++++++++++++++++++++----------
include/nuttx/spi/qspi.h | 11 +++-
2 files changed, 101 insertions(+), 33 deletions(-)
diff --git a/arch/arm/src/stm32h7/stm32_qspi.c b/arch/arm/src/stm32h7/stm32_qspi.c
index 8b828d4..05c1be5 100644
--- a/arch/arm/src/stm32h7/stm32_qspi.c
+++ b/arch/arm/src/stm32h7/stm32_qspi.c
@@ -159,11 +159,35 @@
/* Clocking *****************************************************************/
+/* The board.h file may choose a different clock source for QUADSPI
+ * peripherial by defining the BOARD_QSPI_CLK macro to one of the
+ * RCC_D1CCIPR_QSPISEL_XXX values (XXX = HCLK, PLL1, PLL2, PER).
+ * QUADSPI clock defaults to HCLK.
+ */
+
+#ifndef BOARD_QSPI_CLK
+/* Clock QUADSPI from HCLK by default */
+
+# define BOARD_QSPI_CLK RCC_D1CCIPR_QSPISEL_HCLK
+#endif
+
/* The QSPI bit rate clock is generated by dividing the peripheral clock by
- * a value between 1 and 255
+ * a value between 1 and 255.
+ *
+ * Find out the frequency of the QSPI clock.
*/
-#define STL32F7_QSPI_CLOCK STM32_SYSCLK_FREQUENCY /* Frequency of the QSPI clock */
+#if BOARD_QSPI_CLK == RCC_D1CCIPR_QSPISEL_HCLK
+# define QSPI_CLK_FREQUENCY STM32_HCLK_FREQUENCY
+#elif BOARD_QSPI_CLK == RCC_D1CCIPR_QSPISEL_PLL1
+# define QSPI_CLK_FREQUENCY STM32_PLL1Q_FREQUENCY
+#elif BOARD_QSPI_CLK == RCC_D1CCIPR_QSPISEL_PLL2
+# define QSPI_CLK_FREQUENCY STM32_PLL2R_FREQUENCY
+#elif BOARD_QSPI_CLK == RCC_D1CCIPR_QSPISEL_PER
+# define QSPI_CLK_FREQUENCY STM32_PER_FREQUENCY
+#else
+# error "BOARD_QSPI_CLK has unknown value!"
+#endif
/****************************************************************************
* Private Types
@@ -268,8 +292,8 @@ static bool qspi_checkreg(struct stm32h7_qspidev_s *priv, bool wr,
static inline uint32_t qspi_getreg(struct stm32h7_qspidev_s *priv,
unsigned int offset);
-static inline void qspi_putreg(struct stm32h7_qspidev_s *priv, uint32_t value,
- unsigned int offset);
+static inline void qspi_putreg(struct stm32h7_qspidev_s *priv,
+ uint32_t value, unsigned int offset);
#ifdef CONFIG_DEBUG_SPI_INFO
static void qspi_dumpregs(struct stm32h7_qspidev_s *priv,
@@ -314,7 +338,8 @@ static void qspi_dma_sampledone(struct stm32h7_qspidev_s *priv);
/* QSPI methods */
static int qspi_lock(struct qspi_dev_s *dev, bool lock);
-static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency);
+static uint32_t qspi_setfrequency(struct qspi_dev_s *dev,
+ uint32_t frequency);
static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode);
static void qspi_setbits(struct qspi_dev_s *dev, int nbits);
static int qspi_command(struct qspi_dev_s *dev,
@@ -455,8 +480,8 @@ static inline uint32_t qspi_getreg(struct stm32h7_qspidev_s *priv,
*
****************************************************************************/
-static inline void qspi_putreg(struct stm32h7_qspidev_s *priv, uint32_t value,
- unsigned int offset)
+static inline void qspi_putreg(struct stm32h7_qspidev_s *priv,
+ uint32_t value, unsigned int offset)
{
uint32_t address = priv->base + offset;
@@ -493,7 +518,7 @@ static void qspi_dumpregs(struct stm32h7_qspidev_s *priv, const char *msg)
#if 0
/* this extra verbose output may be helpful in some cases; you'll need
- * to make sure your syslog is large enough to accommodate the extra output.
+ * to make sure your syslog is large enough to accommodate extra output.
*/
regval = getreg32(priv->base + STM32_QUADSPI_CR_OFFSET); /* Control Register */
@@ -773,7 +798,19 @@ static int qspi_setupxctnfromcmd(struct qspi_xctnspec_s *xctn,
/* XXX III instruction mode, single dual quad option bits */
- xctn->instrmode = CCR_IMODE_SINGLE;
+ if (QSPICMD_ISIQUAD(cmdinfo->flags))
+ {
+ xctn->instrmode = CCR_IMODE_QUAD;
+ }
+ else if (QSPICMD_ISIDUAL(cmdinfo->flags))
+ {
+ xctn->instrmode = CCR_IMODE_DUAL;
+ }
+ else
+ {
+ xctn->instrmode = CCR_IMODE_SINGLE;
+ }
+
xctn->instr = cmdinfo->cmd;
/* XXX III option bits for 'send instruction only once' */
@@ -881,7 +918,8 @@ static int qspi_setupxctnfrommem(struct qspi_xctnspec_s *xctn,
spiinfo(" cmd: %04x\n", meminfo->cmd);
spiinfo(" address/length: %08lx/%d\n",
(unsigned long)meminfo->addr, meminfo->addrlen);
- spiinfo(" %s Data:\n", QSPIMEM_ISWRITE(meminfo->flags) ? "Write" : "Read");
+ spiinfo(" %s Data:\n", QSPIMEM_ISWRITE(meminfo->flags) ?
+ "Write" : "Read");
spiinfo(" buffer/length: %p/%d\n", meminfo->buffer, meminfo->buflen);
#endif
@@ -891,7 +929,19 @@ static int qspi_setupxctnfrommem(struct qspi_xctnspec_s *xctn,
/* XXX III instruction mode, single dual quad option bits */
- xctn->instrmode = CCR_IMODE_SINGLE;
+ if (QSPIMEM_ISIQUAD(meminfo->flags))
+ {
+ xctn->instrmode = CCR_IMODE_QUAD;
+ }
+ else if (QSPIMEM_ISIDUAL(meminfo->flags))
+ {
+ xctn->instrmode = CCR_IMODE_DUAL;
+ }
+ else
+ {
+ xctn->instrmode = CCR_IMODE_SINGLE;
+ }
+
xctn->instr = meminfo->cmd;
/* XXX III option bits for 'send instruction only once' */
@@ -1008,11 +1058,13 @@ static void qspi_waitstatusflags(struct stm32h7_qspidev_s *priv,
if (polarity)
{
- while (!((regval = qspi_getreg(priv, STM32_QUADSPI_SR_OFFSET)) & mask));
+ while (!((regval = qspi_getreg(priv, STM32_QUADSPI_SR_OFFSET)) & mask))
+ ;
}
else
{
- while (((regval = qspi_getreg(priv, STM32_QUADSPI_SR_OFFSET)) & mask));
+ while (((regval = qspi_getreg(priv, STM32_QUADSPI_SR_OFFSET)) & mask))
+ ;
}
}
@@ -1137,13 +1189,14 @@ static int qspi0_interrupt(int irq, void *context, FAR void *arg)
{
/* Write data until we have no more or have no place to put it */
- while (((regval = qspi_getreg(&g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) &
- QSPI_SR_FTF) != 0)
+ while (((regval = qspi_getreg(
+ &g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) & QSPI_SR_FTF) != 0)
{
if (g_qspi0dev.xctn->idxnow < g_qspi0dev.xctn->datasize)
{
*(volatile uint8_t *)datareg =
- ((uint8_t *)g_qspi0dev.xctn->buffer)[g_qspi0dev.xctn->idxnow];
+ ((uint8_t *)g_qspi0dev.xctn->buffer)
+ [g_qspi0dev.xctn->idxnow];
++g_qspi0dev.xctn->idxnow;
}
else
@@ -1158,13 +1211,13 @@ static int qspi0_interrupt(int irq, void *context, FAR void *arg)
{
/* Read data until we have no more or have no place to put it */
- while (((regval = qspi_getreg(&g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) &
- QSPI_SR_FTF) != 0)
+ while (((regval = qspi_getreg(
+ &g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) & QSPI_SR_FTF) != 0)
{
if (g_qspi0dev.xctn->idxnow < g_qspi0dev.xctn->datasize)
{
- ((uint8_t *)g_qspi0dev.xctn->buffer)[g_qspi0dev.xctn->idxnow] =
- *(volatile uint8_t *)datareg;
+ ((uint8_t *)g_qspi0dev.xctn->buffer)
+ [g_qspi0dev.xctn->idxnow] = *(volatile uint8_t *)datareg;
++g_qspi0dev.xctn->idxnow;
}
else
@@ -1202,13 +1255,14 @@ static int qspi0_interrupt(int irq, void *context, FAR void *arg)
/* Read any remaining data */
- while (((regval = qspi_getreg(&g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) &
+ while (((regval = qspi_getreg(
+ &g_qspi0dev, STM32_QUADSPI_SR_OFFSET)) &
QSPI_SR_FLEVEL_MASK) != 0)
{
if (g_qspi0dev.xctn->idxnow < g_qspi0dev.xctn->datasize)
{
- ((uint8_t *)g_qspi0dev.xctn->buffer)[g_qspi0dev.xctn->idxnow] =
- *(volatile uint8_t *)datareg;
+ ((uint8_t *)g_qspi0dev.xctn->buffer)
+ [g_qspi0dev.xctn->idxnow] = *(volatile uint8_t *)datareg;
++g_qspi0dev.xctn->idxnow;
}
else
@@ -1831,8 +1885,8 @@ static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency)
/* Configure QSPI to a frequency as close as possible to the requested
* frequency.
*
- * QSCK frequency = STL32F7_QSPI_CLOCK / prescaler, or
- * prescaler = STL32F7_QSPI_CLOCK / frequency
+ * QSCK frequency = QSPI_CLK_FREQUENCY / prescaler, or
+ * prescaler = QSPI_CLK_FREQUENCY / frequency
*
* Where prescaler can have the range 1 to 256 and the
* STM32_QUADSPI_CR_OFFSET register field holds prescaler - 1.
@@ -1840,7 +1894,7 @@ static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency)
* 'frequency' is treated as a not-to-exceed value.
*/
- prescaler = (frequency + STL32F7_QSPI_CLOCK - 1) / frequency;
+ prescaler = (frequency + QSPI_CLK_FREQUENCY - 1) / frequency;
/* Make sure that the divider is within range */
@@ -1862,7 +1916,7 @@ static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency)
/* Calculate the new actual frequency */
- actual = STL32F7_QSPI_CLOCK / prescaler;
+ actual = QSPI_CLK_FREQUENCY / prescaler;
spiinfo("prescaler=%d actual=%d\n", prescaler, actual);
/* Save the frequency setting */
@@ -2049,8 +2103,8 @@ static int qspi_command(struct qspi_dev_s *dev,
qspi_ccrconfig(priv, &xctn, CCR_FMODE_INDWR);
- /* Enable 'Transfer Error' 'FIFO Threshhold' and 'Transfer Complete'
- * interrupts.
+ /* Enable 'Transfer Error' 'FIFO Threshhold' and
+ * 'Transfer Complete' interrupts.
*/
regval = qspi_getreg(priv, STM32_QUADSPI_CR_OFFSET);
@@ -2074,8 +2128,8 @@ static int qspi_command(struct qspi_dev_s *dev,
qspi_putreg(priv, addrval, STM32_QUADSPI_AR_OFFSET);
- /* Enable 'Transfer Error' 'FIFO Threshhold' and 'Transfer Complete'
- * interrupts
+ /* Enable 'Transfer Error' 'FIFO Threshhold' and
+ * 'Transfer Complete' interrupts
*/
regval = qspi_getreg(priv, STM32_QUADSPI_CR_OFFSET);
@@ -2444,7 +2498,8 @@ static int qspi_hw_initialize(struct stm32h7_qspidev_s *priv)
/* Configure QSPI FIFO Threshold */
regval &= ~(QSPI_CR_FTHRES_MASK);
- regval |= ((CONFIG_STM32H7_QSPI_FIFO_THESHOLD - 1) << QSPI_CR_FTHRES_SHIFT);
+ regval |= ((CONFIG_STM32H7_QSPI_FIFO_THESHOLD - 1) <<
+ QSPI_CR_FTHRES_SHIFT);
qspi_putreg(priv, regval, STM32_QUADSPI_CR_OFFSET);
/* Wait till BUSY flag reset */
@@ -2538,6 +2593,10 @@ struct qspi_dev_s *stm32h7_qspi_initialize(int intf)
priv = &g_qspi0dev;
+ /* Select QSPI clock source */
+
+ modreg32 (BOARD_QSPI_CLK, RCC_D1CCIPR_QSPISEL_MASK, STM32_RCC_D1CCIPR);
+
/* Enable clocking to the QSPI peripheral */
regval = getreg32(STM32_RCC_AHB3ENR);
diff --git a/include/nuttx/spi/qspi.h b/include/nuttx/spi/qspi.h
index 9cc86dd..f6a081d 100644
--- a/include/nuttx/spi/qspi.h
+++ b/include/nuttx/spi/qspi.h
@@ -49,6 +49,7 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+
/* Access macros ************************************************************/
/****************************************************************************
@@ -149,11 +150,15 @@
#define QSPICMD_ADDRESS (1 << 0) /* Bit 0: Enable address transfer */
#define QSPICMD_READDATA (1 << 1) /* Bit 1: Enable read data transfer */
#define QSPICMD_WRITEDATA (1 << 2) /* Bit 2: Enable write data transfer */
+#define QSPICMD_IDUAL (1 << 3) /* Bit 3: Instruction on two lines */
+#define QSPICMD_IQUAD (1 << 4) /* Bit 4: Instruction on four lines */
#define QSPICMD_ISADDRESS(f) (((f) & QSPICMD_ADDRESS) != 0)
#define QSPICMD_ISDATA(f) (((f) & (QSPICMD_READDATA | QSPICMD_WRITEDATA)) != 0)
#define QSPICMD_ISREAD(f) (((f) & QSPICMD_READDATA) != 0)
#define QSPICMD_ISWRITE(f) (((f) & QSPICMD_WRITEDATA) != 0)
+#define QSPICMD_ISIDUAL(f) (((f) & QSPICMD_IDUAL) != 0)
+#define QSPICMD_ISIQUAD(f) (((f) & QSPICMD_IQUAD) != 0)
/****************************************************************************
* Name: QSPI_MEMORY
@@ -180,12 +185,16 @@
#define QSPIMEM_QUADIO (1 << 4) /* Bit 4: Use Quad I/O (READ only) */
#define QSPIMEM_SCRAMBLE (1 << 5) /* Bit 5: Scramble data */
#define QSPIMEM_RANDOM (1 << 6) /* Bit 6: Use random key in scrambler */
+#define QSPIMEM_IDUAL (1 << 7) /* Bit 7: Instruction on two lines */
+#define QSPIMEM_IQUAD (1 << 0) /* Bit 0: Instruction on four lines */
#define QSPIMEM_ISREAD(f) (((f) & QSPIMEM_WRITE) == 0)
#define QSPIMEM_ISWRITE(f) (((f) & QSPIMEM_WRITE) != 0)
#define QSPIMEM_ISDUALIO(f) (((f) & QSPIMEM_DUALIO) != 0)
#define QSPIMEM_ISQUADIO(f) (((f) & QSPIMEM_QUADIO) != 0)
#define QSPIMEM_ISSCRAMBLE(f) (((f) & QSPIMEM_SCRAMBLE) != 0)
+#define QSPIMEM_ISIDUAL(f) (((f) & QSPIMEM_IDUAL) != 0)
+#define QSPIMEM_ISIQUAD(f) (((f) & QSPIMEM_IQUAD) != 0)
#define QSPIMEM_ISRANDOM(f) \
(((f) & (QSPIMEM_SCRAMBLE|QSPIMEM_RANDOM)) == \
@@ -309,7 +318,7 @@ extern "C"
#endif
/****************************************************************************
- * Public Functions
+ * Public Function Prototypes
****************************************************************************/
#undef EXTERN