Skip to content

Commit 14183c9

Browse files
committed
Fixes for QSPI DMA mode. For example reduces QSPI->DDR load of 154MB from 18,228ms to 2,607ms. Changed QSPI to use DMA by default (can force IO mode using GQSPI_MODE_IO).
1 parent 5f68cb3 commit 14183c9

File tree

3 files changed

+50
-49
lines changed

3 files changed

+50
-49
lines changed

config/examples/zynqmp.config

+3
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,6 @@ CFLAGS_EXTRA+=-DWOLFBOOT_SHA_BLOCK_SIZE=4096
8282

8383
# QSPI Clock at 0=150MHz, 1=75MHz, 2=37.5MHz (default)
8484
#CFLAGS_EXTRA+=-DGQSPI_CLK_DIV=0
85+
86+
# QSPI force IO mode (default is faster DMA mode)
87+
#CFLAGS_EXTRA+=-DGQSPI_MODE_IO

hal/zynq.c

+43-47
Original file line numberDiff line numberDiff line change
@@ -296,13 +296,13 @@ static inline int qspi_isr_wait(uint32_t wait_mask, uint32_t wait_val)
296296
}
297297
return 0;
298298
}
299-
#ifdef GQSPI_DMA
299+
#ifndef GQSPI_MODE_IO
300300
static inline int qspi_dmaisr_wait(uint32_t wait_mask, uint32_t wait_val)
301301
{
302302
uint32_t timeout = 0;
303303
while ((GQSPIDMA_ISR & wait_mask) == wait_val &&
304-
++timeout < GQSPI_TIMEOUT_TRIES);
305-
if (timeout == GQSPI_TIMEOUT_TRIES) {
304+
++timeout < GQSPIDMA_TIMEOUT_TRIES);
305+
if (timeout == GQSPIDMA_TIMEOUT_TRIES) {
306306
return -1;
307307
}
308308
return 0;
@@ -362,7 +362,7 @@ static int gspi_fifo_tx(const uint8_t* data, uint32_t sz)
362362
return GQSPI_CODE_SUCCESS;
363363
}
364364

365-
#ifndef GQSPI_DMA
365+
#ifdef GQSPI_MODE_IO
366366
static int gspi_fifo_rx(uint8_t* data, uint32_t sz)
367367
{
368368
uint32_t tmp32;
@@ -415,28 +415,28 @@ static int qspi_cs(QspiDev_t* pDev, int csAssert)
415415

416416
static uint32_t qspi_calc_exp(uint32_t xferSz, uint32_t* reg_genfifo)
417417
{
418-
uint32_t expval = 8;
418+
uint32_t expval;
419419
*reg_genfifo &= ~(GQSPI_GEN_FIFO_IMM_MASK | GQSPI_GEN_FIFO_EXP_MASK);
420420
if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) {
421-
/* Use exponent mode */
422-
while (1) {
421+
/* Use exponent mode (DMA max is 2^28) */
422+
for (expval=28; expval>=8; expval--) {
423+
/* find highest bit set */
423424
if (xferSz & (1 << expval)) {
424425
*reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK;
425-
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(expval); /* IMM is exponent */
426+
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(expval); /* IMM=exponent */
426427
xferSz = (1 << expval);
427428
break;
428429
}
429-
expval++;
430430
}
431431
}
432432
else {
433433
/* Use length mode */
434-
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */
434+
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM=actual length */
435435
}
436436
return xferSz;
437437
}
438438

439-
#ifdef GQSPI_DMA
439+
#ifndef GQSPI_MODE_IO
440440
static uint8_t XALIGNED(QQSPI_DMA_ALIGN) dmatmp[GQSPI_DMA_TMPSZ];
441441
#endif
442442

@@ -448,7 +448,7 @@ static int qspi_transfer(QspiDev_t* pDev,
448448
{
449449
int ret = GQSPI_CODE_SUCCESS;
450450
uint32_t reg_genfifo, xferSz;
451-
#ifdef GQSPI_DMA
451+
#ifndef GQSPI_MODE_IO
452452
uint8_t* dmarxptr = NULL;
453453
#endif
454454
GQSPI_EN = 1; /* Enable device */
@@ -529,27 +529,26 @@ static int qspi_transfer(QspiDev_t* pDev,
529529
reg_genfifo |= (GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_DATA_XFER);
530530
reg_genfifo |= (pDev->stripe & GQSPI_GEN_FIFO_STRIPE);
531531

532-
xferSz = rxSz;
533-
#ifdef GQSPI_DMA
534-
/* if xferSz or rxData is not QQSPI_DMA_ALIGN aligned use tmp */
532+
xferSz = qspi_calc_exp(rxSz, &reg_genfifo);
533+
#ifndef GQSPI_MODE_IO
534+
/* check if pointer is aligned or odd remainder */
535535
dmarxptr = rxData;
536-
if ((rxSz & (QQSPI_DMA_ALIGN-1)) ||
537-
(((size_t)rxData) & (QQSPI_DMA_ALIGN-1))) {
536+
if (((size_t)rxData & (QQSPI_DMA_ALIGN-1)) || (xferSz & 3)) {
538537
dmarxptr = (uint8_t*)dmatmp;
539-
/* round up */
540538
xferSz = ((xferSz + (QQSPI_DMA_ALIGN-1)) & ~(QQSPI_DMA_ALIGN-1));
541539
if (xferSz > (uint32_t)sizeof(dmatmp)) {
542540
xferSz = (uint32_t)sizeof(dmatmp);
543541
}
542+
/* re-adjust transfer */
543+
xferSz = qspi_calc_exp(xferSz, &reg_genfifo);
544544
}
545545

546546
GQSPIDMA_DST = (unsigned long)dmarxptr;
547547
GQSPIDMA_SIZE = xferSz;
548-
GQSPIDMA_IER = GQSPIDMA_ISR_ALL_MASK;
548+
GQSPIDMA_IER = GQSPIDMA_ISR_DONE; /* enable DMA done interrupt */
549549
flush_dcache_range((unsigned long)dmarxptr,
550550
(unsigned long)dmarxptr + xferSz);
551551
#endif
552-
xferSz = qspi_calc_exp(xferSz, &reg_genfifo);
553552

554553
/* Submit general FIFO operation */
555554
ret = qspi_gen_fifo_write(reg_genfifo);
@@ -558,7 +557,7 @@ static int qspi_transfer(QspiDev_t* pDev,
558557
break;
559558
}
560559

561-
#ifndef GQSPI_DMA
560+
#ifdef GQSPI_MODE_IO
562561
/* Read FIFO */
563562
ret = gspi_fifo_rx(rxData, xferSz);
564563
if (ret != GQSPI_CODE_SUCCESS) {
@@ -569,14 +568,21 @@ static int qspi_transfer(QspiDev_t* pDev,
569568
if (qspi_dmaisr_wait(GQSPIDMA_ISR_DONE, 0)) {
570569
return GQSPI_CODE_TIMEOUT;
571570
}
572-
GQSPIDMA_ISR = GQSPIDMA_ISR_DONE;
571+
GQSPIDMA_ISR = GQSPIDMA_ISR_DONE; /* clear DMA interrupt */
573572
/* adjust xfer sz */
574573
if (xferSz > rxSz)
575574
xferSz = rxSz;
576575
/* copy result if not aligned */
577576
if (dmarxptr != rxData) {
578577
memcpy(rxData, dmarxptr, xferSz);
579578
}
579+
#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 3
580+
if (xferSz <= 1024) {
581+
for (uint32_t i=0; i<xferSz; i+=4) {
582+
wolfBoot_printf("RXD=%08x\n", *((uint32_t*)&rxData[i]));
583+
}
584+
}
585+
#endif
580586
#endif
581587

582588
/* offset size and buffer */
@@ -594,7 +600,7 @@ static int qspi_transfer(QspiDev_t* pDev,
594600
static int qspi_flash_read_id(QspiDev_t* dev, uint8_t* id, uint32_t idSz)
595601
{
596602
int ret;
597-
uint8_t cmd[20]; /* size multiple of uint32_t */
603+
uint8_t cmd[4]; /* size multiple of uint32_t */
598604
uint8_t status = 0;
599605

600606
memset(cmd, 0, sizeof(cmd));
@@ -846,53 +852,47 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
846852
/* Select Generic Quad-SPI */
847853
GQSPI_SEL = 1;
848854

849-
/* Clear and disable interrupts */
855+
/* Clear and disable all interrupts */
850856
reg_isr = GQSPI_ISR;
851-
GQSPI_ISR |= GQSPI_ISR_WR_TO_CLR_MASK; /* Clear poll timeout counter interrupt */
857+
GQSPI_ISR = (reg_isr | GQSPI_ISR_WR_TO_CLR_MASK); /* Clear poll timeout counter interrupt */
852858
reg_cfg = GQSPIDMA_ISR;
853859
GQSPIDMA_ISR = reg_cfg; /* clear all active interrupts */
854-
GQSPIDMA_STS |= GQSPIDMA_STS_WTC; /* mark outstanding DMA's done */
855860
GQSPI_IDR = GQSPI_IXR_ALL_MASK; /* disable interrupts */
856-
GQSPIDMA_ISR = GQSPIDMA_ISR_ALL_MASK; /* disable interrupts */
857-
/* Reset FIFOs */
858-
if (GQSPI_ISR & GQSPI_IXR_RX_FIFO_EMPTY) {
859-
GQSPI_FIFO_CTRL |= (GQSPI_FIFO_CTRL_RST_TX_FIFO | GQSPI_FIFO_CTRL_RST_RX_FIFO);
860-
}
861-
if (reg_isr & GQSPI_IXR_RX_FIFO_EMPTY) {
862-
GQSPI_FIFO_CTRL |= GQSPI_FIFO_CTRL_RST_RX_FIFO;
863-
}
861+
GQSPIDMA_IDR = GQSPIDMA_ISR_ALL_MASK;
864862

865863
GQSPI_EN = 0; /* Disable device */
866864

867865
/* Initialize clock divisor, write protect hold and start mode */
868-
#ifdef GQSPI_DMA
869-
reg_cfg = GQSPI_CFG_MODE_EN_DMA; /* Use DMA Transfer Mode */
870-
#else
866+
#ifdef GQSPI_MODE_IO
871867
reg_cfg = GQSPI_CFG_MODE_EN_IO; /* Use I/O Transfer Mode */
872868
reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Auto start GFIFO cmd execution */
869+
#else
870+
reg_cfg = GQSPI_CFG_MODE_EN_DMA; /* Use DMA Transfer Mode */
873871
#endif
874872
reg_cfg |= GQSPI_CFG_BAUD_RATE_DIV(GQSPI_CLK_DIV); /* Clock Divider */
875873
reg_cfg |= GQSPI_CFG_WP_HOLD; /* Use WP Hold */
876874
reg_cfg &= ~(GQSPI_CFG_CLK_POL | GQSPI_CFG_CLK_PH); /* Use POL=0,PH=0 */
877875
GQSPI_CFG = reg_cfg;
878876

879-
#if GQSPI_CLK_DIV >= 2 /* 300/8=37.5MHz */
880-
/* At 40 MHz, the Quad-SPI controller should be in non-loopback mode with
877+
#if GQSPI_CLK_DIV >= 1 /* 125/4=31.25MHz */
878+
/* At <40 MHz, the Quad-SPI controller should be in non-loopback mode with
881879
* the clock and data tap delays bypassed. */
882880
IOU_TAPDLY_BYPASS |= IOU_TAPDLY_BYPASS_LQSPI_RX;
883881
GQSPI_LPBK_DLY_ADJ = 0;
884882
GQSPI_DATA_DLY_ADJ = 0;
885-
#elif GQSPI_CLK_DIV >= 1 /* 300/4=75MHz */
886-
/* At 100 MHz, the Quad-SPI controller should be in clock loopback mode
883+
#elif GQSPI_CLK_DIV >= 0 /* 125/2 = 62.5MHz */
884+
/* At <100 MHz, the Quad-SPI controller should be in clock loopback mode
887885
* with the clock tap delay bypassed, but the data tap delay enabled. */
888886
IOU_TAPDLY_BYPASS |= IOU_TAPDLY_BYPASS_LQSPI_RX;
889887
GQSPI_LPBK_DLY_ADJ = GQSPI_LPBK_DLY_ADJ_USE_LPBK;
890888
GQSPI_DATA_DLY_ADJ = (GQSPI_DATA_DLY_ADJ_USE_DATA_DLY |
891889
GQSPI_DATA_DLY_ADJ_DATA_DLY_ADJ(2));
892-
#else
893-
/* At 150 MHz, only the generic controller can be used.
890+
#endif
891+
#if 0
892+
/* At <150 MHz, only the generic controller can be used.
894893
* The generic controller should be in clock loopback mode and the clock
895894
* tap delay enabled, but the data tap delay disabled. */
895+
/* For EL2 or lower must use IOCTL_SET_TAPDELAY_BYPASS ARG1=2, ARG2=0 */
896896
IOU_TAPDLY_BYPASS = 0;
897897
GQSPI_LPBK_DLY_ADJ = GQSPI_LPBK_DLY_ADJ_USE_LPBK;
898898
GQSPI_DATA_DLY_ADJ = 0;
@@ -907,10 +907,6 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
907907
GQSPIDMA_CTRL = GQSPIDMA_CTRL_DEF;
908908
GQSPIDMA_CTRL2 = GQSPIDMA_CTRL2_DEF;
909909

910-
/* Interrupts unmask and enable */
911-
GQSPI_IMR = GQSPI_IXR_ALL_MASK;
912-
GQSPI_IER = GQSPI_IXR_ALL_MASK;
913-
914910
GQSPI_EN = 1; /* Enable Device */
915911
#endif /* USE_QNX */
916912
(void)reg_cfg;

hal/zynq.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,12 @@
174174
#define GQSPI_FIFO_CTRL_RST_RX_FIFO (1UL << 2)
175175

176176
/* GQSPIDMA_CTRL */
177-
#define GQSPIDMA_CTRL_DEF 0x403FFA00UL
177+
#define GQSPIDMA_CTRL_DEF 0x803FFA00UL
178178
#define GQSPIDMA_CTRL2_DEF 0x081BFFF8UL
179179

180180
/* GQSPIDMA_STS */
181-
#define GQSPIDMA_STS_WTC 0xE000U
181+
#define GQSPIDMA_STS_WTC (7UL << 13)
182+
#define GQSPIDMA_STS_BUSY (1UL << 0)
182183

183184
/* GQSPIDMA_ISR */
184185
#define GQSPIDMA_ISR_DONE 0x02
@@ -201,6 +202,7 @@
201202
#endif
202203
#endif
203204
#define GQSPI_TIMEOUT_TRIES 100000
205+
#define GQSPIDMA_TIMEOUT_TRIES 100000000
204206
#define QSPI_FLASH_READY_TRIES 1000
205207

206208
/* QSPI Configuration */

0 commit comments

Comments
 (0)