/**************************************************************************** * arch/arm/src/sama5/sam_nand.h * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ #ifndef __ARCH_ARM_SRC_SAMA5_SAM_NAND_H #define __ARCH_ARM_SRC_SAMA5_SAM_NAND_H /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "up_arch.h" #include "chip.h" #include "chip/sam_hsmc.h" #include "sam_dmac.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Configuration ************************************************************/ /* DMA */ #ifdef CONFIG_SAMA5_NAND_DMA # if defined(CONFIG_SAMA5_DMAC1) # define NAND_DMAC 1 # elif defined(CONFIG_SAMA5_DMAC0) # define NAND_DMAC 0 # else # error "A DMA controller must be enabled to perform DMA transfers" # undef CONFIG_SAMA5_NAND_DMA # endif #endif /* Hardware ECC types. These are extensions to the NANDECC_HWECC value * defined in include/nuttx/mtd/nand_raw.h. * * NANDECC_CHIPECC ECC is performed internal to chip * NANDECC_PMECC Programmable Multibit Error Correcting Code (PMECC) */ #define NANDECC_CHIPECC (NANDECC_HWECC + 0) #define NANDECC_PMECC (NANDECC_HWECC + 1) /* Per NAND bank ECC selections */ #if defined(CONFIG_SAMA5_EBICS0_NAND) # if defined(CONFIG_SAMA5_EBICS0_ECCNONE) # define SAMA5_EBICS0_ECCTYPE NANDECC_NONE # elif defined(CONFIG_SAMA5_EBICS0_SWECC) # ifndef CONFIG_MTD_NAND_SWECC # error CONFIG_SAMA5_EBICS0_SWECC is an invalid selection # endif # define SAMA5_EBICS0_ECCTYPE NANDECC_SWECC # elif defined(CONFIG_SAMA5_EBICS0_PMECC) # ifndef CONFIG_MTD_NAND_HWECC # error CONFIG_SAMA5_EBICS0_PMECC is an invalid selection # endif # define SAMA5_EBICS0_ECCTYPE NANDECC_PMECC # elif defined(CONFIG_SAMA5_EBICS0_CHIPECC) # ifndef CONFIG_MTD_NAND_EMBEDDEDECC # error CONFIG_SAMA5_EBICS0_CHIPECC is an invalid selection # endif # define SAMA5_EBICS0_ECCTYPE NANDECC_CHIPECC # else # error "No ECC type specified for CS0" # endif #endif /* CONFIG_SAMA5_EBICS0_NAND */ #if defined(CONFIG_SAMA5_EBICS1_NAND) # if defined(CONFIG_SAMA5_EBICS1_ECCNONE) # define SAMA5_EBICS1_ECCTYPE NANDECC_NONE # elif defined(CONFIG_SAMA5_EBICS1_SWECC) # ifndef CONFIG_MTD_NAND_SWECC # error CONFIG_SAMA5_EBICS1_SWECC is an invalid selection # endif # define SAMA5_EBICS1_ECCTYPE NANDECC_SWECC # elif defined(CONFIG_SAMA5_EBICS1_PMECC) # ifndef CONFIG_MTD_NAND_HWECC # error CONFIG_SAMA5_EBICS1_PMECC is an invalid selection # endif # define SAMA5_EBICS1_ECCTYPE NANDECC_PMECC # elif defined(CONFIG_SAMA5_EBICS1_CHIPECC) # ifndef CONFIG_MTD_NAND_EMBEDDEDECC # error CONFIG_SAMA5_EBICS1_CHIPECC is an invalid selection # endif # define SAMA5_EBICS1_ECCTYPE NANDECC_CHIPECC # else # error "No ECC type specified for CS1" # endif #endif /* CONFIG_SAMA5_EBICS1_NAND */ #if defined(CONFIG_SAMA5_EBICS2_NAND) # if defined(CONFIG_SAMA5_EBICS2_ECCNONE) # define SAMA5_EBICS2_ECCTYPE NANDECC_NONE # elif defined(CONFIG_SAMA5_EBICS2_SWECC # ifndef CONFIG_MTD_NAND_SWECC # error CONFIG_SAMA5_EBICS2_SWECC is an invalid selection # endif # define SAMA5_EBICS2_ECCTYPE NANDECC_SWECC # elif defined(CONFIG_SAMA5_EBICS2_PMECC) # ifndef CONFIG_MTD_NAND_HWECC # error CONFIG_SAMA5_EBICS2_PMECC is an invalid selection # endif # define SAMA5_EBICS2_ECCTYPE NANDECC_PMECC # elif defined(CONFIG_SAMA5_EBICS2_CHIPECC) # ifndef CONFIG_MTD_NAND_EMBEDDEDECC # error CONFIG_SAMA5_EBICS2_CHIPECC is an invalid selection # endif # define SAMA5_EBICS2_ECCTYPE NANDECC_CHIPECC # else # error "No ECC type specified for CS2" # endif #endif /* CONFIG_SAMA5_EBICS2_NAND */ #if defined(CONFIG_SAMA5_EBICS3_NAND) # if defined(CONFIG_SAMA5_EBICS3_ECCNONE) # define SAMA5_EBICS3_ECCTYPE NANDECC_NONE # elif defined(CONFIG_SAMA5_EBICS3_SWECC) # ifndef CONFIG_MTD_NAND_SWECC # error CONFIG_SAMA5_EBICS3_SWECC is an invalid selection # endif # define SAMA5_EBICS3_ECCTYPE NANDECC_SWECC # elif defined(CONFIG_SAMA5_EBICS3_PMECC) # ifndef CONFIG_MTD_NAND_HWECC # error CONFIG_SAMA5_EBICS3_PMECC is an invalid selection # endif # define SAMA5_EBICS3_ECCTYPE NANDECC_PMECC # elif defined(CONFIG_SAMA5_EBICS3_CHIPECC) # ifndef CONFIG_MTD_NAND_EMBEDDEDECC # error CONFIG_SAMA5_EBICS3_CHIPECC is an invalid selection # endif # define SAMA5_EBICS3_ECCTYPE NANDECC_CHIPECC # else # error "No ECC type specified for CS3" # endif #endif /* CONFIG_SAMA5_EBICS3_NAND */ /* Count the number of banks that configured for NAND with PMECC support * enabled. */ #undef CONFIG_SAMA5_HAVE_NAND #ifdef CONFIG_SAMA5_EBICS0_NAND # define CONFIG_SAMA5_HAVE_NAND 1 # define NAND_HAVE_EBICS0 1 #else # define NAND_HAVE_EBICS0 0 #endif #ifdef CONFIG_SAMA5_EBICS1_NAND # define CONFIG_SAMA5_HAVE_NAND 1 # define NAND_HAVE_EBICS1 1 #else # define NAND_HAVE_EBICS1 0 #endif #ifdef CONFIG_SAMA5_EBICS2_NAND # define CONFIG_SAMA5_HAVE_NAND 1 # define NAND_HAVE_EBICS2 1 #else # define NAND_HAVE_EBICS2 0 #endif #ifdef CONFIG_SAMA5_EBICS3_NAND # define CONFIG_SAMA5_HAVE_NAND 1 # define NAND_HAVE_EBICS3 1 #else # define NAND_HAVE_EBICS3 0 #endif #ifdef CONFIG_SAMA5_HAVE_NAND /* Count the number of banks configured for NAND */ #define NAND_NBANKS \ (NAND_HAVE_EBICS0 + NAND_HAVE_EBICS1 + NAND_HAVE_EBICS2 + NAND_HAVE_EBICS3) /* Debug */ #if !defined(CONFIG_DEBUG) # undef CONFIG_DEBUG_FS # undef CONFIG_SAMA5_NAND_REGDEBUG # undef CONFIG_SAMA5_NAND_DUMP #endif /* 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 ****************************************************************************/ /* This type represents the state of a raw NAND MTD device on a single chip * select. The struct nand_raw_s must appear at the beginning of the * definition so that you can freely cast between pointers to struct * nand_raw_s and struct sam_nandcs_s. * * NOTE: Currently, only SAMA5D3x CS3 can support NAND. The logic here would * support NAND on any CS, but that capability is not needed. */ struct sam_nandcs_s { struct nand_raw_s raw; /* Externally visible part of the driver */ /* Static configuration */ uint8_t cs; /* Chip select number (0..3) */ #ifdef CONFIG_SAMA5_NAND_DMA volatile bool dmadone; /* True: DMA has completed */ #endif #ifdef CONFIG_SAMA5_PMECC_TRIMPAGE bool dropjss; /* Enable page trimming */ uint16_t trimpage; /* Trim page number boundary */ #endif #ifdef CONFIG_SAMA5_NAND_DMA sem_t waitsem; /* Used to wait for DMA done */ DMA_HANDLE dma; /* DMA channel assigned to this CS */ int result; /* The result of the DMA */ #endif }; struct sam_nand_s { bool initialized; /* True: One time initialization is complete */ #if NAND_NBANKS > 1 sem_t exclsem; /* Enforce exclusive access to the SMC hardware */ #endif /* Dynamic state */ #ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS volatile bool cmddone; /* True: NFC command has completed (latching) */ volatile bool xfrdone; /* True: Transfer has completed (latching) */ volatile bool rbedge; /* True: Ready/busy edge detected (latching) */ sem_t waitsem; /* Used to wait for one of the above states */ #else bool cmddone; /* True: NFC command has completed (latching) */ bool xfrdone; /* True: Transfer has completed (latching) */ bool rbedge; /* True: Ready/busy edge detected (latching) */ #endif #ifdef CONFIG_SAMA5_HAVE_PMECC uint8_t ecctab[CONFIG_MTD_NAND_MAX_PMECCSIZE]; #endif #ifdef CONFIG_SAMA5_NAND_REGDEBUG /* Register debug state */ bool wr; /* Last was a write */ uint32_t regadddr; /* Last address */ uint32_t regval; /* Last value */ int ntimes; /* Number of times */ #endif }; /**************************************************************************** * Public Data ****************************************************************************/ #ifndef __ASSEMBLY__ #undef EXTERN #if defined(__cplusplus) #define EXTERN extern "C" extern "C" { #else #define EXTERN extern #endif /* NAND global state */ EXTERN struct sam_nand_s g_nand; /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sam_nand_initialize * * Description: * Create and initialize an raw NAND device instance. This driver * implements the RAW NAND interface: No software ECC or sparing is * performed here. Those necessary NAND features are provided by common, * higher level NAND MTD layers found in drivers/mtd. * * Input parameters: * cs - Chip select number (in the event that multiple NAND devices * are connected on-board). * * Returned value. * On success a non-NULL pointer to an MTD device structure is returned; * NULL is returned on a failure. * ****************************************************************************/ struct mtd_dev_s; struct mtd_dev_s *sam_nand_initialize(int cs); /**************************************************************************** * Name: board_nandflash_config * * Description: * If CONFIG_SAMA5_BOOT_CS3FLASH is defined, then NAND FLASH support is * enabled. This function provides the board-specific implementation of * the logic to reprogram the SMC to support NAND FLASH on the specified * CS. * * Input Parameters: * cs - Chip select number (in the event that multiple NAND devices * are connected on-board). * * Returned Values: * OK if the HSMC was successfully configured for this CS. A negated * errno value is returned on a failure. This would fail with -ENODEV, * for example, if the board does not support NAND FLASH on the requested * CS. * ****************************************************************************/ int board_nandflash_config(int cs); /**************************************************************************** * Name: board_nand_busy * * Description: * Must be provided if the board logic supports and interface to detect * NAND Busy/Ready signal. * * Input Parameters: * cs - Chip select number (in the event that multiple NAND devices * are connected on-board). * * Returned Values: * True: NAND is busy, False: NAND is ready * ****************************************************************************/ #ifdef CONFIG_SAMA5_NAND_READYBUSY bool board_nand_busy(int cs); #endif /**************************************************************************** * Name: board_nandflash_config * * Description: * Must be provided if the board logic supports and interface to control * the NAND Chip Enable signal. * * Input Parameters: * cs - Chip select number (in the event that multiple NAND devices * are connected on-board). * enable - True: enable Chip Select, False: Disable Chip select * * Returned Values: * OK if the HSMC was successfully configured for this CS. A negated * errno value is returned on a failure. This would fail with -ENODEV, * for example, if the board does not support NAND FLASH on the requested * CS. * ****************************************************************************/ #ifdef CONFIG_SAMA5_NAND_CE void board_nand_ce(int cs, bool enable); #endif /**************************************************************************** * Name: nand_checkreg * * Description: * Check if the current HSMC register access is a duplicate of the preceding. * * Input Parameters: * regval - The value to be written * regaddr - The address of the register to write to * * Returned Value: * true: This is the first register access of this type. * flase: This is the same as the preceding register access. * ****************************************************************************/ #ifdef CONFIG_SAMA5_NAND_REGDEBUG bool nand_checkreg(bool wr, uintptr_t regaddr, uint32_t regval); #endif /**************************************************************************** * Name: nand_getreg * * Description: * Read an HSMC register * ****************************************************************************/ static inline uint32_t nand_getreg(uintptr_t regaddr) { uint32_t regval = getreg32(regaddr); #ifdef CONFIG_SAMA5_NAND_REGDEBUG if (nand_checkreg(false, regaddr, regval)) { lldbg("%08x->%08x\n", regaddr, regval); } #endif return regval; } /**************************************************************************** * Name: nand_putreg * * Description: * Write a value to an HSMC register * ****************************************************************************/ static inline void nand_putreg(uintptr_t regaddr, uint32_t regval) { #ifdef CONFIG_SAMA5_NAND_REGDEBUG if (nand_checkreg(true, regaddr, regval)) { lldbg("%08x<-%08x\n", regaddr, regval); } #endif putreg32(regval, regaddr); } /**************************************************************************** * Name: nand_trimffs_enable * * Description: * Set current trimffs status. * * Input Parameters: * * Returned Value: * * ****************************************************************************/ #ifdef CONFIG_SAMA5_PMECC_TRIMPAGE static inline void nand_trimffs_enable(struct sam_nandcs_s *priv, bool enable) { priv->dropjss = enable; } #else # define nand_trimffs_enable(p,e) #endif /**************************************************************************** * Name: nand_trrimffs * * Description: * Get current trimffs status. * * Input Parameters: * * Returned Value: * * ****************************************************************************/ #ifdef CONFIG_SAMA5_PMECC_TRIMPAGE static inline bool nand_trrimffs(struct sam_nandcs_s *priv) { return priv->dropjss; } #else # define nand_trrimffs(p) (false) #endif /**************************************************************************** * Name: nand_set_trimpage * * Description: * Set current trimffs page. * * Input Parameters: * page - Start trim page. * * Returned Value: * * ****************************************************************************/ #ifdef CONFIG_SAMA5_PMECC_TRIMPAGE static inline void nand_set_trimpage(struct sam_nandcs_s *priv, uint16_t page) { priv->trimpage = page; } #else # define nand_set_trimpage(p,t) #endif /**************************************************************************** * Name: nand_get_trimpage * * Description: * Get current trimffs page. * * Input Parameters: * None * * Returned Value: * Start trim page. * ****************************************************************************/ #ifdef CONFIG_SAMA5_PMECC_TRIMPAGE uint16_t nand_get_trimpage(struct sam_nandcs_s *priv) { return priv->trimpage; } #else # define nand_get_trimpage(p) (0) #endif #undef EXTERN #if defined(__cplusplus) } #endif #endif /* __ASSEMBLY__ */ #endif /* CONFIG_SAMA5_HAVE_NAND */ #endif /* __ARCH_ARM_SRC_SAMA5_SAM_NAND_H */