On 12/14/21 3:34 PM, Tudor Ambarus wrote: > The sama7g5 QSPI controller uses dedicated clocks for the > QSPI Controller Interface and the QSPI Controller Core, and > requires synchronization before accessing registers or bit > fields. > > QSPI_SR.SYNCBSY must be zero before accessing any of the bits: > QSPI_CR.QSPIEN, QSPI_CR.QSPIDIS, QSPI_CR.SRFRSH, QSPI_CR.SWRST, > QSPI_CR.UPDCFG, QSPI_CR.STTFR, QSPI_CR.RTOUT, QSPI_CR.LASTXFER. > > Also, the QSPI controller core configuration can be updated by > writing the QSPI_CR.UPDCFG bit to ‘1’. This is needed by the > following registers: QSPI_MR, QSPI_SCR, QSPI_IAR, QSPI_WICR, > QSPI_IFR, QSPI_RICR, QSPI_SMR, QSPI_SKR,QSPI_REFRESH, QSPI_WRACNT > QSPI_PCALCFG. > > The Octal SPI supports frequencies up to 200 MHZ DDR. The need > for output impedance calibration arises. To avoid the degradation > of the signal quality, a PAD calibration cell is used to adjust > the output impedance to the driven I/Os. > > The transmission flow requires different sequences for setting > the configuration and for the actual transfer, than what is in > the sama5d2 and sam9x60 versions of the IP. Different interrupts > are handled. aq->ops->set_cfg() and aq->ops->transfer() are > introduced to help differentiating the flows. > > Tested single and octal SPI mode with mx66lm1g45g. > > Signed-off-by: Tudor Ambarus <tudor.ambarus@xxxxxxxxxxxxx> > --- > drivers/spi/atmel-quadspi.c | 921 ++++++++++++++++++++++++++++++++++-- > 1 file changed, 869 insertions(+), 52 deletions(-) > > diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c > index 92d9610df1fd..8980a729dd53 100644 > --- a/drivers/spi/atmel-quadspi.c > +++ b/drivers/spi/atmel-quadspi.c > @@ -11,11 +11,15 @@ cut > +static int atmel_qspi_reg_sync(struct atmel_qspi *aq) > +{ > + u32 val; > + int ret; > + > + ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, > + !(val & QSPI_SR2_SYNCBSY), 40, > + ATMEL_QSPI_SYNC_TIMEOUT); > + return ret; return readl_poll_timeout(); > +} cut > +static int atmel_qspi_dma_xfer(struct atmel_qspi *aq, struct dma_chan *chan, > + dma_addr_t dma_dst, dma_addr_t dma_src, > + unsigned int len) > +{ > + struct dma_async_tx_descriptor *tx; > + dma_cookie_t cookie; > + int ret; > + > + tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, > + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); > + if (!tx) { > + dev_err(&aq->pdev->dev, "device_prep_dma_memcpy error\n"); > + return -EIO; > + } > + > + reinit_completion(&aq->dma_completion); > + tx->callback = atmel_qspi_dma_callback; > + tx->callback_param = aq; > + cookie = tx->tx_submit(tx); > + ret = dma_submit_error(cookie); > + if (ret) { > + dev_err(&aq->pdev->dev, "dma_submit_error %d\n", cookie); > + return ret; > + } > + > + dma_async_issue_pending(chan); > + ret = wait_for_completion_timeout(&aq->dma_completion, > + msecs_to_jiffies(20 * ATMEL_QSPI_TIMEOUT)); 20 * ATMEL_QSPI_TIMEOUT, this is a leftover from a debug session. I'll send a new version to fix these small issues. Cheers, ta