Skip to content

Commit 7205820

Browse files
dgarskedanielinux
authored andcommitted
Added QSPI DMA support.
1 parent acb9d83 commit 7205820

File tree

7 files changed

+225
-83
lines changed

7 files changed

+225
-83
lines changed

hal/zynq.c

Lines changed: 143 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ static int qspi_wait_we(QspiDev_t* dev);
8080
static int test_ext_flash(QspiDev_t* dev);
8181
#endif
8282

83+
/* asm function */
84+
extern void flush_dcache_range(unsigned long start, unsigned long stop);
85+
8386
#ifdef DEBUG_UART
8487
void uart_init(void)
8588
{
@@ -293,9 +296,23 @@ static inline int qspi_isr_wait(uint32_t wait_mask, uint32_t wait_val)
293296
}
294297
return 0;
295298
}
299+
#ifdef GQSPI_DMA
300+
static inline int qspi_dmaisr_wait(uint32_t wait_mask, uint32_t wait_val)
301+
{
302+
uint32_t timeout = 0;
303+
while ((GQSPIDMA_ISR & wait_mask) == wait_val &&
304+
++timeout < GQSPI_TIMEOUT_TRIES);
305+
if (timeout == GQSPI_TIMEOUT_TRIES) {
306+
return -1;
307+
}
308+
return 0;
309+
}
310+
#endif
296311

297312
static int qspi_gen_fifo_write(uint32_t reg_genfifo)
298313
{
314+
uint32_t reg_cfg;
315+
299316
/* wait until the gen FIFO is not full to write */
300317
if (qspi_isr_wait(GQSPI_IXR_GEN_FIFO_NOT_FULL, 0)) {
301318
return GQSPI_CODE_TIMEOUT;
@@ -317,6 +334,17 @@ static int gspi_fifo_tx(const uint8_t* data, uint32_t sz)
317334
return GQSPI_CODE_TIMEOUT;
318335
}
319336

337+
#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 3
338+
uint32_t txSz = sz;
339+
if (txSz > GQSPI_FIFO_WORD_SZ)
340+
txSz = GQSPI_FIFO_WORD_SZ;
341+
memcpy(&tmp32, data, txSz);
342+
GQSPI_TXD = tmp32;
343+
wolfBoot_printf("TXD=%08x\n", tmp32);
344+
345+
sz -= txSz;
346+
data += txSz;
347+
#else
320348
/* Write data */
321349
if (sz >= 4) {
322350
GQSPI_TXD = *(uint32_t*)data;
@@ -329,23 +357,32 @@ static int gspi_fifo_tx(const uint8_t* data, uint32_t sz)
329357
GQSPI_TXD = tmp32;
330358
sz = 0;
331359
}
360+
#endif
332361
}
333362
return GQSPI_CODE_SUCCESS;
334363
}
335364

336-
static int gspi_fifo_rx(uint8_t* data, uint32_t sz, uint32_t discardSz)
365+
#ifndef GQSPI_DMA
366+
static int gspi_fifo_rx(uint8_t* data, uint32_t sz)
337367
{
338368
uint32_t tmp32;
369+
339370
while (sz > 0) {
340371
/* Wait for RX FIFO not empty */
341372
if (qspi_isr_wait(GQSPI_IXR_RX_FIFO_NOT_EMPTY, 0)) {
342373
return GQSPI_CODE_TIMEOUT;
343374
}
344-
if (discardSz >= GQSPI_FIFO_WORD_SZ) {
345-
tmp32 = GQSPI_RXD; /* discard */
346-
discardSz -= GQSPI_FIFO_WORD_SZ;
347-
continue;
348-
}
375+
376+
#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 3
377+
uint32_t rxSz = sz;
378+
if (rxSz > GQSPI_FIFO_WORD_SZ)
379+
rxSz = GQSPI_FIFO_WORD_SZ;
380+
tmp32 = GQSPI_RXD;
381+
memcpy(data, &tmp32, rxSz);
382+
wolfBoot_printf("RXD=%08x\n", tmp32);
383+
sz -= rxSz;
384+
data += rxSz;
385+
#else
349386
if (sz >= 4) {
350387
*(uint32_t*)data = GQSPI_RXD;
351388
data += 4;
@@ -356,9 +393,11 @@ static int gspi_fifo_rx(uint8_t* data, uint32_t sz, uint32_t discardSz)
356393
memcpy(data, &tmp32, sz);
357394
sz = 0;
358395
}
396+
#endif
359397
}
360398
return GQSPI_CODE_SUCCESS;
361399
}
400+
#endif
362401

363402
static int qspi_cs(QspiDev_t* pDev, int csAssert)
364403
{
@@ -374,6 +413,33 @@ static int qspi_cs(QspiDev_t* pDev, int csAssert)
374413
return qspi_gen_fifo_write(reg_genfifo);
375414
}
376415

416+
static uint32_t qspi_calc_exp(uint32_t xferSz, uint32_t* reg_genfifo)
417+
{
418+
uint32_t expval = 8;
419+
*reg_genfifo &= ~(GQSPI_GEN_FIFO_IMM_MASK | GQSPI_GEN_FIFO_EXP_MASK);
420+
if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) {
421+
/* Use exponent mode */
422+
while (1) {
423+
if (xferSz & (1 << expval)) {
424+
*reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK;
425+
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(expval); /* IMM is exponent */
426+
xferSz = (1 << expval);
427+
break;
428+
}
429+
expval++;
430+
}
431+
}
432+
else {
433+
/* Use length mode */
434+
*reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */
435+
}
436+
return xferSz;
437+
}
438+
439+
#ifdef GQSPI_DMA
440+
static uint8_t XALIGNED(QQSPI_DMA_ALIGN) dmatmp[GQSPI_DMA_TMPSZ];
441+
#endif
442+
377443
static int qspi_transfer(QspiDev_t* pDev,
378444
const uint8_t* cmdData, uint32_t cmdSz,
379445
const uint8_t* txData, uint32_t txSz,
@@ -382,7 +448,9 @@ static int qspi_transfer(QspiDev_t* pDev,
382448
{
383449
int ret = GQSPI_CODE_SUCCESS;
384450
uint32_t reg_genfifo, xferSz;
385-
451+
#ifdef GQSPI_DMA
452+
uint8_t* dmarxptr = NULL;
453+
#endif
386454
GQSPI_EN = 1; /* Enable device */
387455
qspi_cs(pDev, 1); /* Select slave */
388456

@@ -395,14 +463,14 @@ static int qspi_transfer(QspiDev_t* pDev,
395463
xferSz = cmdSz;
396464
while (ret == GQSPI_CODE_SUCCESS && cmdData && xferSz > 0) {
397465
/* Enable TX and send command inline */
398-
reg_genfifo |= GQSPI_GEN_FIFO_TX;
399466
reg_genfifo &= ~(GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_IMM_MASK);
467+
reg_genfifo |= GQSPI_GEN_FIFO_TX;
400468
reg_genfifo |= GQSPI_GEN_FIFO_IMM(*cmdData); /* IMM is data */
401469

402470
/* Submit general FIFO operation */
403471
ret = qspi_gen_fifo_write(reg_genfifo);
404472
if (ret != GQSPI_CODE_SUCCESS) {
405-
wolfBoot_printf("on line %d: error %d\n", __LINE__, ret);
473+
wolfBoot_printf("zynq.c:%d (error %d)\n", __LINE__, ret);
406474
break;
407475
}
408476

@@ -411,39 +479,28 @@ static int qspi_transfer(QspiDev_t* pDev,
411479
cmdData++;
412480
}
413481

414-
/* Set desired data mode and stripe */
482+
/* Set desired data mode */
415483
reg_genfifo |= (mode & GQSPI_GEN_FIFO_MODE_MASK);
416-
reg_genfifo |= (pDev->stripe & GQSPI_GEN_FIFO_STRIPE);
417484

418485
/* TX Data */
419486
while (ret == GQSPI_CODE_SUCCESS && txData && txSz > 0) {
420-
xferSz = txSz;
421-
422487
/* Enable TX */
423488
reg_genfifo &= ~(GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_IMM_MASK |
424489
GQSPI_GEN_FIFO_EXP_MASK);
425490
reg_genfifo |= (GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_DATA_XFER);
426-
427-
if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) {
428-
/* Use exponent mode */
429-
xferSz = 256; /* 2 ^ 8 = 256 */
430-
reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK;
431-
reg_genfifo |= GQSPI_GEN_FIFO_IMM(8); /* IMM is exponent */
432-
}
433-
else {
434-
reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */
435-
}
491+
reg_genfifo |= (pDev->stripe & GQSPI_GEN_FIFO_STRIPE);
492+
xferSz = qspi_calc_exp(txSz, &reg_genfifo);
436493

437494
/* Submit general FIFO operation */
438495
ret = qspi_gen_fifo_write(reg_genfifo);
439496
if (ret != GQSPI_CODE_SUCCESS) {
440-
wolfBoot_printf("on line %d: error %d\n", __LINE__, ret);
497+
wolfBoot_printf("zynq.c:%d (error %d)\n", __LINE__, ret);
441498
}
442499

443500
/* Fill FIFO */
444501
ret = gspi_fifo_tx(txData, xferSz);
445502
if (ret != GQSPI_CODE_SUCCESS) {
446-
wolfBoot_printf("on line %d: error %d\n", __LINE__, ret);
503+
wolfBoot_printf("zynq.c:%d (error %d)\n", __LINE__, ret);
447504
break;
448505
}
449506

@@ -454,60 +511,77 @@ static int qspi_transfer(QspiDev_t* pDev,
454511

455512
/* Dummy operations */
456513
if (ret == GQSPI_CODE_SUCCESS && dummySz) {
457-
/* Send dummy clocks (Disable TX & RX) */
514+
/* Send dummy clocks (Disable TX & RX), do not set stripe */
458515
reg_genfifo &= ~(GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_RX |
459-
GQSPI_GEN_FIFO_IMM_MASK | GQSPI_GEN_FIFO_EXP_MASK);
516+
GQSPI_GEN_FIFO_IMM_MASK | GQSPI_GEN_FIFO_EXP_MASK |
517+
GQSPI_GEN_FIFO_STRIPE);
518+
reg_genfifo |= GQSPI_GEN_FIFO_DATA_XFER;
460519
/* IMM is number of dummy clock cycles */
461520
reg_genfifo |= GQSPI_GEN_FIFO_IMM(dummySz);
462521
ret = qspi_gen_fifo_write(reg_genfifo); /* Submit FIFO Dummy Op */
463-
464-
if (rxSz > 0) {
465-
/* Convert dummy bits to bytes */
466-
dummySz = (dummySz + 7) / 8;
467-
/* Adjust rxSz for dummy bytes */
468-
rxSz += dummySz;
469-
/* round up by FIFO Word Size */
470-
rxSz = (((rxSz + GQSPI_FIFO_WORD_SZ - 1) / GQSPI_FIFO_WORD_SZ) *
471-
GQSPI_FIFO_WORD_SZ);
472-
}
473522
}
474523

475524
/* RX Data */
476525
while (ret == GQSPI_CODE_SUCCESS && rxData && rxSz > 0) {
477-
xferSz = rxSz;
478-
479526
/* Enable RX */
480527
reg_genfifo &= ~(GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_IMM_MASK |
481528
GQSPI_GEN_FIFO_EXP_MASK);
482529
reg_genfifo |= (GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_DATA_XFER);
530+
reg_genfifo |= (pDev->stripe & GQSPI_GEN_FIFO_STRIPE);
483531

484-
if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) {
485-
/* Use exponent mode */
486-
xferSz = 256; /* 2 ^ 8 = 256 */
487-
reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK;
488-
reg_genfifo |= GQSPI_GEN_FIFO_IMM(8); /* IMM is exponent */
489-
}
490-
else {
491-
reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */
532+
xferSz = rxSz;
533+
#ifdef GQSPI_DMA
534+
/* if xferSz or rxData is not QQSPI_DMA_ALIGN aligned use tmp */
535+
dmarxptr = rxData;
536+
if ((rxSz & (QQSPI_DMA_ALIGN-1)) ||
537+
(((size_t)rxData) & (QQSPI_DMA_ALIGN-1))) {
538+
dmarxptr = (uint8_t*)dmatmp;
539+
/* round up */
540+
xferSz = ((xferSz + (QQSPI_DMA_ALIGN-1)) & ~(QQSPI_DMA_ALIGN-1));
541+
if (xferSz > (uint32_t)sizeof(dmatmp)) {
542+
xferSz = (uint32_t)sizeof(dmatmp);
543+
}
492544
}
493545

546+
GQSPIDMA_DST = (unsigned long)dmarxptr;
547+
GQSPIDMA_SIZE = xferSz;
548+
GQSPIDMA_IER = GQSPIDMA_ISR_ALL_MASK;
549+
flush_dcache_range((unsigned long)dmarxptr,
550+
(unsigned long)dmarxptr + xferSz);
551+
#endif
552+
xferSz = qspi_calc_exp(xferSz, &reg_genfifo);
553+
494554
/* Submit general FIFO operation */
495555
ret = qspi_gen_fifo_write(reg_genfifo);
496556
if (ret != GQSPI_CODE_SUCCESS) {
497-
wolfBoot_printf("on line %d: error %d\n", __LINE__, ret);
557+
wolfBoot_printf("zynq.c:%d (error %d)\n", __LINE__, ret);
498558
break;
499559
}
500560

561+
#ifndef GQSPI_DMA
501562
/* Read FIFO */
502-
ret = gspi_fifo_rx(rxData, xferSz-dummySz, dummySz);
563+
ret = gspi_fifo_rx(rxData, xferSz);
503564
if (ret != GQSPI_CODE_SUCCESS) {
504-
wolfBoot_printf("on line %d: error %d\n", __LINE__, ret);
565+
wolfBoot_printf("zynq.c:%d (error %d)\n", __LINE__, ret);
505566
}
567+
#else
568+
/* Wait for DMA done */
569+
if (qspi_dmaisr_wait(GQSPIDMA_ISR_DONE, 0)) {
570+
return GQSPI_CODE_TIMEOUT;
571+
}
572+
GQSPIDMA_ISR = GQSPIDMA_ISR_DONE;
573+
/* adjust xfer sz */
574+
if (xferSz > rxSz)
575+
xferSz = rxSz;
576+
/* copy result if not aligned */
577+
if (dmarxptr != rxData) {
578+
memcpy(rxData, dmarxptr, xferSz);
579+
}
580+
#endif
506581

507582
/* offset size and buffer */
508583
rxSz -= xferSz;
509-
rxData += (xferSz - dummySz);
510-
dummySz = 0; /* only first RX */
584+
rxData += xferSz;
511585
}
512586

513587
qspi_cs(pDev, 0); /* Deselect Slave */
@@ -524,7 +598,7 @@ static int qspi_flash_read_id(QspiDev_t* dev, uint8_t* id, uint32_t idSz)
524598
uint8_t status = 0;
525599

526600
memset(cmd, 0, sizeof(cmd));
527-
cmd[0] = MULTI_IO_READ_ID_CMD;
601+
cmd[0] = READ_ID_CMD;
528602
ret = qspi_transfer(&mDev, cmd, 1, NULL, 0, cmd, sizeof(cmd), 0,
529603
GQSPI_GEN_FIFO_MODE_SPI);
530604

@@ -775,11 +849,11 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
775849
/* Clear and disable interrupts */
776850
reg_isr = GQSPI_ISR;
777851
GQSPI_ISR |= GQSPI_ISR_WR_TO_CLR_MASK; /* Clear poll timeout counter interrupt */
778-
reg_cfg = QSPIDMA_DST_I_STS;
779-
QSPIDMA_DST_I_STS = reg_cfg; /* clear all active interrupts */
780-
QSPIDMA_DST_STS |= QSPIDMA_DST_STS_WTC; /* mark outstanding DMA's done */
852+
reg_cfg = GQSPIDMA_ISR;
853+
GQSPIDMA_ISR = reg_cfg; /* clear all active interrupts */
854+
GQSPIDMA_STS |= GQSPIDMA_STS_WTC; /* mark outstanding DMA's done */
781855
GQSPI_IDR = GQSPI_IXR_ALL_MASK; /* disable interrupts */
782-
QSPIDMA_DST_I_STS = QSPIDMA_DST_I_STS_ALL_MASK; /* disable interrupts */
856+
GQSPIDMA_ISR = GQSPIDMA_ISR_ALL_MASK; /* disable interrupts */
783857
/* Reset FIFOs */
784858
if (GQSPI_ISR & GQSPI_IXR_RX_FIFO_EMPTY) {
785859
GQSPI_FIFO_CTRL |= (GQSPI_FIFO_CTRL_RST_TX_FIFO | GQSPI_FIFO_CTRL_RST_RX_FIFO);
@@ -791,10 +865,14 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
791865
GQSPI_EN = 0; /* Disable device */
792866

793867
/* 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
794871
reg_cfg = GQSPI_CFG_MODE_EN_IO; /* Use I/O Transfer Mode */
872+
reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Auto start GFIFO cmd execution */
873+
#endif
795874
reg_cfg |= GQSPI_CFG_BAUD_RATE_DIV(GQSPI_CLK_DIV); /* Clock Divider */
796875
reg_cfg |= GQSPI_CFG_WP_HOLD; /* Use WP Hold */
797-
reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Start GFIFO command execution */
798876
reg_cfg &= ~(GQSPI_CFG_CLK_POL | GQSPI_CFG_CLK_PH); /* Use POL=0,PH=0 */
799877
GQSPI_CFG = reg_cfg;
800878

@@ -803,30 +881,31 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
803881
* the clock and data tap delays bypassed. */
804882
IOU_TAPDLY_BYPASS |= IOU_TAPDLY_BYPASS_LQSPI_RX;
805883
GQSPI_LPBK_DLY_ADJ = 0;
806-
QSPI_DATA_DLY_ADJ = 0;
884+
GQSPI_DATA_DLY_ADJ = 0;
807885
#elif GQSPI_CLK_DIV >= 1 /* 300/4=75MHz */
808886
/* At 100 MHz, the Quad-SPI controller should be in clock loopback mode
809887
* with the clock tap delay bypassed, but the data tap delay enabled. */
810888
IOU_TAPDLY_BYPASS |= IOU_TAPDLY_BYPASS_LQSPI_RX;
811889
GQSPI_LPBK_DLY_ADJ = GQSPI_LPBK_DLY_ADJ_USE_LPBK;
812-
QSPI_DATA_DLY_ADJ = QSPI_DATA_DLY_ADJ_USE_DATA_DLY | QSPI_DATA_DLY_ADJ_DATA_DLY_ADJ(2);
890+
GQSPI_DATA_DLY_ADJ = (GQSPI_DATA_DLY_ADJ_USE_DATA_DLY |
891+
GQSPI_DATA_DLY_ADJ_DATA_DLY_ADJ(2));
813892
#else
814893
/* At 150 MHz, only the generic controller can be used.
815894
* The generic controller should be in clock loopback mode and the clock
816895
* tap delay enabled, but the data tap delay disabled. */
817896
IOU_TAPDLY_BYPASS = 0;
818897
GQSPI_LPBK_DLY_ADJ = GQSPI_LPBK_DLY_ADJ_USE_LPBK;
819-
QSPI_DATA_DLY_ADJ = 0;
898+
GQSPI_DATA_DLY_ADJ = 0;
820899
#endif
821900

822901
/* Initialize hardware parameters for Threshold and Interrupts */
823902
GQSPI_TX_THRESH = 1;
824903
GQSPI_RX_THRESH = 1;
825-
GQSPI_GF_THRESH = 16;
904+
GQSPI_GF_THRESH = 31;
826905

827906
/* Reset DMA */
828-
QSPIDMA_DST_CTRL = QSPIDMA_DST_CTRL_DEF;
829-
QSPIDMA_DST_CTRL2 = QSPIDMA_DST_CTRL2_DEF;
907+
GQSPIDMA_CTRL = GQSPIDMA_CTRL_DEF;
908+
GQSPIDMA_CTRL2 = GQSPIDMA_CTRL2_DEF;
830909

831910
/* Interrupts unmask and enable */
832911
GQSPI_IMR = GQSPI_IXR_ALL_MASK;

0 commit comments

Comments
 (0)