diff --git a/arch/arm/src/sama5/chip/sam_hsmc.h b/arch/arm/src/sama5/chip/sam_hsmc.h index fbd6de24a1..c7fa83f3dd 100644 --- a/arch/arm/src/sama5/chip/sam_hsmc.h +++ b/arch/arm/src/sama5/chip/sam_hsmc.h @@ -53,6 +53,9 @@ #define HSMC_CS2 2 #define HSMC_CS3 3 +#define NFCSRAM_BASE SAM_NFCSRAM_VSECTION +#define NFCCMD_BASE SAM_NFCCR_VSECTION + /* SMC Register Offsets *************************************************************/ #define SAM_HSMC_CFG_OFFSET 0x0000 /* HSMC NFC Configuration Register */ @@ -572,4 +575,50 @@ #define HSMC_WPSR_WPVSRC_SHIFT (8) /* Bit 8-23: Write Protection Violation Source */ #define HSMC_WPSR_WPVSRC_MASK (0xffff << HSMC_WPSR_WPVSRC_SHIFT) +/* NFC Command/Data Registers *******************************************************/ + +#define NFCADDR_CMD_CMD1_SHIFT (2) /* Bits 2-9: Command Register Value for Cycle 1 */ +#define NFCADDR_CMD_CMD1_MASK (0xff << NFCADDR_CMD_CMD1_SHIFT) +# define NFCADDR_CMD_CMD1(n) ((uint32_t)(n) << NFCADDR_CMD_CMD1_SHIFT) +#define NFCADDR_CMD_CMD2_SHIFT (10) /* Bits 10-17: Command Register Value for Cycle 1 */ +#define NFCADDR_CMD_CMD2_MASK (0xff << NFCADDR_CMD_CMD2_SHIFT) +# define NFCADDR_CMD_CMD2(n) ((uint32_t)(n) << NFCADDR_CMD_CMD2_SHIFT) +#define NFCADDR_CMD_VCMD2 (1 << 18) /* Bit 18:Valid Cycle 2 Command */ +#define NFCADDR_CMD_ACYCLE_SHIFT (19) /* Bits 19-21: Number of Address required for command */ +#define NFCADDR_CMD_ACYCLE_MASK (7 << NFCADDR_CMD_ACYCLE_SHIFT) +# define NFCADDR_CMD_ACYCLE_NONE (0 << NFCADDR_CMD_ACYCLE_SHIFT) /* No address cycle */ +# define NFCADDR_CMD_ACYCLE_ONE (1 << NFCADDR_CMD_ACYCLE_SHIFT) /* One address cycle */ +# define NFCADDR_CMD_ACYCLE_TWO (2 << NFCADDR_CMD_ACYCLE_SHIFT) /* Two address cycles */ +# define NFCADDR_CMD_ACYCLE_THREE (3 << NFCADDR_CMD_ACYCLE_SHIFT) /* Three address cycles */ +# define NFCADDR_CMD_ACYCLE_FOUR (4 << NFCADDR_CMD_ACYCLE_SHIFT) /* Four address cycles */ +# define NFCADDR_CMD_ACYCLE_FIVE (5 << NFCADDR_CMD_ACYCLE_SHIFT) /* Five address cycles */ +#define NFCADDR_CMD_CSID_SHIFT (22) /* Bits 22-24: Chip Select Identifier */ +#define NFCADDR_CMD_CSID_MASK (7 << NFCADDR_CMD_CSID_SHIFT) /* Bits 22-24: Chip Select Identifier */ +# define NFCADDR_CMD_CSID_0 (0 << NFCADDR_CMD_CSID_SHIFT) /* CS0 */ +# define NFCADDR_CMD_CSID_1 (1 << NFCADDR_CMD_CSID_SHIFT) /* CS1 */ +# define NFCADDR_CMD_CSID_2 (2 << NFCADDR_CMD_CSID_SHIFT) /* CS2 */ +# define NFCADDR_CMD_CSID_3 (3 << NFCADDR_CMD_CSID_SHIFT) /* CS3 */ +# define NFCADDR_CMD_CSID_4 (4 << NFCADDR_CMD_CSID_SHIFT) /* CS4 */ +# define NFCADDR_CMD_CSID_5 (5 << NFCADDR_CMD_CSID_SHIFT) /* CS5 */ +# define NFCADDR_CMD_CSID_6 (6 << NFCADDR_CMD_CSID_SHIFT) /* CS6 */ +# define NFCADDR_CMD_CSID_7 (7 << NFCADDR_CMD_CSID_SHIFT) /* CS7 */ +#define NFCADDR_CMD_DATAEN (1 << 25) /* Bit 25: 1=NFC Data Enable */ +#define NFCADDR_CMD_DATADIS (0 << 25) /* Bit 25: 0=NFC Data disable */ +#define NFCADDR_CMD_NFCRD (0 << 26) /* Bit 26: 0=NFC Read Enable */ +#define NFCADDR_CMD_NFCWR (1 << 26) /* Bit 26: 1=NFC Write Enable */ +#define NFCADDR_CMD_NFCCMD (1 << 27) /* Bit 27: 1=NFC Command Enable */ + +#define NFCDATA_ADDT_CYCLE1_SHIFT (0) /* Bits 0-7: NAND Flash Array Address Cycle 1 */ +#define NFCDATA_ADDT_CYCLE1_MASK (0xff << NFCDATA_ADDT_CYCLE1_SHIFT) +# define NFCDATA_ADDT_CYCLE1(n) ((uint32_t)(n) << NFCDATA_ADDT_CYCLE1_SHIFT) +#define NFCDATA_ADDT_CYCLE2_SHIFT (8) /* Bits 8-15: NAND Flash Array Address Cycle 2 */ +#define NFCDATA_ADDT_CYCLE2_MASK (0xff << NFCDATA_ADDT_CYCLE2_SHIFT) +# define NFCDATA_ADDT_CYCLE2(n) ((uint32_t)(n) << NFCDATA_ADDT_CYCLE2_SHIFT) +#define NFCDATA_ADDT_CYCLE3_SHIFT (nn) /* Bits 16-23: NAND Flash Array Address Cycle 3 */ +#define NFCDATA_ADDT_CYCLE3_MASK (16 << NFCDATA_ADDT_CYCLE3_SHIFT) +# define NFCDATA_ADDT_CYCLE3(n) ((uint32_t)(n) << NFCDATA_ADDT_CYCLE3_SHIFT) +#define NFCDATA_ADDT_CYCLE4_SHIFT (24) /* Bits 24-31: NAND Flash Array Address Cycle 4 */ +#define NFCDATA_ADDT_CYCLE4_MASK (0xff << NFCDATA_ADDT_CYCLE4_SHIFT) +# define NFCDATA_ADDT_CYCLE4(n) ((uint32_t)(n) << NFCDATA_ADDT_CYCLE4_SHIFT) + #endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_HSMC_H */ diff --git a/arch/arm/src/sama5/sam_hsmci.c b/arch/arm/src/sama5/sam_hsmci.c index d73e307ca2..1028dd12fe 100644 --- a/arch/arm/src/sama5/sam_hsmci.c +++ b/arch/arm/src/sama5/sam_hsmci.c @@ -681,7 +681,7 @@ static bool sam_checkreg(struct sam_dev_s *priv, bool wr, uint32_t value, * Name: sam_getreg * * Description: - * Read an SPI register + * Read an HSMCI register * ****************************************************************************/ @@ -704,7 +704,7 @@ static inline uint32_t sam_getreg(struct sam_dev_s *priv, unsigned int offset) * Name: sam_putreg * * Description: - * Write a value to an SPI register + * Write a value to an HSMCI register * ****************************************************************************/ diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index 0bac4bb998..d46bbe9e77 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -64,6 +64,8 @@ #include +#include "up_arch.h" + #include "sam_pmecc.h" #include "sam_nand.h" @@ -71,65 +73,94 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_SAMA5_NAND_CE +# define ENABLE_CE(priv) board_nand_ce(priv->cs, true) +# define DISABLE_CE(priv) board_nand_ce(priv->cs, false) +#else +# define ENABLE_CE(priv) +# define DISABLE_CE(priv) +#endif + +/* Nand flash chip status codes */ + +#define STATUS_ERROR (1 << 0) +#define STATUS_READY (1 << 6) + +/* + * NFC ALE CLE command paramter + */ +#define SMC_ALE_COL_EN (1 << 0) +#define SMC_ALE_ROW_EN (1 << 1) +#define SMC_CLE_WRITE_EN (1 << 2) +#define SMC_CLE_DATA_EN (1 << 3) +#define SMC_CLE_VCMD2_EN (1 << 4) + /**************************************************************************** * Private Types ****************************************************************************/ -/* This type represents the state of the raw NAND MTD device. 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_rawnand_s. - */ - -struct sam_rawnand_s -{ - struct nand_raw_s raw; /* Externally visible part of the driver */ - uint8_t cs; /* Chip select number (0..3) */ -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -/* NAND Helpers */ +/* Low-level HSMC Helpers */ -static int nand_readpage_noecc(struct sam_rawnand_s *priv, off_t block, - unsigned int page, void *data, void *spare); +static void nand_nfccmd_waitdone(void); +static void nand_nfccmd_send(uint32_t cmd, uint32_t acycle, + uint32_t cycle0); +static bool nand_operation_complete(struct sam_nandcs_s *priv); +static void nand_coladdr_write(struct sam_nandcs_s *priv, + uint16_t coladdr); +static void nand_rowaddr_write(struct sam_nandcs_s *priv, + uint32_t rowaddr); +static int nand_translate_address(struct sam_nandcs_s *priv, + uint16_t coladdr, uint32_t rowaddr, uint32_t *acycle0, + uint32_t *acycle1234, bool rowonly); +static uint32_t nand_get_acycle(int ncycles); +static void nand_nfc_configure(struct sam_nandcs_s *priv, + uint8_t mode, uint32_t cmd1, uint32_t cmd2, + uint32_t coladdr, uint32_t rowaddr); + +/* NAND Access Helpers */ + +static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block, + unsigned int page, void *data, void *spare); #ifdef NAND_HAVE_HSIAO -static int nand_readpage_hsiao(struct sam_rawnand_s *priv, off_t block, - unsigned int page, void *data, void *spare); +static int nand_readpage_hsiao(struct sam_nandcs_s *priv, off_t block, + unsigned int page, void *data, void *spare); #endif #ifdef NAND_HAVE_PMECC -static int nand_readpage_pmecc(struct sam_rawnand_s *priv, off_t block, - unsigned int page, void *data); +static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block, + unsigned int page, void *data); #endif -static int nand_writepage_noecc(struct sam_rawnand_s *priv, off_t block, - unsigned int page, const void *data, const void *spare); +static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block, + unsigned int page, const void *data, const void *spare); #ifdef NAND_HAVE_HSIAO -static int nand_writepage_hsiao(struct sam_rawnand_s *priv, off_t block, - unsigned int page, const void *data, const void *spare); +static int nand_writepage_hsiao(struct sam_nandcs_s *priv, off_t block, + unsigned int page, const void *data, const void *spare); #endif #ifdef NAND_HAVE_PMECC -static int nand_writepage_pmecc(struct sam_rawnand_s *priv, off_t block, - unsigned int page, const void *data); +static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block, + unsigned int page, const void *data); #endif /* MTD driver methods */ -static int nand_eraseblock(struct nand_raw_s *raw, off_t block); -static int nand_rawread(struct nand_raw_s *raw, off_t block, - unsigned int page, void *data, void *spare); -static int nand_rawwrite(struct nand_raw_s *raw, off_t block, - unsigned int page, const void *data, const void *spare); +static int nand_eraseblock(struct nand_raw_s *raw, off_t block); +static int nand_rawread(struct nand_raw_s *raw, off_t block, + unsigned int page, void *data, void *spare); +static int nand_rawwrite(struct nand_raw_s *raw, off_t block, + unsigned int page, const void *data, const void *spare); #ifdef CONFIG_MTD_NAND_HWECC -static int nand_readpage(struct nand_raw_s *raw, off_t block, - unsigned int page, void *data, void *spare); -static int nand_writepage(struct nand_raw_s *raw, off_t block, - unsigned int page, const void *data, const void *spare); +static int nand_readpage(struct nand_raw_s *raw, off_t block, + unsigned int page, void *data, void *spare); +static int nand_writepage(struct nand_raw_s *raw, off_t block, + unsigned int page, const void *data, const void *spare); #endif /**************************************************************************** @@ -140,22 +171,471 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block, */ #ifdef CONFIG_SAMA5_EBICS0_NAND -static struct sam_rawnand_s g_cs0nand; +static struct sam_nandcs_s g_cs0nand; #endif #ifdef CONFIG_SAMA5_EBICS1_NAND -static struct sam_rawnand_s g_cs1nand; +static struct sam_nandcs_s g_cs1nand; #endif #ifdef CONFIG_SAMA5_EBICS2_NAND -static struct sam_rawnand_s g_cs2nand; +static struct sam_nandcs_s g_cs2nand; #endif #ifdef CONFIG_SAMA5_EBICS3_NAND -static struct sam_rawnand_s g_cs3nand; +static struct sam_nandcs_s g_cs3nand; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* NAND regiser debug state */ + +#ifdef CONFIG_SAMA5_NAND_REGDEBUG +struct sam_nanddbg_s g_nanddbg; #endif /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nand_nfccmd_waitdone + * + * Description: + * Wait for NFC command done + * + * Input parameters: + * None + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_nfccmd_waitdone(void) +{ +#warning Missing logic +} + +/**************************************************************************** + * Name: nand_nfccmd_waitdone + * + * Description: + * Waiting for the completion of a page program, erase and random read + * completion. + * + * Input parameters: + * priv Pointer to a sam_nandcs_s instance. + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_waitready(struct sam_nandcs_s *priv) +{ +#ifdef SAMA5_NAND_READYBUSY + while (board_nand_busy(priv->cs)); +#endif + nand_nfc_configure(priv, 0, COMMAND_STATUS, 0, 0, 0); + while ((READ_DATA8(&priv->raw) & STATUS_READY) == 0); +} + +/**************************************************************************** + * Name: nand_nfccmd_send + * + * Description: + * Use the HOST nandflash controller to send a command to the NFC. + * + * Input parameters: + * cmd - command to send + * acycle - address cycle when command access id decoded + * cycle0 - address at first cycle + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_nfccmd_send(uint32_t cmd, uint32_t acycle, uint32_t cycle0) +{ + uintptr_t cmdaddr; + + /* Wait until host controller is not busy. */ + + while ((nand_getreg(NFCCMD_BASE + NFCADDR_CMD_NFCCMD) & 0x8000000) != 0); + + /* Send the command plus the ADDR_CYCLE */ + + cmdaddr = NFCCMD_BASE + cmd; + nand_putreg(SAM_HSMC_ADDR, cycle0); + nand_putreg(cmdaddr, acycle); + + /* Wait for the command transfer to complete */ + + nand_nfccmd_waitdone(); +} + +/**************************************************************************** + * Name: nand_coladdr_write + * + * Description: + * Check if a program or erase operation completed successfully + * + * Input parameters: + * priv - Lower-half, private NAND FLASH device state + * + * Returned value. + * None + * + ****************************************************************************/ + +static bool nand_operation_complete(struct sam_nandcs_s *priv) +{ + uint8_t status; + + nand_nfc_configure(priv, 0, COMMAND_STATUS, 0, 0, 0); + status = READ_DATA8(&priv->raw); + + if (((status & STATUS_READY) == 0) || ((status & STATUS_ERROR) != 0)) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Name: nand_coladdr_write + * + * Description: + * Send a column address to the NAND FLASH chip. + * + * Input parameters: + * priv - Lower-half, private NAND FLASH device state + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_coladdr_write(struct sam_nandcs_s *priv, uint16_t coladdr) +{ + uint16_t pagesize = nandmodel_getpagesize(&priv->raw.model); + + /* Check the data bus width of the NAND FLASH */ + + if (nandmodel_getbuswidth(&priv->raw.model) == 16) + { + /* Use word vs byte addressing */ + + coladdr >>= 1; + } + + /* Send single column address byte for small block devices, or two column + * address bytes for large block devices + */ + + while (pagesize > 2) + { + if (nandmodel_getbuswidth(&priv->raw.model) == 16) + { + WRITE_ADDRESS16(&priv->raw, coladdr & 0xff); + } + else + { + WRITE_ADDRESS8(&priv->raw, coladdr & 0xff); + } + + pagesize >>= 8; + coladdr >>= 8; + } +} + +/**************************************************************************** + * Name: nand_rowaddr_write + * + * Description: + * Send a row address to the NAND FLASH chip. + * + * Input parameters: + * priv - Lower-half, private NAND FLASH device state + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_rowaddr_write(struct sam_nandcs_s *priv, uint32_t rowaddr) +{ + uint32_t npages = nandmodel_getdevpagesize(&priv->raw.model); + + while (npages > 0) + { + if (nandmodel_getbuswidth(&priv->raw.model) == 16) + { + WRITE_ADDRESS16(&priv->raw, rowaddr & 0xff); + } + else + { + WRITE_ADDRESS8(&priv->raw, rowaddr & 0xff); + } + + npages >>= 8; + rowaddr >>= 8; + } +} + +/**************************************************************************** + * Name: nand_translate_address + * + * Description: + * Translates the given column and row address into first and other (1-4) + * address cycles. The resulting values are stored in the provided + * variables if they are not null. + * + * Input parameters: + * priv - Lower-half, private NAND FLASH device state + * coladdr - Column address to translate. + * rowaddr - Row address to translate. + * acycle0 - First address cycle + * acycle1234 - Four address cycles. + * rowonly - True:Only ROW address is used. + * + * Returned value. + * Number of address cycles converted. + * + ****************************************************************************/ + +static int nand_translate_address(struct sam_nandcs_s *priv, + uint16_t coladdr, uint32_t rowaddr, + uint32_t *acycle0, uint32_t *acycle1234, + bool rowonly) +{ + uint16_t maxsize; + uint32_t page; + uint32_t accum0; + uint32_t accum1234; + uint8_t bytes[8]; + int ncycles; + int ndx; + int pos; + + /* Setup */ + + maxsize = nandmodel_getpagesize(&priv->raw.model) + + nandmodel_getsparesize(&priv->raw.model) - 1; + page = nandmodel_getdevpagesize(&priv->raw.model) - 1; + ncycles = 0; + accum0 = 0; + accum1234 = 0; + + /* Check the data bus width of the NAND FLASH */ + + if (nandmodel_getbuswidth(&priv->raw.model) == 16) + { + /* Use word vs. bytes addressing */ + + coladdr >>= 1; + } + + /* Convert column address */ + + if (!rowonly) + { + /* Send single column address byte for small block devices, or two + * column address bytes for large block devices + */ + + while (maxsize > 2) + { + bytes[ncycles++] = coladdr & 0xff; + maxsize >>= 8; + coladdr >>= 8; + } + } + + /* Convert row address */ + + while (page > 0) + { + bytes[ncycles++] = rowaddr & 0xff; + page >>= 8; + rowaddr >>= 8; + } + + /* Build acycle0 and acycle1234 */ + + ndx = 0; + + /* If more than 4 cycles, acycle0 is used */ + + if (ncycles > 4) + { + for (pos = 0; ndx < ncycles - 4; ndx++) + { + accum0 += bytes[ndx] << pos; + pos += 8; + } + } + + /* acycle1234 */ + + for (pos = 0; ndx < ncycles; ndx++) + { + accum1234 += bytes[ndx] << pos; + pos += 8; + } + + /* Store values */ + + if (acycle0) + { + *acycle0 = accum0; + } + + if (acycle1234) + { + *acycle1234 = accum1234; + } + + return ncycles; +} + +/**************************************************************************** + * Name: nand_get_acycle + * + * Description: + * Map the number of address cycles the bit setting for the NFC command + * + * Input parameters: + * ncycles - Number of address cycles + * + * Returned value. + * NFC command value + * + ****************************************************************************/ + +static uint32_t nand_get_acycle(int ncycles) +{ + switch(ncycles) + { + case 1: + return NFCADDR_CMD_ACYCLE_ONE; + + case 2: + return NFCADDR_CMD_ACYCLE_TWO; + + case 3: + return NFCADDR_CMD_ACYCLE_THREE; + + case 4: + return NFCADDR_CMD_ACYCLE_FOUR; + + case 5: + return NFCADDR_CMD_ACYCLE_FIVE; + } + + return 0; +} + +/**************************************************************************** + * Name: nand_nfc_configure + * + * Description: + * Sets NFC configuration. + * + * Input parameters: + * priv - Pointer to a sam_nandcs_s instance. + * mode - SMC ALE CLE mode parameter. + * cmd1 - First command to be sent. + * cmd2 - Second command to be sent. + * coladdr - Column address. + * rowaddr - Row address. + * + * Returned value. + * None + * + ****************************************************************************/ + +static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode, + uint32_t cmd1, uint32_t cmd2, + uint32_t coladdr, uint32_t rowaddr) +{ + uint32_t cmd; + uint32_t regval; + uint32_t rw; + uint32_t acycle; + uint32_t acycle0 = 0; + uint32_t acycle1234 = 0; + int ncycles; + + /* Issue CLE and ALE through EBI */ + + if (!nand_nfc_enabled(priv)) + { + WRITE_COMMAND8(&priv->raw, cmd1); + if ((mode & SMC_ALE_COL_EN) == SMC_ALE_COL_EN) + { + nand_coladdr_write(priv, coladdr); + } + + if ((mode & SMC_ALE_ROW_EN)== SMC_ALE_ROW_EN) + { + nand_rowaddr_write(priv, rowaddr); + } + + if ((mode & SMC_CLE_VCMD2_EN) == SMC_CLE_VCMD2_EN) + { + /* When set, the CMD2 field is issued after the address cycle */ + + WRITE_COMMAND8(&priv->raw, cmd2); + } + } + + /* Issue CLE and ALE using NFC */ + + else + { + if ((mode & SMC_CLE_WRITE_EN) == SMC_CLE_WRITE_EN) + { + rw = NFCADDR_CMD_NFCWR; + } + else + { + rw = NFCADDR_CMD_NFCRD; + } + + if (((mode & SMC_CLE_DATA_EN) == SMC_CLE_DATA_EN) && + nand_nfcsram_enabled(priv)) + { + regval = NFCADDR_CMD_DATAEN; + } + else + { + regval = NFCADDR_CMD_DATADIS; + } + + if (((mode & SMC_ALE_COL_EN) == SMC_ALE_COL_EN) || + ((mode & SMC_ALE_ROW_EN) == SMC_ALE_ROW_EN)) + { + bool rowonly = (((mode & SMC_ALE_COL_EN) == 0) && + ((mode & SMC_ALE_ROW_EN) == SMC_ALE_ROW_EN)); + nand_translate_address(priv, coladdr, rowaddr, &acycle0, &acycle1234, rowonly); + acycle = nand_get_acycle(ncycles); + } + else + { + acycle = NFCADDR_CMD_ACYCLE_NONE; + } + + cmd = (rw | regval | NFCADDR_CMD_CSID_3 | acycle | + (((mode & SMC_CLE_VCMD2_EN) == SMC_CLE_VCMD2_EN) ? NFCADDR_CMD_VCMD2 : 0) | + (cmd1 << NFCADDR_CMD_CMD1_SHIFT) | (cmd2 << NFCADDR_CMD_CMD2_SHIFT)); + + nand_nfccmd_send( cmd, acycle1234, acycle0); + } +} + /**************************************************************************** * Name: nand_readpage_noecc * @@ -176,7 +656,7 @@ static struct sam_rawnand_s g_cs3nand; * ****************************************************************************/ -static int nand_readpage_noecc(struct sam_rawnand_s *priv, off_t block, +static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block, unsigned int page, void *data, void *spare) { #warning Missing logic @@ -203,7 +683,7 @@ static int nand_readpage_noecc(struct sam_rawnand_s *priv, off_t block, ****************************************************************************/ #ifdef NAND_HAVE_HSIAO -static int nand_readpage_hsiao(struct sam_rawnand_s *priv, off_t block, +static int nand_readpage_hsiao(struct sam_nandcs_s *priv, off_t block, unsigned int page, void *data, void *spare) { #warning Missing logic @@ -230,7 +710,7 @@ static int nand_readpage_hsiao(struct sam_rawnand_s *priv, off_t block, ****************************************************************************/ #ifdef NAND_HAVE_PMECC -static int nand_readpage_pmecc(struct sam_rawnand_s *priv, off_t block, +static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block, unsigned int page, void *data) { #warning Missing logic @@ -257,7 +737,7 @@ static int nand_readpage_pmecc(struct sam_rawnand_s *priv, off_t block, * ****************************************************************************/ -static int nand_writepage_noecc(struct sam_rawnand_s *priv, off_t block, +static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block, unsigned int page, const void *data, const void *spare) { #warning Missing logic @@ -284,7 +764,7 @@ static int nand_writepage_noecc(struct sam_rawnand_s *priv, off_t block, ****************************************************************************/ #ifdef NAND_HAVE_HSIAO -static int nand_writepage_hsiao(struct sam_rawnand_s *priv, off_t block, +static int nand_writepage_hsiao(struct sam_nandcs_s *priv, off_t block, unsigned int page, const void *data, const void *spare) { int ret; @@ -304,7 +784,7 @@ static int nand_writepage_hsiao(struct sam_rawnand_s *priv, off_t block, * Name: nand_writepage_pmecc * * Description: - * Writes the data area of a NAND FLASH page, The PMECC module generates + * Writes the data area of a NAND FLASH page, The PMECC module generates * redundancy at encoding time. When a NAND write page operation is * performed. The redundancy is appended to the page and written in the * spare area. @@ -321,7 +801,7 @@ static int nand_writepage_hsiao(struct sam_rawnand_s *priv, off_t block, ****************************************************************************/ #ifdef NAND_HAVE_PMECC -static int nand_writepage_pmecc(struct sam_rawnand_s *priv, off_t block, +static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block, unsigned int page, const void *data) { int ret; @@ -353,10 +833,33 @@ static int nand_writepage_pmecc(struct sam_rawnand_s *priv, off_t block, static int nand_eraseblock(struct nand_raw_s *raw, off_t block) { - struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw; + struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw; + uint32_t rawaddr; + int ret = OK; + DEBUGASSERT(raw); -#warning Missing logic - return -ENOSYS; + + fvdbg("Block %d\n", (int)block); + + /* Calculate address used for erase */ + + rawaddr = block * nandmodel_pagesperblock(&raw->model); + + /* Configure the NFC for the block erase */ + + nand_nfc_configure(priv, (SMC_CLE_VCMD2_EN | SMC_ALE_ROW_EN), + COMMAND_ERASE_1, COMMAND_ERASE_2, 0, rawaddr); + + /* Wait for the erase operation to complete */ + + nand_waitready(priv); + if (!nand_operation_complete(priv)) + { + fdbg("ERROR: Could not erase block %d\n", block); + ret = -ENOEXEC; + } + + return ret; } /**************************************************************************** @@ -381,7 +884,7 @@ static int nand_eraseblock(struct nand_raw_s *raw, off_t block) static int nand_rawread(struct nand_raw_s *raw, off_t block, unsigned int page, void *data, void *spare) { - struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw; + struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw; DEBUGASSERT(raw); return nand_readpage_noecc(priv, block, page, data, spare); @@ -410,7 +913,7 @@ static int nand_rawwrite(struct nand_raw_s *raw, off_t block, unsigned int page, const void *data, const void *spare) { - struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw; + struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw; DEBUGASSERT(raw); return nand_writepage_noecc(priv, block, page, data, spare); @@ -440,7 +943,7 @@ static int nand_rawwrite(struct nand_raw_s *raw, off_t block, static int nand_readpage(struct nand_raw_s *raw, off_t block, unsigned int page, void *data, void *spare) { - struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw; + struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw; DEBUGASSERT(raw); #ifndef CONFIG_MTD_NAND_BLOCKCHECK @@ -496,7 +999,7 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block, unsigned int page, const void *data, const void *spare) { - struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw; + struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw; DEBUGASSERT(raw); #ifndef CONFIG_MTD_NAND_BLOCKCHECK @@ -553,7 +1056,7 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block, struct mtd_dev_s *sam_nand_initialize(int cs) { - struct sam_rawnand_s *priv; + struct sam_nandcs_s *priv; struct mtd_dev_s *mtd; uintptr_t cmdaddr; uintptr_t addraddr; @@ -638,7 +1141,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs) /* Initialize the device structure */ - memset(priv, 0, sizeof(struct sam_rawnand_s)); + memset(priv, 0, sizeof(struct sam_nandcs_s)); priv->raw.cmdaddr = cmdaddr; priv->raw.addraddr = addraddr; priv->raw.dataaddr = dataaddr; @@ -679,3 +1182,57 @@ struct mtd_dev_s *sam_nand_initialize(int cs) return mtd; } + +/**************************************************************************** + * 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) +{ + if (wr == g_nanddbg.wr && /* Same kind of access? */ + regval == g_nanddbg.regval && /* Same regval? */ + regaddr == g_nanddbg.regadddr) /* Same address? */ + { + /* Yes, then just keep a count of the number of times we did this. */ + + g_nanddbg.ntimes++; + return false; + } + else + { + /* Did we do the previous operation more than once? */ + + if (g_nanddbg.ntimes > 0) + { + /* Yes... show how many times we did it */ + + lldbg("...[Repeats %d times]...\n", g_nanddbg.ntimes); + } + + /* Save information about the new access */ + + g_nanddbg.wr = wr; + g_nanddbg.regval = regval; + g_nanddbg.regadddr = regaddr; + g_nanddbg.ntimes = 0; + } + + /* Return true if this is the first time that we have done this operation */ + + return true; +} +#endif + diff --git a/arch/arm/src/sama5/sam_nand.h b/arch/arm/src/sama5/sam_nand.h index 6b4cf7a0e3..56400c1fca 100644 --- a/arch/arm/src/sama5/sam_nand.h +++ b/arch/arm/src/sama5/sam_nand.h @@ -42,6 +42,10 @@ #include +#include +#include +#include + #include #include "chip.h" @@ -96,6 +100,36 @@ #define NANDECC_PMECC (NANDECC_HWECC + 1) #define NANDECC_HSIAO (NANDECC_HWECC + 2) +/**************************************************************************** + * 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. + */ + +struct sam_nandcs_s +{ + struct nand_raw_s raw; /* Externally visible part of the driver */ + uint8_t cs :2; /* Chip select number (0..3) */ + uint8_t nfcen :1; /* True: NFC is enabled */ + uint8_t nfcsram :1; /* True: Use NFC SRAM */ + uint8_t dmaxfr :1; /* True: Use DMA transfers */ +}; + +/* Register debug state */ + +#ifdef CONFIG_SAMA5_NAND_REGDEBUG +struct sam_nanddbg_s +{ + bool wr; /* Last was a write */ + uint32_t regadddr; /* Last address */ + uint32_t regval; /* Last value */ + int ntimes; /* Number of times */ +}; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -110,6 +144,12 @@ extern "C" { #define EXTERN extern #endif +/* NAND regiser debug state */ + +#ifdef CONFIG_SAMA5_NAND_REGDEBUG +EXTERN struct sam_nanddbg_s g_nanddbg; +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -203,6 +243,241 @@ bool board_nand_busy(int cs); 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_nfc_enable + * + * Description: + * Enable the NAND FLASH controller + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void nand_nfc_enable(struct sam_nandcs_s *priv) +{ + priv->nfcen = true; + nand_putreg(SAM_HSMC_CTRL, HSMC_CTRL_NFCEN); +} + +/**************************************************************************** + * Name: nand_nfc_enable + * + * Description: + * Enable the NAND FLASH controller + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void nand_nfc_disable(struct sam_nandcs_s *priv) +{ + priv->nfcen = false; + nand_putreg(SAM_HSMC_CTRL, HSMC_CTRL_NFCDIS); +} + +/**************************************************************************** + * Name: nand_nfc_enabled + * + * Description: + * Return the state of the NAND FLASH controller + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * True if the NAND FLASH controller is enabled + * + ****************************************************************************/ + +static inline uint8_t nand_nfc_enabled(struct sam_nandcs_s *priv) +{ + return (bool)priv->nfcen; +} + +/**************************************************************************** + * Name: nand_nfcsram_enable + * + * Description: + * Enable use of NFC Host SRAM + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void nand_nfcsram_enable(struct sam_nandcs_s *priv) +{ + priv->nfcsram = true; +} + +/**************************************************************************** + * Name: nand_nfcsram_disable + * + * Description: + * Disable use of NFC Host SRAM + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void nand_nfcsram_disable(struct sam_nandcs_s *priv) +{ + priv->nfcsram = false; +} + +/**************************************************************************** + * Name: nand_nfcsram_enabled + * + * Description: + * Returrn the state of the NFS Host SRAM + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * True if the NFC Host SRAM is used + * + ****************************************************************************/ + +static inline bool nand_nfcsram_enabled(struct sam_nandcs_s *priv) +{ + return (bool)priv->nfcsram; +} + +/**************************************************************************** + * Name: nand_nanddma_enable + * + * Description: + * Enable use of DMA to perform transfers + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void nand_nanddma_enable(struct sam_nandcs_s *priv) +{ + priv->dmaxfr = true; +} + +/**************************************************************************** + * Name: nand_nanddma_disable + * + * Description: + * Disable use of DMA to perform transfers + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +void nand_nanddma_disable(struct sam_nandcs_s *priv) +{ + priv->dmaxfr = false; +} + +/**************************************************************************** + * Name: nand_nanddma_enabled + * + * Description: + * Returrn the state of the DMA usage + * + * Input Parameters: + * priv - A reference to the NAND chip select data structure + * + * Returned Value: + * True if transfers are performed using DMA + * + ****************************************************************************/ + +bool nand_nanddma_enabled(struct sam_nandcs_s *priv) +{ + return priv->dmaxfr; +} + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/nuttx/mtd/nand_model.h b/include/nuttx/mtd/nand_model.h index b0c058dcd1..d0a3ebc469 100644 --- a/include/nuttx/mtd/nand_model.h +++ b/include/nuttx/mtd/nand_model.h @@ -259,7 +259,7 @@ int nandmodel_translate(FAR const struct nand_model_s *model, off_t address, ****************************************************************************/ #define nandmodel_pagesperblock(m) \ - ((uint32_t)((m)->blocksize << 10) / model->pagesize) + ((uint32_t)((m)->blocksize << 10) / (m)->pagesize) /**************************************************************************** * Name: nandmodel_getdevpagesize diff --git a/include/nuttx/mtd/nand_raw.h b/include/nuttx/mtd/nand_raw.h index 881596d9db..2934b829fd 100644 --- a/include/nuttx/mtd/nand_raw.h +++ b/include/nuttx/mtd/nand_raw.h @@ -104,21 +104,21 @@ /* NAND access macros */ #define WRITE_COMMAND8(raw, command) \ - {*((volatile uint8_t *)raw->cmdaddr) = (uint8_t)command;} + {*((volatile uint8_t *)(raw)->cmdaddr) = (uint8_t)command;} #define WRITE_COMMAND16(raw, command) \ - {*((volatile uint16_t *)raw->cmdaddr) = (uint16_t)command;} + {*((volatile uint16_t *)(raw)->cmdaddr) = (uint16_t)command;} #define WRITE_ADDRESS8(raw, address) \ - {*((volatile uint8_t *)raw->addraddr) = (uint8_t)address;} + {*((volatile uint8_t *)(raw)->addraddr) = (uint8_t)address;} #define WRITE_ADDRESS16(raw, address) \ - {*((volatile uint16_t *)raw->addraddr) = (uint16_t)address;} + {*((volatile uint16_t *)(raw)->addraddr) = (uint16_t)address;} #define WRITE_DATA8(raw, data) \ - {*((volatile uint8_t *)raw->dataaddr) = (uint8_t)data;} + {*((volatile uint8_t *)(raw)->dataaddr) = (uint8_t)data;} #define READ_DATA8(raw) \ - (*((volatile uint8_t *)raw->dataaddr)) + (*((volatile uint8_t *)(raw)->dataaddr)) #define WRITE_DATA16(raw, data) \ - {*((volatile uint16_t *) raw->dataaddr) = (uint16_t)data;} + {*((volatile uint16_t *)(raw)->dataaddr) = (uint16_t)data;} #define READ_DATA16(raw) \ - (*((volatile uint16_t *)raw->dataaddr)) + (*((volatile uint16_t *)(raw)->dataaddr)) /* struct nand_raw_s operations */