SAMA5 NAND: Don't use HSMC interrupts. They occur to quickly and cause mysterious race conditions
This commit is contained in:
parent
49bcf2da73
commit
4b8ba0cddc
@ -662,6 +662,7 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
|
||||
|
||||
static void nand_wait_cmddone(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
@ -683,6 +684,12 @@ static void nand_wait_cmddone(struct sam_nandcs_s *priv)
|
||||
g_nand.cmddone = false;
|
||||
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_CMDDONE);
|
||||
irqrestore(flags);
|
||||
|
||||
#else
|
||||
/* Poll for the CMDDONE event */
|
||||
|
||||
while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_CMDDONE) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -701,6 +708,7 @@ static void nand_wait_cmddone(struct sam_nandcs_s *priv)
|
||||
|
||||
static void nand_setup_cmddone(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
|
||||
/* Clear all pending interrupts. This must be done with interrupts
|
||||
@ -718,6 +726,11 @@ static void nand_setup_cmddone(struct sam_nandcs_s *priv)
|
||||
|
||||
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_CMDDONE);
|
||||
irqrestore(flags);
|
||||
#else
|
||||
/* Just clear any pending CMDDONE status */
|
||||
|
||||
nand_getreg(SAM_HSMC_SR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -736,6 +749,7 @@ static void nand_setup_cmddone(struct sam_nandcs_s *priv)
|
||||
|
||||
static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
@ -757,6 +771,12 @@ static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
|
||||
g_nand.xfrdone = false;
|
||||
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_XFRDONE);
|
||||
irqrestore(flags);
|
||||
|
||||
#else
|
||||
/* Poll for the XFRDONE event */
|
||||
|
||||
while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_XFRDONE) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -775,6 +795,7 @@ static void nand_wait_xfrdone(struct sam_nandcs_s *priv)
|
||||
|
||||
static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
|
||||
/* Clear all pending interrupts. This must be done with interrupts
|
||||
@ -792,6 +813,11 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
|
||||
|
||||
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_XFRDONE);
|
||||
irqrestore(flags);
|
||||
#else
|
||||
/* Just clear any pending XFRDONE status */
|
||||
|
||||
nand_getreg(SAM_HSMC_SR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -810,6 +836,7 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
|
||||
|
||||
static void nand_wait_rbedge(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
@ -831,6 +858,12 @@ static void nand_wait_rbedge(struct sam_nandcs_s *priv)
|
||||
g_nand.rbedge = false;
|
||||
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_RBEDGE0);
|
||||
irqrestore(flags);
|
||||
|
||||
#else
|
||||
/* Poll for the RBEDGE0 event */
|
||||
|
||||
while((nand_getreg(SAM_HSMC_SR) & HSMC_NFCINT_RBEDGE0) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -849,6 +882,7 @@ static void nand_wait_rbedge(struct sam_nandcs_s *priv)
|
||||
|
||||
static void nand_setup_rbedge(struct sam_nandcs_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
irqstate_t flags;
|
||||
|
||||
/* Clear all pending interrupts. This must be done with interrupts
|
||||
@ -866,6 +900,12 @@ static void nand_setup_rbedge(struct sam_nandcs_s *priv)
|
||||
|
||||
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_RBEDGE0);
|
||||
irqrestore(flags);
|
||||
|
||||
#else
|
||||
/* Just clear any pending RBEDGE0 status */
|
||||
|
||||
nand_getreg(SAM_HSMC_SR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -882,6 +922,7 @@ static void nand_setup_rbedge(struct sam_nandcs_s *priv)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
static int hsmc_interrupt(int irq, void *context)
|
||||
{
|
||||
uint32_t sr = nand_getreg(SAM_HSMC_SR);
|
||||
@ -924,6 +965,7 @@ static int hsmc_interrupt(int irq, void *context)
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_wait_dma
|
||||
@ -1251,6 +1293,8 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
#endif
|
||||
int buswidth;
|
||||
|
||||
fvdbg("nfcsram=%d buffer=%p buflen=%d\n", nfcsram, buffer, (int)buflen);
|
||||
|
||||
/* Get the buswidth */
|
||||
|
||||
buswidth = nandmodel_getbuswidth(&priv->raw.model);
|
||||
@ -1550,6 +1594,9 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
#endif
|
||||
int buswidth;
|
||||
|
||||
fvdbg("nfcsram=%d buffer=%p buflen=%d offset=%d\n",
|
||||
nfcsram, buffer, (int)buflen, (int)offset);
|
||||
|
||||
/* Get the buswidth */
|
||||
|
||||
buswidth = nandmodel_getbuswidth(&priv->raw.model);
|
||||
@ -2615,7 +2662,9 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
#if NAND_NBANKS > 1
|
||||
sem_init(&g_nand.exclsem, 0, 1);
|
||||
#endif
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
sem_init(&g_nand.waitsem, 0, 0);
|
||||
#endif
|
||||
|
||||
/* Enable the NAND FLASH Controller (The NFC is always used) */
|
||||
|
||||
@ -2634,6 +2683,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
nand_putreg(SAM_HSMC_PMECCFG, 0);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
/* Attach the CAN interrupt handler */
|
||||
|
||||
ret = irq_attach(SAM_IRQ_HSMC, hsmc_interrupt);
|
||||
@ -2642,15 +2692,17 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
fdbg("Failed to attach HSMC IRQ (%d)", SAM_IRQ_HSMC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Disable all interrupts at the HSMC */
|
||||
|
||||
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_ALL);
|
||||
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
/* Enable the HSMC interrupts at the interrupt controller */
|
||||
|
||||
up_enable_irq(SAM_IRQ_HSMC);
|
||||
g_nand.initialized = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Initialize the NAND hardware for this CS */
|
||||
|
@ -233,6 +233,17 @@
|
||||
|
||||
#ifdef CONFIG_SAMA5_HAVE_NAND
|
||||
|
||||
/* An early version of this driver used SMC interrupts to determine when
|
||||
* NAND commands completed, transfers completed, and RB edges occurred. It
|
||||
* turns out that those interrupts occurred so quickly that some really
|
||||
* nasty race conditions were created. Rather than resolve those, I simply
|
||||
* disabled the interrupt logic with this setting. The setting is retained
|
||||
* in case, for some reason, someone wants to restore the interrupt-driven
|
||||
* logic. Polling should be better solution in this case.
|
||||
*/
|
||||
|
||||
#undef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -274,10 +285,12 @@ struct sam_nand_s
|
||||
|
||||
/* Dynamic state */
|
||||
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
volatile bool cmddone; /* True: NFC command has completed */
|
||||
volatile bool xfrdone; /* True: Transfer has completed */
|
||||
volatile bool rbedge; /* True: Ready/busy edge detected */
|
||||
sem_t waitsem; /* Used to wait for one of the above states */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_HAVE_PMECC
|
||||
uint8_t ecctab[CONFIG_MTD_NAND_MAX_PMECCSIZE];
|
||||
|
Loading…
Reference in New Issue
Block a user