SAM3/4: Support for PDC based HSMCI ADMA from Bob Doiron

This commit is contained in:
Gregory Nutt 2014-04-21 17:18:30 -06:00
parent b0f4941c77
commit 5eadd8df7a
2 changed files with 236 additions and 101 deletions

View File

@ -43,6 +43,7 @@
#include <nuttx/config.h>
#include "chip.h"
#include "chip/sam_pdc.h"
#include "chip/sam_memorymap.h"
/****************************************************************************************
@ -113,6 +114,19 @@
#define SAM_HSMCI_WPSR (SAM_HSMCI_BASE+SAM_HSMCI_WPSR_OFFSET)
#define SAM_HSMCI_FIFO (SAM_HSMCI_BASE+SAM_HSMCI_FIFO_OFFSET)
#if (defined(CONFIG_ARCH_CHIP_SAM4S) && defined(CONFIG_SAM34_PDCA))
# define SAM_HSMCI_PDC_RPR (SAM_HSMCI_BASE+SAM_PDC_RPR_OFFSET)
# define SAM_HSMCI_PDC_RCR (SAM_HSMCI_BASE+SAM_PDC_RCR_OFFSET)
# define SAM_HSMCI_PDC_TPR (SAM_HSMCI_BASE+SAM_PDC_TPR_OFFSET)
# define SAM_HSMCI_PDC_TCR (SAM_HSMCI_BASE+SAM_PDC_TCR_OFFSET)
# define SAM_HSMCI_PDC_RNPR (SAM_HSMCI_BASE+SAM_PDC_RNPR_OFFSET)
# define SAM_HSMCI_PDC_RNCR (SAM_HSMCI_BASE+SAM_PDC_RNCR_OFFSET)
# define SAM_HSMCI_PDC_TNPR (SAM_HSMCI_BASE+SAM_PDC_TNPR_OFFSET)
# define SAM_HSMCI_PDC_TNCR (SAM_HSMCI_BASE+SAM_PDC_TNCR_OFFSET)
# define SAM_HSMCI_PDC_PTCR (SAM_HSMCI_BASE+SAM_PDC_PTCR_OFFSET)
# define SAM_HSMCI_PDC_PTSR (SAM_HSMCI_BASE+SAM_PDC_PTSR_OFFSET)
#endif
/* HSMCI register bit definitions *******************************************************/
/* HSMCI Control Register */

View File

@ -61,15 +61,25 @@
#include "up_arch.h"
#include "sam_gpio.h"
#include "sam_dmac.h"
#include "sam_cmcc.h"
#include "sam_hsmci.h"
#include "sam_periphclks.h"
#include "chip/sam_dmac.h"
#ifdef CONFIG_SAM34_DMAC
# include "sam_dmac.h"
#endif
#include "chip/sam_pmc.h"
#include "chip/sam_hsmci.h"
#include "chip/sam_pinmap.h"
#ifdef CONFIG_SAM34_DMAC
# include "chip/sam_dmac.h"
#endif
#ifdef CONFIG_SAM34_PDCA
# include "chip/sam_pdc.h"
#endif
#if CONFIG_SAM34_HSMCI
/****************************************************************************
@ -78,8 +88,8 @@
/* Configuration ************************************************************/
#ifndef CONFIG_SAM34_DMAC0
# warning "HSMCI driver requires CONFIG_SAM34_DMAC0"
#if !(defined(CONFIG_SAM34_DMAC0) || defined(CONFIG_SAM34_PDCA))
# warning "HSMCI driver requires CONFIG_SAM34_DMAC0 or CONFIG_SAM34_PDCA"
#endif
#ifndef CONFIG_SCHED_WORKQUEUE
@ -122,6 +132,7 @@
#define HSMCI_DTIMER_DATATIMEOUT (0x000fffff)
#ifdef CONFIG_SAM34_DMAC0
/* DMA configuration flags */
#define DMA_FLAGS \
@ -131,6 +142,7 @@
DMACH_FLAG_PERIPHWIDTH_32BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT | \
DMACH_FLAG_MEMCHUNKSIZE_4)
#endif
/* Status errors:
*
@ -147,11 +159,6 @@
* HSMCI_INT_RINDE Response Index Error
*/
#define HSMCI_STATUS_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_BLKOVRE | HSMCI_INT_CSTOE | \
HSMCI_INT_DTOE | HSMCI_INT_DCRCE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | \
HSMCI_INT_RCRCE | HSMCI_INT_RDIRE | HSMCI_INT_RINDE)
/* Response errors:
*
* HSMCI_INT_CSTOE Completion signal time-out error (see HSMCI_CSTOR)
@ -183,30 +190,43 @@
* HSMCI_INT_DCRCE Data CRC Error
*/
#if defined(CONFIG_ARCH_CHIP_SAM3U)
# define HSMCI_DATA_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_BLKOVRE | HSMCI_INT_CSTOE | \
HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
#ifdef CONFIG_SAM34_DMAC0
# if defined(CONFIG_ARCH_CHIP_SAM3U)
# define HSMCI_DATA_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_BLKOVRE | HSMCI_INT_CSTOE | \
HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
# else
# define HSMCI_DATA_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | \
HSMCI_INT_DCRCE)
# endif
#else
# define HSMCI_DATA_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | \
HSMCI_INT_DCRCE)
#define HSMCI_DATA_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | \
HSMCI_INT_DCRCE)
#endif
#define HSMCI_DATA_TIMEOUT_ERRORS \
(HSMCI_INT_CSTOE | HSMCI_INT_DTOE)
#if defined(CONFIG_ARCH_CHIP_SAM3U)
#ifdef CONFIG_SAM34_DMAC0
# if defined(CONFIG_ARCH_CHIP_SAM3U)
# define HSMCI_DATA_DMARECV_ERRORS \
(HSMCI_INT_OVRE | HSMCI_INT_BLKOVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | \
HSMCI_INT_DCRCE)
# else
# define HSMCI_DATA_DMARECV_ERRORS \
(HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
# endif
#endif
#ifdef CONFIG_SAM34_PDCA
# define HSMCI_DATA_DMARECV_ERRORS \
(HSMCI_INT_OVRE | HSMCI_INT_BLKOVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | \
HSMCI_INT_DCRCE)
#else
# define HSMCI_DATA_DMARECV_ERRORS \
(HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
(HSMCI_INT_OVRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
#endif
#define HSMCI_DATA_DMASEND_ERRORS \
(HSMCI_INT_UNRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
(HSMCI_INT_UNRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE)
/* Data transfer status and interrupt mask bits.
*
@ -222,10 +242,19 @@
* 1: DMA buffer transfer has completed.
*/
#define HSMCI_DMARECV_INTS \
(HSMCI_DATA_DMARECV_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */)
#define HSMCI_DMASEND_INTS \
(HSMCI_DATA_DMASEND_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */)
#ifdef CONFIG_SAM34_DMAC0
# define HSMCI_DMARECV_INTS \
(HSMCI_DATA_DMARECV_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */)
# define HSMCI_DMASEND_INTS \
(HSMCI_DATA_DMASEND_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */)
#endif
#ifdef CONFIG_SAM34_PDCA
#define HSMCI_DMARECV_INTS \
(HSMCI_DATA_DMARECV_ERRORS | HSMCI_INT_ENDRX)
#define HSMCI_DMASEND_INTS \
(HSMCI_DATA_DMASEND_ERRORS | HSMCI_INT_ENDTX)
#endif
/* Event waiting interrupt mask bits.
*
@ -284,7 +313,9 @@ struct sam_dev_s
uint32_t cmdrmask; /* Interrupt enables for this particular cmd/response */
volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */
WDOG_ID waitwdog; /* Watchdog that handles event timeouts */
#ifdef CONFIG_SAM34_DMAC0
bool dmabusy; /* TRUE: DMA is in progress */
#endif
/* Callback support */
@ -301,7 +332,9 @@ struct sam_dev_s
/* DMA data transfer support */
bool widebus; /* Required for DMA support */
#ifdef CONFIG_SAM34_DMAC0
DMA_HANDLE dma; /* Handle for DMA channel */
#endif
};
/* Register logging support */
@ -309,24 +342,37 @@ struct sam_dev_s
#if defined(CONFIG_SAM34_HSMCI_XFRDEBUG) || defined(CONFIG_SAM34_HSMCI_CMDDEBUG)
struct sam_hsmciregs_s
{
uint32_t mr; /* Mode Register */
uint32_t dtor; /* Data Timeout Register */
uint32_t sdcr; /* SD/SDIO Card Register */
uint32_t argr; /* Argument Register */
uint32_t blkr; /* Block Register */
uint32_t cstor; /* Completion Signal Timeout Register */
uint32_t rsp0; /* Response Register 0 */
uint32_t rsp1; /* Response Register 1 */
uint32_t rsp2; /* Response Register 2 */
uint32_t rsp3; /* Response Register 3 */
uint32_t sr; /* Status Register */
uint32_t imr; /* Interrupt Mask Register */
uint32_t mr; /* Mode Register */
uint32_t dtor; /* Data Timeout Register */
uint32_t sdcr; /* SD/SDIO Card Register */
uint32_t argr; /* Argument Register */
uint32_t blkr; /* Block Register */
uint32_t cstor; /* Completion Signal Timeout Register */
uint32_t rsp0; /* Response Register 0 */
uint32_t rsp1; /* Response Register 1 */
uint32_t rsp2; /* Response Register 2 */
uint32_t rsp3; /* Response Register 3 */
uint32_t sr; /* Status Register */
uint32_t imr; /* Interrupt Mask Register */
#if defined(CONFIG_ARCH_CHIP_SAM3U)
uint32_t dma; /* DMA Configuration Register */
uint32_t dma; /* DMA Configuration Register */
#endif
uint32_t cfg; /* Configuration Register */
uint32_t wpmr; /* Write Protection Mode Register */
uint32_t wpsr; /* Write Protection Status Register */
#ifdef CONFIG_SAM34_PDCA
uint32_t pdc_rpr; /* Receive Pointer Register */
uint32_t pdc_rcr; /* Receive Counter Register */
uint32_t pdc_tpr; /* Transmit Pointer Register */
uint32_t pdc_tcr; /* Transmit Counter Register */
uint32_t pdc_rnpr; /* Receive Next Pointer Register */
uint32_t pdc_rncr; /* Receive Next Counter Register */
uint32_t pdc_tnpr; /* Transmit Next Pointer Register */
uint32_t pdc_tncr; /* Transmit Next Counter Register */
//uint32_t pdc_ptcr; /* Transfer Control Register */
uint32_t pdc_ptsr; /* Transfer Status Register */
#endif
uint32_t cfg; /* Configuration Register */
uint32_t wpmr; /* Write Protection Mode Register */
uint32_t wpsr; /* Write Protection Status Register */
};
#endif
@ -334,7 +380,7 @@ struct sam_hsmciregs_s
struct sam_xfrregs_s
{
struct sam_hsmciregs_s hsmci;
#ifdef CONFIG_DEBUG_DMA
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_SAM34_DMAC0)
struct sam_dmaregs_s dma;
#endif
};
@ -390,9 +436,11 @@ static void sam_cmddump(void);
# define sam_cmddump()
#endif
#ifdef CONFIG_SAM34_DMAC0
/* DMA Helpers **************************************************************/
static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result);
#endif
/* Data Transfer Helpers ****************************************************/
@ -733,24 +781,37 @@ static inline void sam_enable(void)
#if defined(CONFIG_SAM34_HSMCI_XFRDEBUG) || defined(CONFIG_SAM34_HSMCI_CMDDEBUG)
static void sam_hsmcisample(struct sam_hsmciregs_s *regs)
{
regs->mr = getreg32(SAM_HSMCI_MR);
regs->dtor = getreg32(SAM_HSMCI_DTOR);
regs->sdcr = getreg32(SAM_HSMCI_SDCR);
regs->argr = getreg32(SAM_HSMCI_ARGR);
regs->blkr = getreg32(SAM_HSMCI_BLKR);
regs->cstor = getreg32(SAM_HSMCI_CSTOR);
regs->rsp0 = getreg32(SAM_HSMCI_RSPR0);
regs->rsp1 = getreg32(SAM_HSMCI_RSPR1);
regs->rsp2 = getreg32(SAM_HSMCI_RSPR2);
regs->rsp3 = getreg32(SAM_HSMCI_RSPR3);
regs->sr = getreg32(SAM_HSMCI_SR);
regs->imr = getreg32(SAM_HSMCI_IMR);
regs->mr = getreg32(SAM_HSMCI_MR);
regs->dtor = getreg32(SAM_HSMCI_DTOR);
regs->sdcr = getreg32(SAM_HSMCI_SDCR);
regs->argr = getreg32(SAM_HSMCI_ARGR);
regs->blkr = getreg32(SAM_HSMCI_BLKR);
regs->cstor = getreg32(SAM_HSMCI_CSTOR);
regs->rsp0 = getreg32(SAM_HSMCI_RSPR0);
regs->rsp1 = getreg32(SAM_HSMCI_RSPR1);
regs->rsp2 = getreg32(SAM_HSMCI_RSPR2);
regs->rsp3 = getreg32(SAM_HSMCI_RSPR3);
regs->sr = getreg32(SAM_HSMCI_SR);
regs->imr = getreg32(SAM_HSMCI_IMR);
#if defined(CONFIG_ARCH_CHIP_SAM3U)
regs->dma = getreg32(SAM_HSMCI_DMA);
regs->dma = getreg32(SAM_HSMCI_DMA);
#endif
regs->cfg = getreg32(SAM_HSMCI_CFG);
regs->wpmr = getreg32(SAM_HSMCI_WPMR);
regs->wpsr = getreg32(SAM_HSMCI_WPSR);
#ifdef CONFIG_SAM34_PDCA
regs->pdc_rpr = getreg32(SAM_HSMCI_PDC_RPR);
regs->pdc_rcr = getreg32(SAM_HSMCI_PDC_RCR);
regs->pdc_tpr = getreg32(SAM_HSMCI_PDC_TPR);
regs->pdc_tcr = getreg32(SAM_HSMCI_PDC_TCR);
regs->pdc_rnpr = getreg32(SAM_HSMCI_PDC_RNPR);
regs->pdc_rncr = getreg32(SAM_HSMCI_PDC_RNCR);
regs->pdc_tnpr = getreg32(SAM_HSMCI_PDC_TNPR);
regs->pdc_tncr = getreg32(SAM_HSMCI_PDC_TNCR);
//regs->pdc_ptcr = getreg32(SAM_HSMCI_PDC_PTCR);
regs->pdc_ptsr = getreg32(SAM_HSMCI_PDC_PTSR);
#endif
regs->cfg = getreg32(SAM_HSMCI_CFG);
regs->wpmr = getreg32(SAM_HSMCI_WPMR);
regs->wpsr = getreg32(SAM_HSMCI_WPSR);
}
#endif
@ -766,24 +827,38 @@ static void sam_hsmcisample(struct sam_hsmciregs_s *regs)
static void sam_hsmcidump(struct sam_hsmciregs_s *regs, const char *msg)
{
fdbg("HSMCI Registers: %s\n", msg);
fdbg(" MR[%08x]: %08x\n", SAM_HSMCI_MR, regs->mr);
fdbg(" DTOR[%08x]: %08x\n", SAM_HSMCI_DTOR, regs->dtor);
fdbg(" SDCR[%08x]: %08x\n", SAM_HSMCI_SDCR, regs->sdcr);
fdbg(" ARGR[%08x]: %08x\n", SAM_HSMCI_ARGR, regs->argr);
fdbg(" BLKR[%08x]: %08x\n", SAM_HSMCI_BLKR, regs->blkr);
fdbg(" CSTOR[%08x]: %08x\n", SAM_HSMCI_CSTOR, regs->cstor);
fdbg(" RSPR0[%08x]: %08x\n", SAM_HSMCI_RSPR0, regs->rsp0);
fdbg(" RSPR1[%08x]: %08x\n", SAM_HSMCI_RSPR1, regs->rsp1);
fdbg(" RSPR2[%08x]: %08x\n", SAM_HSMCI_RSPR2, regs->rsp2);
fdbg(" RSPR3[%08x]: %08x\n", SAM_HSMCI_RSPR3, regs->rsp3);
fdbg(" SR[%08x]: %08x\n", SAM_HSMCI_SR, regs->sr);
fdbg(" IMR[%08x]: %08x\n", SAM_HSMCI_IMR, regs->imr);
fdbg(" MR[%08x]: %08x\n", SAM_HSMCI_MR, regs->mr);
fdbg(" DTOR[%08x]: %08x\n", SAM_HSMCI_DTOR, regs->dtor);
fdbg(" SDCR[%08x]: %08x\n", SAM_HSMCI_SDCR, regs->sdcr);
fdbg(" ARGR[%08x]: %08x\n", SAM_HSMCI_ARGR, regs->argr);
fdbg(" BLKR[%08x]: %08x\n", SAM_HSMCI_BLKR, regs->blkr);
fdbg(" CSTOR[%08x]: %08x\n", SAM_HSMCI_CSTOR, regs->cstor);
fdbg(" RSPR0[%08x]: %08x\n", SAM_HSMCI_RSPR0, regs->rsp0);
fdbg(" RSPR1[%08x]: %08x\n", SAM_HSMCI_RSPR1, regs->rsp1);
fdbg(" RSPR2[%08x]: %08x\n", SAM_HSMCI_RSPR2, regs->rsp2);
fdbg(" RSPR3[%08x]: %08x\n", SAM_HSMCI_RSPR3, regs->rsp3);
fdbg(" SR[%08x]: %08x\n", SAM_HSMCI_SR, regs->sr);
fdbg(" IMR[%08x]: %08x\n", SAM_HSMCI_IMR, regs->imr);
#if defined(CONFIG_ARCH_CHIP_SAM3U)
fdbg(" DMA[%08x]: %08x\n", SAM_HSMCI_DMA, regs->dma);
fdbg(" DMA[%08x]: %08x\n", SAM_HSMCI_DMA, regs->dma);
#endif
fdbg(" CFG[%08x]: %08x\n", SAM_HSMCI_CFG, regs->cfg);
fdbg(" WPMR[%08x]: %08x\n", SAM_HSMCI_WPMR, regs->wpmr);
fdbg(" WPSR[%08x]: %08x\n", SAM_HSMCI_WPSR, regs->wpsr);
#ifdef CONFIG_SAM34_PDCA
fdbg("HSMCI PDC Registers:\n");
fdbg(" RPR[%08x]: %08x\n", SAM_HSMCI_PDC_RPR, regs->pdc_rpr);
fdbg(" RCR[%08x]: %08x\n", SAM_HSMCI_PDC_RCR, regs->pdc_rcr);
fdbg(" TPR[%08x]: %08x\n", SAM_HSMCI_PDC_TPR, regs->pdc_tpr);
fdbg(" TCR[%08x]: %08x\n", SAM_HSMCI_PDC_TCR, regs->pdc_tcr);
fdbg(" RNPR[%08x]: %08x\n", SAM_HSMCI_PDC_RNPR, regs->pdc_rnpr);
fdbg(" RNCR[%08x]: %08x\n", SAM_HSMCI_PDC_RNCR, regs->pdc_rncr);
fdbg(" TNPR[%08x]: %08x\n", SAM_HSMCI_PDC_TNPR, regs->pdc_tnpr);
fdbg(" TNCR[%08x]: %08x\n", SAM_HSMCI_PDC_TNCR, regs->pdc_tncr);
//fdbg(" TCR[%08x]: %08x\n", SAM_HSMCI_PDC_PTCR, regs->pdc_ptcr);
fdbg(" PTSR[%08x]: %08x\n", SAM_HSMCI_PDC_PTSR, regs->pdc_ptsr);
#endif
fdbg(" CFG[%08x]: %08x\n", SAM_HSMCI_CFG, regs->cfg);
fdbg(" WPMR[%08x]: %08x\n", SAM_HSMCI_WPMR, regs->wpmr);
fdbg(" WPSR[%08x]: %08x\n", SAM_HSMCI_WPSR, regs->wpsr);
}
#endif
@ -799,7 +874,7 @@ static void sam_hsmcidump(struct sam_hsmciregs_s *regs, const char *msg)
static void sam_xfrsample(struct sam_dev_s *priv, int index)
{
struct sam_xfrregs_s *regs = &g_xfrsamples[index];
#ifdef CONFIG_DEBUG_DMA
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_SAM34_DMAC0)
sam_dmasample(priv->dma, &regs->dma);
#endif
sam_hsmcisample(&regs->hsmci);
@ -836,7 +911,7 @@ static void sam_xfrsampleinit(void)
static void sam_xfrdumpone(struct sam_dev_s *priv,
struct sam_xfrregs_s *regs, const char *msg)
{
#ifdef CONFIG_DEBUG_DMA
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_SAM34_DMAC0)
sam_dmadump(priv->dma, &regs->dma, msg);
#endif
sam_hsmcidump(&regs->hsmci, msg);
@ -864,7 +939,7 @@ static void sam_xfrdump(struct sam_dev_s *priv)
#endif
sam_xfrdumpone(priv, &g_xfrsamples[SAMPLENDX_AFTER_SETUP], "After setup");
sam_xfrdumpone(priv, &g_xfrsamples[SAMPLENDX_END_TRANSFER], "End of transfer");
#ifdef CONFIG_DEBUG_DMA
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_SAM34_DMAC0)
sam_xfrdumpone(priv, &g_xfrsamples[SAMPLENDX_DMA_CALLBACK], "DMA Callback");
#endif
#ifdef CONFIG_SAM34_HSMCI_CMDDEBUG
@ -949,6 +1024,7 @@ static void sam_cmddump(void)
*
****************************************************************************/
#ifdef CONFIG_SAM34_DMAC0
static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result)
{
struct sam_dev_s *priv = (struct sam_dev_s *)arg;
@ -963,6 +1039,7 @@ static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result)
sam_xfrsample((struct sam_dev_s*)arg, SAMPLENDX_DMA_CALLBACK);
}
#endif
/****************************************************************************
* Data Transfer Helpers
@ -1073,6 +1150,7 @@ static void sam_endtransfer(struct sam_dev_s *priv,
sam_xfrsample(priv, SAMPLENDX_END_TRANSFER);
#ifdef CONFIG_SAM34_DMAC0
/* Make sure that the DMA is stopped (it will be stopped automatically
* on normal transfers, but not necessarily when the transfer terminates
* on an error condition.
@ -1086,6 +1164,11 @@ static void sam_endtransfer(struct sam_dev_s *priv,
putreg32(0, SAM_HSMCI_DMA);
#endif
#endif
#ifdef CONFIG_SAM34_PDCA
putreg32(PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS, SAM_HSMCI_PDC_PTCR);
#endif
/* Is a thread wait for these data transfer complete events? */
@ -1114,19 +1197,28 @@ static void sam_endtransfer(struct sam_dev_s *priv,
static void sam_notransfer(struct sam_dev_s *priv)
{
#ifdef CONFIG_SAM34_DMAC0
uint32_t regval;
regval = getreg32(SAM_HSMCI_MR);
#if defined(CONFIG_ARCH_CHIP_SAM3U)
regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF | HSMCI_MR_BLKLEN_MASK);
#else
regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF);
#endif
putreg32(regval, SAM_HSMCI_MR);
#endif
#ifdef CONFIG_SAM34_PDCA
modifyreg32(SAM_HSMCI_MR, HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF |
HSMCI_MR_PDCMODE, 0);
#endif
}
/****************************************************************************
* Interrrupt Handling
* Interrupt Handling
****************************************************************************/
/****************************************************************************
@ -1311,18 +1403,22 @@ static void sam_reset(FAR struct sdio_dev_s *dev)
/* Set the SDCard Register */
putreg32(HSMCI_SDCR_SDCSEL_SLOTA | HSMCI_SDCR_SDCBUS_4BIT, SAM_HSMCI_SDCR);
putreg32(HSMCI_SDCR_SDCSEL_SLOTA | HSMCI_SDCR_SDCBUS_1BIT, SAM_HSMCI_SDCR);
/* Enable the MCI controller */
putreg32(HSMCI_CR_MCIEN, SAM_HSMCI_CR);
#if defined(CONFIG_ARCH_CHIP_SAM3U)
/* Disable the DMA interface */
#if defined(CONFIG_ARCH_CHIP_SAM3U)
putreg32(0, SAM_HSMCI_DMA);
#endif
#ifdef CONFIG_SAM34_PDCA
putreg32(PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS, SAM_HSMCI_PDC_PTCR);
#endif
/* Configure MCI */
putreg32(HSMCI_CFG_FIFOMODE, SAM_HSMCI_CFG);
@ -1336,7 +1432,10 @@ static void sam_reset(FAR struct sdio_dev_s *dev)
priv->waitevents = 0; /* Set of events to be waited for */
priv->waitmask = 0; /* Interrupt enables for event waiting */
priv->wkupevent = 0; /* The event that caused the wakeup */
#ifdef CONFIG_SAM34_DMAC0
priv->dmabusy = false; /* No DMA in progress */
#endif
wd_cancel(priv->waitwdog); /* Cancel any timeouts */
/* Interrupt mode data transfer support */
@ -1345,7 +1444,7 @@ static void sam_reset(FAR struct sdio_dev_s *dev)
/* DMA data transfer support */
priv->widebus = false; /* Required for DMA support */
priv->widebus = false;
irqrestore(flags);
}
@ -1604,7 +1703,7 @@ static int sam_sendcmd(FAR struct sdio_dev_s *dev,
break;
}
/* 'OR' in data transer related bits */
/* 'OR' in data transfer related bits */
switch (cmd & MMCSD_DATAXFR_MASK)
{
@ -1676,9 +1775,14 @@ static void sam_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocklen,
DEBUGASSERT(dev != NULL && nblocks > 0 && nblocks < 65535 && blocklen < 65535);
/* Set the block size */
/* When TRTYP - Single or Multi, blocklen must be 1-511, 0-512 */
DEBUGASSERT(blocklen <= 512);
/* Set the block size. Clear bits followed by set */
regval = getreg32(SAM_HSMCI_MR);
#if defined(CONFIG_ARCH_CHIP_SAM3U)
regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF | HSMCI_MR_BLKLEN_MASK);
regval |= HSMCU_PROOF_BITS;
@ -1687,13 +1791,12 @@ static void sam_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocklen,
regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF);
regval |= HSMCU_PROOF_BITS;
#endif
putreg32(regval, SAM_HSMCI_MR);
/* Set the block count */
/* Set the block count register */
regval = getreg32(SAM_HSMCI_BLKR);
regval &= ~HSMCI_BLKR_BCNT_MASK;
regval |= (nblocks << HSMCI_BLKR_BCNT_SHIFT);
regval = HSMCI_BLKR_BLKLEN(blocklen) | HSMCI_BLKR_BCNT(nblocks);
putreg32(regval, SAM_HSMCI_BLKR);
}
@ -1740,8 +1843,10 @@ static int sam_cancel(FAR struct sdio_dev_s *dev)
* on an error condition.
*/
#ifdef CONFIG_SAM34_DMAC0
sam_dmastop(priv->dma);
priv->dmabusy = false;
#endif
#if defined(CONFIG_ARCH_CHIP_SAM3U)
/* Disable the DMA handshaking */
@ -1749,6 +1854,10 @@ static int sam_cancel(FAR struct sdio_dev_s *dev)
putreg32(0, SAM_HSMCI_DMA);
#endif
#ifdef CONFIG_SAM34_PDCA
putreg32(PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS, SAM_HSMCI_PDC_PTCR);
#endif
return OK;
}
@ -2157,18 +2266,6 @@ static sdio_eventset_t sam_eventwait(FAR struct sdio_dev_s *dev,
return SDIOWAIT_TIMEOUT;
}
#if 0
/* I am not sure why this is, but I am currently seeing some
* additional delays when DMA is used (On the SAMA5, might
* not be necessary for SAM3/4).
*/
if (priv->dmabusy)
{
timeout += 500;
}
#endif
/* Start the watchdog timer */
delay = (timeout + (MSEC_PER_TICK-1)) / MSEC_PER_TICK;
@ -2340,6 +2437,7 @@ static int sam_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
sam_xfrsampleinit();
sam_xfrsample(priv, SAMPLENDX_BEFORE_SETUP);
#ifdef CONFIG_SAM34_DMAC0
/* Configure the RX DMA */
sam_dmarxsetup(priv->dma, SAM_HSMCI_RDR, (uint32_t)buffer, buflen);
@ -2361,6 +2459,16 @@ static int sam_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
priv->dmabusy = true;
sam_dmastart(priv->dma, sam_dmacallback, priv);
#endif
#ifdef CONFIG_SAM34_PDCA
modifyreg32(SAM_HSMCI_MR, 0, HSMCI_MR_PDCMODE);
fdbg("SAM_HSMCI_MR = 0x%08X\n", getreg32(SAM_HSMCI_MR));
putreg32((uint32_t)buffer, SAM_HSMCI_PDC_RPR);
putreg32(buflen/4, SAM_HSMCI_PDC_RCR);
putreg32(PDC_PTCR_RXTEN, SAM_HSMCI_PDC_PTCR);
sam_xfrsample(priv, SAMPLENDX_BEFORE_ENABLE);
#endif
/* Configure transfer-related interrupts. Transfer interrupts are not
* enabled until after the transfer is stard with an SD command (i.e.,
@ -2404,6 +2512,7 @@ static int sam_dmasendsetup(FAR struct sdio_dev_s *dev,
sam_xfrsampleinit();
sam_xfrsample(priv, SAMPLENDX_BEFORE_SETUP);
#ifdef CONFIG_SAM34_DMAC0
/* Configure the TX DMA */
sam_dmatxsetup(priv->dma, SAM_HSMCI_TDR, (uint32_t)buffer, buflen);
@ -2419,6 +2528,16 @@ static int sam_dmasendsetup(FAR struct sdio_dev_s *dev,
priv->dmabusy = true;
sam_dmastart(priv->dma, sam_dmacallback, priv);
#endif
#ifdef CONFIG_SAM34_PDCA
modifyreg32(SAM_HSMCI_MR, 0, HSMCI_MR_PDCMODE);
fdbg("SAM_HSMCI_MR = 0x%08X\n", getreg32(SAM_HSMCI_MR));
putreg32((uint32_t)buffer, SAM_HSMCI_PDC_TPR);
putreg32(buflen/4, SAM_HSMCI_PDC_TCR);
putreg32(PDC_PTCR_TXTEN, SAM_HSMCI_PDC_PTCR);
sam_xfrsample(priv, SAMPLENDX_BEFORE_ENABLE);
#endif
/* Configure transfer-related interrupts. Transfer interrupts are not
* enabled until after the transfer is stard with an SD command (i.e.,
@ -2543,10 +2662,12 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
priv->waitwdog = wd_create();
DEBUGASSERT(priv->waitwdog);
#ifdef CONFIG_SAM34_DMAC0
/* Allocate a DMA channel. A FIFO size of 8 is sufficient. */
priv->dma = sam_dmachannel(DMA_FLAGS);
DEBUGASSERT(priv->dma);
#endif
/* Configure GPIOs for 4-bit, wide-bus operation. NOTE: (1) the chip is capable of
* 8-bit wide bus operation but D4-D7 are not configured, (2) any card detection