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
This commit is contained in:
Andrey Zabolotnyi 2020-03-19 15:59:18 +03:00 committed by GitHub
parent 1ab71814c2
commit 73b655f3b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 34 deletions

View File

@ -159,11 +159,35 @@
/* Clocking *****************************************************************/
/* The QSPI bit rate clock is generated by dividing the peripheral clock by
* a value between 1 and 255
/* 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.
*/
#define STL32F7_QSPI_CLOCK STM32_SYSCLK_FREQUENCY /* Frequency of the QSPI clock */
#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.
*
* Find out the 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);

View File

@ -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