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