From 6483a05d1408d56b0d8a4c173c3d9967cfc03e74 Mon Sep 17 00:00:00 2001
From: Giovanni Di Sirio <gdisirio@gmail.com>
Date: Sat, 14 May 2016 09:42:48 +0000
Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9480
 35acf78f-673a-0410-8e92-d51de3d6d3f4

---
 os/hal/include/hal_qspi.h                       | 30 +++++++++--
 os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c | 68 +++++++++++++++++------
 os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h | 11 ++++
 os/hal/ports/STM32/STM32L4xx/stm32_registry.h   |  3 +-
 os/hal/src/hal_qspi.c                           | 71 +++++++++++++++++++------
 5 files changed, 146 insertions(+), 37 deletions(-)

diff --git a/os/hal/include/hal_qspi.h b/os/hal/include/hal_qspi.h
index 498fedec7..0fe1e79fb 100644
--- a/os/hal/include/hal_qspi.h
+++ b/os/hal/include/hal_qspi.h
@@ -69,11 +69,6 @@
 #define QSPI_CFG_DATA_MODE_ONE_LINE         (1U << 24U)
 #define QSPI_CFG_DATA_MODE_TWO_LINES        (2U << 24U)
 #define QSPI_CFG_DATA_MODE_FOUR_LINES       (3U << 24U)
-#define QSPI_CFG_F_MODE_MASK                (3U << 26U)
-#define QSPI_CFG_F_MODE_INDIRECT_WRITE      (0U << 26U)
-#define QSPI_CFG_F_MODE_INDIRECT_READ       (1U << 26U)
-#define QSPI_CFG_F_MODE_MEMORY_MAPPED       (2U << 26U)
-#define QSPI_CFG_F_MODE_FOUR_LINES          (3U << 26U)
 #define QSPI_CFG_SIOO                       (1U << 28U)
 #define QSPI_CFG_DDRM                       (1U << 31U)
 /** @} */
@@ -141,6 +136,23 @@ typedef struct {
  * @name    Macro Functions
  * @{
  */
+/**
+ * @brief   Sends a command without data phase.
+ * @post    At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip     pointer to the @p QSPIDriver object
+ * @param[in] cmd       pointer to the command descriptor
+ *
+ * @iclass
+ */
+#define qspiCommandI(qspip, cmd) {                                          \
+  osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) ==                   \
+                QSPI_CFG_DATA_MODE_NONE,                                    \
+                "data mode specified");                                     \
+  (qspip)->state = QSPI_ACTIVE;                                             \
+  qspi_lld_command(qspip, cmd, n, txbuf);                                   \
+}
+
 /**
  * @brief   Sends data over the QSPI bus.
  * @details This asynchronous function starts a transmit operation.
@@ -154,6 +166,9 @@ typedef struct {
  * @iclass
  */
 #define qspiStartSendI(qspip, cmd, n, txbuf) {                              \
+  osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) !=                   \
+                QSPI_CFG_DATA_MODE_NONE,                                    \
+                "data mode required");                                      \
   (qspip)->state = QSPI_ACTIVE;                                             \
   qspi_lld_send(qspip, cmd, n, txbuf);                                      \
 }
@@ -171,6 +186,9 @@ typedef struct {
  * @iclass
  */
 #define qspiStartReceiveI(qspip, cmd, n, rxbuf) {                           \
+  osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) !=                   \
+                QSPI_CFG_DATA_MODE_NONE,                                    \
+                "data mode required");                                      \
   (qspip)->state = QSPI_ACTIVE;                                             \
   qspi_lld_receive(qspip, cmd, n, rxbuf);                                   \
 }
@@ -235,11 +253,13 @@ extern "C" {
   void qspiObjectInit(QSPIDriver *qspip);
   void qspiStart(QSPIDriver *qspip, const QSPIConfig *config);
   void qspiStop(QSPIDriver *qspip);
+  void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp);
   void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
                      size_t n, const uint8_t *txbuf);
   void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
                         size_t n, uint8_t *rxbuf);
 #if QSPI_USE_WAIT == TRUE
+  void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp);
   void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
                 size_t n, const uint8_t *txbuf);
   void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
index 4f4036a15..d395e0b43 100644
--- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
+++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
@@ -123,21 +123,29 @@ void qspi_lld_init(void) {
  */
 void qspi_lld_start(QSPIDriver *qspip) {
 
-  /* If in stopped state then enables the QUADSPI and DMA clocks.*/
+  /* If in stopped state then full initialization.*/
   if (qspip->state == QSPI_STOP) {
 #if STM32_QSPI_USE_QUADSPI1
     if (&QSPID1 == qspip) {
-      rccEnableQUADSPI1(FALSE);
+      bool b = dmaStreamAllocate(qspip->dma,
+                                 STM32_QSPI_QUADSPI1_IRQ_PRIORITY,
+                                 (stm32_dmaisr_t)qspi_lld_serve_dma_interrupt,
+                                 (void *)qspip);
+      osalDbgAssert(!b, "stream already allocated");
+      rccEnableQUADSPI1(false);
     }
 #endif
+
+    /* Common initializations.*/
+    dmaStreamSetPeripheral(qspip->dma, &qspip->qspi->DR);
   }
 
   /* QSPI setup and enable.*/
-//  spip->spi->CR1  = 0;
-//  spip->spi->CR1  = spip->config->cr1 | SPI_CR1_MSTR;
-//  spip->spi->CR2  = spip->config->cr2 | SPI_CR2_FRXTH | SPI_CR2_SSOE |
-//                    SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
-//  spip->spi->CR1 |= SPI_CR1_SPE;
+  qspip->qspi->CR  = ((STM32_QSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) |
+                      QUADSPI_CR_TCIE | QUADSPI_CR_TEIE | QUADSPI_CR_DMAEN |
+                      QUADSPI_CR_EN;
+  qspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF |
+                     QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF;
 }
 
 /**
@@ -153,10 +161,12 @@ void qspi_lld_stop(QSPIDriver *qspip) {
   if (qspip->state == QSPI_READY) {
 
     /* QSPI disable.*/
-//    spip->spi->CR1 = 0;
-//    spip->spi->CR2 = 0;
+    qspip->qspi->CR = 0U;
+
+    /* Releasing the DMA.*/
     dmaStreamRelease(qspip->dma);
 
+    /* Stopping involved clocks.*/
 #if STM32_QSPI_USE_QUADSPI1
     if (&QSPID1 == qspip) {
       rccDisableQUADSPI1(FALSE);
@@ -166,13 +176,32 @@ void qspi_lld_stop(QSPIDriver *qspip) {
 }
 
 /**
- * @brief   Sends data over the QSPI bus.
- * @details This asynchronous function starts a transmit operation.
+ * @brief   Sends a command without data phase.
  * @post    At the end of the operation the configured callback is invoked.
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to send
+ *
+ * @notapi
+ */
+void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp) {
+
+  qspip->qspi->CCR = cmdp->cfg;
+  if ((cmdp->cfg & QSPI_CFG_ALT_MODE_MASK) != QSPI_CFG_ALT_MODE_NONE) {
+    qspip->qspi->ABR = cmdp->alt;
+  }
+  if ((cmdp->cfg & QSPI_CFG_ADDR_MODE_MASK) != QSPI_CFG_ADDR_MODE_NONE) {
+    qspip->qspi->AR  = cmdp->addr;
+  }
+}
+
+/**
+ * @brief   Sends a command with data over the QSPI bus.
+ * @post    At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip     pointer to the @p QSPIDriver object
+ * @param[in] cmd       pointer to the command descriptor
+ * @param[in] n         number of bytes to send
  * @param[in] txbuf     the pointer to the transmit buffer
  *
  * @notapi
@@ -184,17 +213,21 @@ void qspi_lld_send(QSPIDriver *qspip, const qspi_command_t *cmdp,
   dmaStreamSetTransactionSize(qspip->dma, n);
   dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_M2P);
 
+  qspip->qspi->DLR = n - 1;
+  qspip->qspi->ABR = cmdp->alt;
+  qspip->qspi->CCR = cmdp->cfg;
+  qspip->qspi->AR  = cmdp->addr;
+
   dmaStreamEnable(qspip->dma);
 }
 
 /**
- * @brief   Receives data from the QSPI bus.
- * @details This asynchronous function starts a receive operation.
+ * @brief   Sends a command then receives data over the QSPI bus.
  * @post    At the end of the operation the configured callback is invoked.
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to receive
+ * @param[in] n         number of bytes to send
  * @param[out] rxbuf    the pointer to the receive buffer
  *
  * @notapi
@@ -206,6 +239,11 @@ void qspi_lld_receive(QSPIDriver *qspip, const qspi_command_t *cmdp,
   dmaStreamSetTransactionSize(qspip->dma, n);
   dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_P2M);
 
+  qspip->qspi->DLR = n - 1;
+  qspip->qspi->ABR = cmdp->alt;
+  qspip->qspi->CCR = cmdp->cfg | QUADSPI_CCR_FMODE_0;
+  qspip->qspi->AR  = cmdp->addr;
+
   dmaStreamEnable(qspip->dma);
 }
 
diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
index 14dc01b2f..100572dfc 100644
--- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
+++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
@@ -48,6 +48,16 @@
 #define STM32_QSPI_USE_QUADSPI1             FALSE
 #endif
 
+/**
+ * @brief   QUADSPI1 prescaler setting.
+ * @note    This is the prescaler divider value 1..256. The maximum frequency
+ *          varies depending on the STM32 model and operating conditions,
+ *          find the details in the data sheet.
+ */
+#if !defined(STM32_QSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__)
+#define STM32_QSPI_QUADSPI1_PRESCALER_VALUE 4
+#endif
+
 /**
  * @brief   QUADSPI1 interrupt priority level setting.
  */
@@ -199,6 +209,7 @@ extern "C" {
   void qspi_lld_init(void);
   void qspi_lld_start(QSPIDriver *qspip);
   void qspi_lld_stop(QSPIDriver *qspip);
+  void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp);
   void qspi_lld_send(QSPIDriver *qspip, const qspi_command_t *cmdp,
                      size_t n, const uint8_t *txbuf);
   void qspi_lld_receive(QSPIDriver *qspip, const qspi_command_t *cmdp,
diff --git a/os/hal/ports/STM32/STM32L4xx/stm32_registry.h b/os/hal/ports/STM32/STM32L4xx/stm32_registry.h
index a1474a5c4..09de989ca 100644
--- a/os/hal/ports/STM32/STM32L4xx/stm32_registry.h
+++ b/os/hal/ports/STM32/STM32L4xx/stm32_registry.h
@@ -211,7 +211,8 @@
 
 /* QUADSPI attributes.*/
 #define STM32_HAS_QUADSPI1                  TRUE
-#define STM32_QUADSPI1_DMA_MSK              (STM32_DMA_STREAM_ID_MSK(2, 7))
+#define STM32_QUADSPI1_DMA_MSK              (STM32_DMA_STREAM_ID_MSK(1, 5) |\
+                                             STM32_DMA_STREAM_ID_MSK(2, 7))
 #define STM32_QUADSPI1_DMA_CHN              0x03000000
 
 /* RTC attributes.*/
diff --git a/os/hal/src/hal_qspi.c b/os/hal/src/hal_qspi.c
index 3070eeb66..6fdb0c3a0 100644
--- a/os/hal/src/hal_qspi.c
+++ b/os/hal/src/hal_qspi.c
@@ -123,13 +123,31 @@ void qspiStop(QSPIDriver *qspip) {
 }
 
 /**
- * @brief   Sends data over the QSPI bus.
- * @details This asynchronous function starts a transmit operation.
+ * @brief   Sends a command without data phase.
  * @post    At the end of the operation the configured callback is invoked.
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to send or zero if no data phase
+ *
+ * @api
+ */
+void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) {
+
+  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
+
+  osalSysLock();
+  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+  qspiStartCommandI(qspip, cmd);
+  osalSysUnlock();
+}
+
+/**
+ * @brief   Sends a command with data over the QSPI bus.
+ * @post    At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip     pointer to the @p QSPIDriver object
+ * @param[in] cmd       pointer to the command descriptor
+ * @param[in] n         number of bytes to send
  * @param[in] txbuf     the pointer to the transmit buffer
  *
  * @api
@@ -138,7 +156,7 @@ void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
                    size_t n, const uint8_t *txbuf) {
 
   osalDbgCheck((qspip != NULL) && (cmdp != NULL));
-  osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL)));
+  osalDbgCheck((n > 0U) && (txbuf != NULL));
 
   osalSysLock();
   osalDbgAssert(qspip->state == QSPI_READY, "not ready");
@@ -147,13 +165,12 @@ void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
 }
 
 /**
- * @brief   Receives data from the QSPI bus.
- * @details This asynchronous function starts a receive operation.
+ * @brief   Sends a command then receives data over the QSPI bus.
  * @post    At the end of the operation the configured callback is invoked.
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to receive or zero if no data phase
+ * @param[in] n         number of bytes to send
  * @param[out] rxbuf    the pointer to the receive buffer
  *
  * @api
@@ -162,7 +179,7 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
                       size_t n, uint8_t *rxbuf) {
 
   osalDbgCheck((qspip != NULL) && (cmdp != NULL));
-  osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL)));
+  osalDbgCheck((n > 0U) && (rxbuf != NULL));
 
   osalSysLock();
   osalDbgAssert(qspip->state == QSPI_READY, "not ready");
@@ -172,8 +189,31 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
 
 #if (QSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
 /**
- * @brief   Sends data over the QSPI bus.
- * @details This synchronous function performs a transmit operation.
+ * @brief   Sends a command without data phase.
+ * @pre     In order to use this function the option @p QSPI_USE_WAIT must be
+ *          enabled.
+ * @pre     In order to use this function the driver must have been configured
+ *          without callbacks (@p end_cb = @p NULL).
+ *
+ * @param[in] qspip     pointer to the @p QSPIDriver object
+ * @param[in] cmd       pointer to the command descriptor
+ *
+ * @api
+ */
+void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) {
+
+  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
+
+  osalSysLock();
+  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
+  qspiStartCommandI(qspip, cmd, n, txbuf);
+  (void) osalThreadSuspendS(&qspip->thread);
+  osalSysUnlock();
+}
+
+/**
+ * @brief   Sends a command with data over the QSPI bus.
  * @pre     In order to use this function the option @p QSPI_USE_WAIT must be
  *          enabled.
  * @pre     In order to use this function the driver must have been configured
@@ -181,7 +221,7 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to send or zero if no data phase
+ * @param[in] n         number of bytes to send
  * @param[in] txbuf     the pointer to the transmit buffer
  *
  * @api
@@ -190,7 +230,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
               size_t n, const uint8_t *txbuf) {
 
   osalDbgCheck((qspip != NULL) && (cmdp != NULL));
-  osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL)));
+  osalDbgCheck((n > 0U) && (txbuf != NULL));
 
   osalSysLock();
   osalDbgAssert(qspip->state == QSPI_READY, "not ready");
@@ -201,8 +241,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
 }
 
 /**
- * @brief   Receives data from the QSPI bus.
- * @details This synchronous function performs a receive operation.
+ * @brief   Sends a command then receives data over the QSPI bus.
  * @pre     In order to use this function the option @p QSPI_USE_WAIT must be
  *          enabled.
  * @pre     In order to use this function the driver must have been configured
@@ -210,7 +249,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp,
  *
  * @param[in] qspip     pointer to the @p QSPIDriver object
  * @param[in] cmd       pointer to the command descriptor
- * @param[in] n         number of words to receive or zero if no data phase
+ * @param[in] n         number of bytes to send
  * @param[out] rxbuf    the pointer to the receive buffer
  *
  * @api
@@ -219,7 +258,7 @@ void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
                  size_t n, uint8_t *rxbuf) {
 
   osalDbgCheck((qspip != NULL) && (cmdp != NULL));
-  osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL)));
+  osalDbgCheck((n > 0U) && (rxbuf != NULL));
 
   osalSysLock();
   osalDbgAssert(qspip->state == QSPI_READY, "not ready");
-- 
cgit v1.2.3