From e844610b986e47dc488537fcf7a2ec75d43ec459 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 23 Nov 2013 11:26:33 -0600 Subject: [PATCH] SAMA5 PMECC: A little more --- arch/arm/src/sama5/sam_nand.c | 7 ++- arch/arm/src/sama5/sam_pmecc.c | 106 ++++++++++++++++++++++++++++++--- arch/arm/src/sama5/sam_pmecc.h | 48 +++++++++++++++ 3 files changed, 153 insertions(+), 8 deletions(-) diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index 61430ecb43..5279e99580 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -1976,7 +1976,12 @@ struct mtd_dev_s *sam_nand_initialize(int cs) nand_putreg(SAM_HSMC_CTRL, HSMC_CTRL_NFCEN); -#ifndef NAND_HAVE_PMECC +#ifdef NAND_HAVE_PMECC + /* Perform one-time initialization of the PMECC */ + + pmecc_initialize(); + +#else /* Disable the PMECC if it is not being used */ nand_putreg(SAM_SMC_PMECCTRL, SMC_PMECCTRL_RST); diff --git a/arch/arm/src/sama5/sam_pmecc.c b/arch/arm/src/sama5/sam_pmecc.c index f95cac9583..cf8d818aae 100644 --- a/arch/arm/src/sama5/sam_pmecc.c +++ b/arch/arm/src/sama5/sam_pmecc.c @@ -50,6 +50,8 @@ #include #include +#include +#include #include #include "sam_pmecc.h" @@ -76,7 +78,14 @@ struct sam_pmecc_s { - uint8_t nsectors; /* Number of sectors in data */ + bool configured; /* True: Configured for some HSMC NAND bank */ +#if NAND_NPMECC_BANKS > 1 + sem_t exclem; /* For mutually exclusive access to the PMECC */ + uint8_t cs; /* Currently configured for this bank */ +#endif + bool sector1k; /* True: 1024B sector size; False: 512B sector size */ + uint8_t nsectors; /* Number of sectors per page */ + uint8_t correctability; /* Number of correctable bits per sector */ struct pmecc_desc_s desc; /* Atmel PMECC descriptor */ }; @@ -213,6 +222,7 @@ static void pmecc_pagelayout(uint16_t datasize, uint16_t sparesize, uint8_t nsectors1k; uint8_t bcherr512; uint8_t bcherr1k; + uint8_t bcherr; /* ECC must not start at address zero, since bad block tags are at offset * zero. @@ -249,8 +259,9 @@ static void pmecc_pagelayout(uint16_t datasize, uint16_t sparesize, DEBUGASSERT(bcherr512 > 0 || bcherr1k > 0); if (bcherr1k == 0) { - g_pmecc.nsectors = nsectors512; - g_pmecc.desc.bcherr = bcherr512; + g_pmecc.sector1k = false; + g_pmecc.nsectors = nsectors512; + bcherr = bcherr512; } else { @@ -258,21 +269,53 @@ static void pmecc_pagelayout(uint16_t datasize, uint16_t sparesize, correctability1K = nsectors1k * g_correctability[bcherr1k]; if (correctability512 >= correctability1K) { - g_pmecc.nsectors = nsectors512; - g_pmecc.desc.bcherr = ((uint32_t)bcherr512 << HSMC_PMECCFG_BCHERR_SHIFT); + g_pmecc.sector1k = false; + g_pmecc.nsectors = nsectors512; + bcherr = bcherr512; } else { - g_pmecc.nsectors = nsectors1k; - g_pmecc.desc.bcherr = ((uint32_t)bcherr1k << HSMC_PMECCFG_BCHERR_SHIFT); + g_pmecc.sector1k = true; + g_pmecc.nsectors = nsectors1k; + bcherr = bcherr1k; } } + + /* Save the correctability value */ + + g_pmecc.correctability = g_correctability[bcherr]; + + /* And the correctly shifted BCH_ERR register value */ + + g_pmecc.desc.bcherr = ((uint32_t)bcherr << HSMC_PMECCFG_BCHERR_SHIFT); } /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: pmecc_initialize + * + * Description: + * Perform one-time PMECC initialization. This must be called before any + * other PMECC interfaces are used. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if NAND_NPMECC_BANKS > 1 +void pmecc_initialize(void) +{ + sem_init(&g_pmecc.exclsem, 0, 1); +} +#endif + /**************************************************************************** * Name: pmecc_configure * @@ -281,3 +324,52 @@ static void pmecc_pagelayout(uint16_t datasize, uint16_t sparesize, * ****************************************************************************/ +/**************************************************************************** + * Name: pmecc_lock + * + * Description: + * Get exclusive access to PMECC hardware + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if NAND_NPMECC_BANKS > 1 +void pmecc_lock(void) +{ + int ret; + + do + { + ret = sem_wait(&g_pmecc.exclsem); + DEBUGASSERT(ret == OK || errno == EINTR); + } + while (ret != OK); +} +#endif + +/**************************************************************************** + * Name: pmecc_unlock + * + * Description: + * Relinquish exclusive access to PMECC hardware + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if NAND_NPMECC_BANKS > 1 +void pmecc_unlock(void) +{ + sem_post(&g_pmecc.exclsem); +} +#endif + diff --git a/arch/arm/src/sama5/sam_pmecc.h b/arch/arm/src/sama5/sam_pmecc.h index 2e2b5ec6ed..224ac3b660 100644 --- a/arch/arm/src/sama5/sam_pmecc.h +++ b/arch/arm/src/sama5/sam_pmecc.h @@ -288,6 +288,52 @@ void pmecc_enable(void); void pmecc_disable(void); +/**************************************************************************** + * Name: pmecc_initialize + * + * Description: + * Perform one-time PMECC initialization. This must be called before any + * other PMECC interfaces are used. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if NAND_NPMECC_BANKS > 1 +void pmecc_initialize(void); +#else +# define pmecc_initialize() +#endif + +/**************************************************************************** + * Name: pmecc_configure + * + * Description: + * Configure and Initialie the PMECC peripheral. + * + * Input Parameters: + * priv - Pointer to a struct sam_nandcs_s instance. + * eccoffset - offset of the first ecc byte in spare zone. + * protected - True: The spare area is protected with the last sector of + * data. + * False: The spare area is skipped in read or write mode. + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + * Assumptions: + * The caller holds the PMECC lock. + * + ****************************************************************************/ + +struct sam_nandcs_s; +int pmecc_configure(struct sam_nandcs_s *priv, uint16_t eccoffset, + bool protected); + #undef EXTERN #ifdef __cplusplus } @@ -303,6 +349,8 @@ void pmecc_disable(void); # define pmecc_unlock() # define pmecc_enable() # define pmecc_disable() +# define pmecc_initialize() +# define pmecc_configure(a,b,c) (0) #endif /* NAND_HAVE_PMECC */ #endif /* __ARCH_ARM_SRC_SAMA5_PMECC_H */