From fd74d0b6256278bf37d8f1cbd95f843c9b744996 Mon Sep 17 00:00:00 2001 From: Lok Tep Date: Tue, 1 Dec 2015 23:09:31 +0100 Subject: [PATCH] spifi --- arch/arm/src/lpc43xx/Make.defs | 1 + arch/arm/src/lpc43xx/chip/lpc43_cgu.h | 36 +- arch/arm/src/lpc43xx/lpc43_adc.h | 9 +- arch/arm/src/lpc43xx/lpc43_cgu.c | 8 +- arch/arm/src/lpc43xx/lpc43_spifi.c | 13 +- arch/arm/src/lpc43xx/spifi/.cproject | 175 ++ arch/arm/src/lpc43xx/spifi/.project | 58 + arch/arm/src/lpc43xx/spifi/changelog.txt | 135 ++ .../spifi/inc/private/spifilib_chiphw.h | 349 +++ arch/arm/src/lpc43xx/spifi/inc/spifilib_api.h | 438 ++++ arch/arm/src/lpc43xx/spifi/inc/spifilib_dev.h | 416 ++++ arch/arm/src/lpc43xx/spifi/liblinks.xml | 32 + arch/arm/src/lpc43xx/spifi/src/Make.defs | 39 + .../lpc43xx/spifi/src/spifilib_dev_common.c | 864 ++++++++ .../spifi/src/spifilib_fam_standard_cmd.c | 1866 +++++++++++++++++ 15 files changed, 4404 insertions(+), 35 deletions(-) create mode 100644 arch/arm/src/lpc43xx/spifi/.cproject create mode 100644 arch/arm/src/lpc43xx/spifi/.project create mode 100644 arch/arm/src/lpc43xx/spifi/changelog.txt create mode 100644 arch/arm/src/lpc43xx/spifi/inc/private/spifilib_chiphw.h create mode 100644 arch/arm/src/lpc43xx/spifi/inc/spifilib_api.h create mode 100644 arch/arm/src/lpc43xx/spifi/inc/spifilib_dev.h create mode 100644 arch/arm/src/lpc43xx/spifi/liblinks.xml create mode 100644 arch/arm/src/lpc43xx/spifi/src/Make.defs create mode 100644 arch/arm/src/lpc43xx/spifi/src/spifilib_dev_common.c create mode 100644 arch/arm/src/lpc43xx/spifi/src/spifilib_fam_standard_cmd.c diff --git a/arch/arm/src/lpc43xx/Make.defs b/arch/arm/src/lpc43xx/Make.defs index bd593e22f4..ea5396d2fa 100644 --- a/arch/arm/src/lpc43xx/Make.defs +++ b/arch/arm/src/lpc43xx/Make.defs @@ -178,3 +178,4 @@ CHIP_CSRCS += lpc43_usb0dev.c endif endif +include chip/spifi/src/Make.defs \ No newline at end of file diff --git a/arch/arm/src/lpc43xx/chip/lpc43_cgu.h b/arch/arm/src/lpc43xx/chip/lpc43_cgu.h index 61fa3be0b5..d1554ac2a9 100644 --- a/arch/arm/src/lpc43xx/chip/lpc43_cgu.h +++ b/arch/arm/src/lpc43xx/chip/lpc43_cgu.h @@ -574,28 +574,28 @@ # define BASE_PHYTX_CLKSEL_IDIVD (15 << BASE_PHYTX_CLK_CLKSEL_SHIFT) /* IDIVD */ # define BASE_PHYTX_CLKSEL_IDIVE (16 << BASE_PHYTX_CLK_CLKSEL_SHIFT) /* IDIVE */ /* Bits 29-31: Reserved */ -/* Output stage 9 control register (BASE_APB1_CLK) */ +/* Output stage 9 control register (BASE_APB1_CLK, BASE_APB3_CLK) */ /* NOTE: Clocks 4-19 are identical */ -#define BASE_APB1_CLK_PD (1 << 0) /* Bit 0: Output stage power down */ +#define BASE_APB_CLK_PD (1 << 0) /* Bit 0: Output stage power down */ /* Bits 1-10: Reserved */ -#define BASE_APB1_CLK_AUTOBLOCK (1 << 11) /* Bit 11: Block clock during frequency change */ +#define BASE_APB_CLK_AUTOBLOCK (1 << 11) /* Bit 11: Block clock during frequency change */ /* Bits 12-23: Reserved */ -#define BASE_APB1_CLK_CLKSEL_SHIFT (24) /* Bits 24-28: Clock source selection */ -#define BASE_APB1_CLK_CLKSEL_MASK (31 << BASE_APB1_CLK_CLKSEL_SHIFT) -# define BASE_APB1_CLKSEL_32KHZOSC (0 << BASE_APB1_CLK_CLKSEL_SHIFT) /* 32 kHz oscillator */ -# define BASE_APB1_CLKSEL_IRC (1 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IRC (default) */ -# define BASE_APB1_CLKSEL_ENET_RXCLK (2 << BASE_APB1_CLK_CLKSEL_SHIFT) /* ENET_RX_CLK */ -# define BASE_APB1_CLKSEL_ENET_TXCLK (3 << BASE_APB1_CLK_CLKSEL_SHIFT) /* ENET_TX_CLK */ -# define BASE_APB1_CLKSEL_GPCLKIN (4 << BASE_APB1_CLK_CLKSEL_SHIFT) /* GP_CLKIN */ -# define BASE_APB1_CLKSEL_XTAL (6 << BASE_APB1_CLK_CLKSEL_SHIFT) /* Crystal oscillator */ -# define BASE_APB1_CLKSEL_PLL0AUDIO (8 << BASE_APB1_CLK_CLKSEL_SHIFT) /* PLL0AUDIO */ -# define BASE_APB1_CLKSEL_PLL1 (9 << BASE_APB1_CLK_CLKSEL_SHIFT) /* PLL1 */ -# define BASE_APB1_CLKSEL_IDIVA (12 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IDIVA */ -# define BASE_APB1_CLKSEL_IDIVB (13 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IDIVB */ -# define BASE_APB1_CLKSEL_IDIVC (14 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IDIVC */ -# define BASE_APB1_CLKSEL_IDIVD (15 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IDIVD */ -# define BASE_APB1_CLKSEL_IDIVE (16 << BASE_APB1_CLK_CLKSEL_SHIFT) /* IDIVE */ +#define BASE_APB_CLK_CLKSEL_SHIFT (24) /* Bits 24-28: Clock source selection */ +#define BASE_APB_CLK_CLKSEL_MASK (31 << BASE_APB_CLK_CLKSEL_SHIFT) +# define BASE_APB_CLKSEL_32KHZOSC (0 << BASE_APB_CLK_CLKSEL_SHIFT) /* 32 kHz oscillator */ +# define BASE_APB_CLKSEL_IRC (1 << BASE_APB_CLK_CLKSEL_SHIFT) /* IRC (default) */ +# define BASE_APB_CLKSEL_ENET_RXCLK (2 << BASE_APB_CLK_CLKSEL_SHIFT) /* ENET_RX_CLK */ +# define BASE_APB_CLKSEL_ENET_TXCLK (3 << BASE_APB_CLK_CLKSEL_SHIFT) /* ENET_TX_CLK */ +# define BASE_APB_CLKSEL_GPCLKIN (4 << BASE_APB_CLK_CLKSEL_SHIFT) /* GP_CLKIN */ +# define BASE_APB_CLKSEL_XTAL (6 << BASE_APB_CLK_CLKSEL_SHIFT) /* Crystal oscillator */ +# define BASE_APB_CLKSEL_PLL0AUDIO (8 << BASE_APB_CLK_CLKSEL_SHIFT) /* PLL0AUDIO */ +# define BASE_APB_CLKSEL_PLL1 (9 << BASE_APB_CLK_CLKSEL_SHIFT) /* PLL1 */ +# define BASE_APB_CLKSEL_IDIVA (12 << BASE_APB_CLK_CLKSEL_SHIFT) /* IDIVA */ +# define BASE_APB_CLKSEL_IDIVB (13 << BASE_APB_CLK_CLKSEL_SHIFT) /* IDIVB */ +# define BASE_APB_CLKSEL_IDIVC (14 << BASE_APB_CLK_CLKSEL_SHIFT) /* IDIVC */ +# define BASE_APB_CLKSEL_IDIVD (15 << BASE_APB_CLK_CLKSEL_SHIFT) /* IDIVD */ +# define BASE_APB_CLKSEL_IDIVE (16 << BASE_APB_CLK_CLKSEL_SHIFT) /* IDIVE */ /* Bits 29-31: Reserved */ /* Output stage 11 control register (BASE_LCD_CLK) */ /* NOTE: Clocks 4-19 are identical */ diff --git a/arch/arm/src/lpc43xx/lpc43_adc.h b/arch/arm/src/lpc43xx/lpc43_adc.h index 558bfd75e8..62b2cc5b85 100644 --- a/arch/arm/src/lpc43xx/lpc43_adc.h +++ b/arch/arm/src/lpc43xx/lpc43_adc.h @@ -44,18 +44,11 @@ #include #include "chip/lpc43_adc.h" -#ifdef CONFIG_LPC43_ADC +#ifdef CONFIG_LPC43_ADC0 /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#ifdef CONFIG_ADC_CHANLIST -# if !defined(CONFIG_ADC_NCHANNELS) -# error "CONFIG_ADC_CHANLIST must defined in this configuration" -# elif CONFIG_ADC_NCHANNELS < 1 -# error "The value of CONFIG_ADC_NCHANNELS is invalid" -# endif -#endif /**************************************************************************** * Public Types diff --git a/arch/arm/src/lpc43xx/lpc43_cgu.c b/arch/arm/src/lpc43xx/lpc43_cgu.c index 6b13ee4fd7..fc1eda7321 100644 --- a/arch/arm/src/lpc43xx/lpc43_cgu.c +++ b/arch/arm/src/lpc43xx/lpc43_cgu.c @@ -566,8 +566,8 @@ void lpc43_abp1(void) /* Set clock source */ regval = getreg32(LPC43_BASE_APB1_CLK); - regval &= ~BASE_APB1_CLK_CLKSEL_MASK; - regval |= BOARD_ABP1_CLKSRC | BASE_APB1_CLK_AUTOBLOCK; + regval &= ~BASE_APB_CLK_CLKSEL_MASK; + regval |= BOARD_ABP1_CLKSRC | BASE_APB_CLK_AUTOBLOCK; putreg32(regval, LPC43_BASE_APB1_CLK); } #endif @@ -580,8 +580,8 @@ void lpc43_abp3(void) /* Set clock source */ regval = getreg32(LPC43_BASE_APB3_CLK); - regval &= ~BASE_APB3_CLK_CLKSEL_MASK; - regval |= BOARD_ABP3_CLKSRC | BASE_APB3_CLK_AUTOBLOCK; + regval &= ~BASE_APB_CLK_CLKSEL_MASK; + regval |= BOARD_ABP3_CLKSRC | BASE_APB_CLK_AUTOBLOCK; putreg32(regval, LPC43_BASE_APB3_CLK); } #endif diff --git a/arch/arm/src/lpc43xx/lpc43_spifi.c b/arch/arm/src/lpc43xx/lpc43_spifi.c index 69ce27f26b..227521f21a 100644 --- a/arch/arm/src/lpc43xx/lpc43_spifi.c +++ b/arch/arm/src/lpc43xx/lpc43_spifi.c @@ -62,8 +62,9 @@ #include "lpc43_cgu.h" #include "lpc43_spifi.h" #include "lpc43_pinconfig.h" +#include "spifi/inc/spifilib_api.h" -#ifdef CONFIG_LPC43_SPIFI +#ifdef CONFIG_LPC43_SPIFI_FIXME /**************************************************************************** * Pre-processor Definitions @@ -145,11 +146,11 @@ priv->spifi->spifi_erase(rom, operands) #else # define SPIFI_INIT(priv, rom, cshigh, options, mhz) \ - spifi_init(rom, cshigh, options, mhz) + spifiInit(rom, cshigh, options, mhz) # define SPIFI_PROGRAM(priv, rom, src, operands) \ - spifi_program(rom, src, operands) + spifiProgram(rom, src, operands) # define SPIFI_ERASE(priv, rom, operands) \ - spifi_erase(rom, operands) + spifiErase(rom, operands) #endif /* 512 byte sector simulation */ @@ -244,7 +245,7 @@ * csHigh = ceiling(min CS high / SPIFI clock period) - 1 * * where ceiling means round up to the next higher integer if the argument - * isn’t an integer. + * isn�t an integer. */ #define SPIFI_CSHIGH 9 @@ -791,6 +792,7 @@ static ssize_t lpc43_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t dest = SPIFI_BASE + (startblock << SPIFI_BLKSHIFT); +#if defined(CONFIG_SPIFI_SECTOR512) /* Write all of the erase blocks to FLASH */ ret = lpc43_pagewrite(priv, dest, buffer, nblocks << SPIFI_512SHIFT); @@ -799,6 +801,7 @@ static ssize_t lpc43_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t fdbg("ERROR: lpc43_pagewrite failed: %d\n", ret); return ret; } +#endif lpc43_dumpbuffer(__func__, buffer, nblocks << SPIFI_BLKSHIFT) return nblocks; diff --git a/arch/arm/src/lpc43xx/spifi/.cproject b/arch/arm/src/lpc43xx/spifi/.cproject new file mode 100644 index 0000000000..8424e5a991 --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/.cproject @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> +<TargetConfig> +<Properties property_0="" property_3="NXP" property_4="Generic-M4" property_count="5" version="70200"/> +<infoList vendor="NXP"><info chip="Generic-M4" match_id="0x0" name="Generic-M4" stub="crt_emu_cm3_gen"><chip><name>Generic-M4</name> +<family>Generic-M4</family> +<vendor>NXP (formerly Philips)</vendor> +<reset board="None" core="Real" sys="Real"/> +<clock changeable="TRUE" freq="12MHz" is_accurate="TRUE"/> +<memory can_program="true" id="Flash" is_ro="true" type="Flash"/> +<memory id="RAM" type="RAM"/> +<memory id="Periph" is_volatile="true" type="Peripheral"/> +<memoryInstance derived_from="RAM" id="RamLoc" location="0x0" size="0x4000"/> +<peripheralInstance derived_from="V7M_MPU" determined="infoFile" id="MPU" location="0xe000ed90"/> +<peripheralInstance derived_from="V7M_NVIC" determined="infoFile" id="NVIC" location="0xe000e000"/> +<peripheralInstance derived_from="V7M_DCR" determined="infoFile" id="DCR" location="0xe000edf0"/> +<peripheralInstance derived_from="V7M_ITM" determined="infoFile" id="ITM" location="0xe0000000"/> +</chip> +<processor><name gcc_name="cortex-m4">Cortex-M4</name> +<family>Cortex-M</family> +</processor> +<link href="CM3_peripheral.xme" show="embed" type="simple"/> +</info> +</infoList> +</TargetConfig> + + + diff --git a/arch/arm/src/lpc43xx/spifi/.project b/arch/arm/src/lpc43xx/spifi/.project new file mode 100644 index 0000000000..51daf7cae5 --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/.project @@ -0,0 +1,58 @@ + + + spifilib_m4f_hard + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + changelog.txt + 1 + PARENT-2-WORKSPACE_LOC/changelog.txt + + + inc/spifilib_api.h + 1 + PARENT-2-WORKSPACE_LOC/inc/spifilib_api.h + + + inc/spifilib_dev.h + 1 + PARENT-2-WORKSPACE_LOC/inc/spifilib_dev.h + + + src/spifilib_dev_common.c + 1 + PARENT-2-WORKSPACE_LOC/src/spifilib_dev_common.c + + + src/spifilib_fam_standard_cmd.c + 1 + PARENT-2-WORKSPACE_LOC/src/spifilib_fam_standard_cmd.c + + + inc/private/spifilib_chiphw.h + 1 + PARENT-2-WORKSPACE_LOC/inc/private/spifilib_chiphw.h + + + diff --git a/arch/arm/src/lpc43xx/spifi/changelog.txt b/arch/arm/src/lpc43xx/spifi/changelog.txt new file mode 100644 index 0000000000..f96920a1f5 --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/changelog.txt @@ -0,0 +1,135 @@ +LPCSpifilib version <1.03> +========================== +Release date <01/19/2015> +1. Corrected id for S25FL256S device. +2. Added 4 Byte address support for large devices (S25FL256S and S25FL512S). +3. Changed directory structure to new v3.xx format. +4. Removed --gnu flag and produced generic lib for use with both IAR and Keil + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a] + +LPCSpifilib version <1.02> +========================== +Release date <12/30/2014> +1. Included pre-build of LPCXpresso M4F and M4F_hard libraries + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a] + +LPCSpifilib version <1.01> +========================== +Release date <12/11/2014> +1. Changed reported device string on S25FL512S from "S25FL512S 256kSec" to "S25FL512S". +2. Changelog update: Added support for MX25L1635E, MX25L6435E, MX25L8035E, S25FL016K, S25FL064P, S25FL128S, S25FL256S, + S25FL512S, W25Q16DV, and W25Q64FV devices. +3. Changelog update: Changed maxRead to 16128 (was 32768). + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a] + +LPCSpifilib version <1.0> +========================== +Release date <12/2/2014> +Change Log: +1. Added support for MX25L1635E, MX25L6435E, MX25L8035E, S25FL016K, S25FL064P, S25FL128P, S25FL256S, + S25FL512S, W25Q16DV, and W25Q64FV devices. +2. Added support for device enumeration. +3. Added support for device base address return. +4. Improved read/write performance by issuing dword access to spifi controller. +5. Changed device structure to use function enum to facilitate adding external devices without recompiling library. +6. Added support for dual read / write. +7. Changed quad command to quad io read (improved performance). +8. Added ability for device to define read / write configuration word on a per +device basis. +9. Changed maxRead to 16383 (was 32768) +10. Removed API spifiDeInit(); +11. Renamed spifiDevGetInfo option SPIFI_INFO_MAX_QUADREAD_CLOCK to SPIFI_INFO_MAX_HSREAD_CLOCK +12. Renamed spifiDevGetInfo option SPIFI_INFO_MAX_QUADPROG_CLOCK to SPIFI_INFO_MAX_HSPROG_CLOCK + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a]. + +LPCSpifilib version <0.07> +========================== +Release date <9/9/2014> +Change Log: +1. Added support for Winbond W25Q32FV. +2. Added support for Winbond W25Q80BV. +3. Added API's to return max speed for specific functions: + Read, QuadRead, Program, Quad Program. +4. Added prvGetStatus, prvSetStatus and prvSetQuadMode Functions to device definition structure. +5. Added spifiDevGetCount function. +6. Consolidated MX25L3235E and S25FL164K support into spifilib_fam_standard_cmd module + (removed SPIFI_REG_FAMILY_xxx registration functions and replaced with + spifi_REG_FAMILY_StandardCommandSet function). +7. Fixed bug in spifiRegisterFamily where NULL was being returned instead of the + family handle. +8. Removed switch statements and clib calls to memcpy and memset to facilitate running from iRam. +9. Renamed SPIFI_DEV_FAMILY_T to SPIFI_FAM_NODE_T. +10. Moved spifiDevRegister to shared module (spifilib_dev_common.c). +11. Updated documentation to reflect current design. + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a] + +LPCSpifilib version <0.06> +========================== +Release date <6/25/2014> +Change Log: +1. Changed identify to allow dynamic ID bytes per MFG/PART #. Moved to common + module. +2. Added support for S25FL129P (256kB sectors). +3. Verified S25FL129P 64kB sectors variant. +4. Renamed familes to indicate functionality in place of root device. + (This was done to avoid confusion over where devices reside). +5. Family cleanup to aid in comparison. +6. Removed Chip.h dependency. +7. Moved getInfo to common module. +8. Code/Memory optimizations. +9. LPCXpresso XML projects added. +10. M0 Library added. +11. Sub-block erase fixed for devices with full capability. +12. IAR libarary renamed to match Keil library +13. Moved project files into proj directory + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Will break IAR examples in LPCOpen v2.12 [Libraries in projects must be +renamed from lib_llpcspifi_Mx.a to lib_lpcspifi_Mx.a] + +LPCSpifilib version <0.05> +========================== +Release date <5/15/2014> +Change Log: +1. Comment cleanup. +2. Added support for 40xx series +3. Changed spifiInit() api to include spifi control register address. +4. Changed spifiInitDevice() to include spifi control register address. + +Known issues: (carried forward) +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Option SPIFI_CAP_SUBBLKERASE is not working. +3. Device S25FL129P is un-tested. + + +LPCSpifilib version <0.04> +=========================== +Release date <4/25/2014> +Change Log: +1. Initial version. + +Known issues: +1. Option SPIFI_CAP_NOBLOCK is not implemented. +2. Option SPIFI_CAP_SUBBLKERASE is not working. +3. Device S25FL129P is un-tested. diff --git a/arch/arm/src/lpc43xx/spifi/inc/private/spifilib_chiphw.h b/arch/arm/src/lpc43xx/spifi/inc/private/spifilib_chiphw.h new file mode 100644 index 0000000000..841915b10e --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/inc/private/spifilib_chiphw.h @@ -0,0 +1,349 @@ +/* + * @brief LPCSPIFILIB hardware definitions and functions + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licenser disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#ifndef __SPIFILIB_CHIPHW_H_ +#define __SPIFILIB_CHIPHW_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define for inline */ +#ifndef INLINE +#ifdef __CC_ARM +#define INLINE __inline +#else +#define INLINE inline +#endif /* __CC_ARM */ +#endif /* !INLINE */ + +#ifdef __CC_ARM +#pragma anon_unions +#endif +/** @defgroup LPCSPIFILIB_HW_API LPCSPIFILIB hardware definitions and API functions + * @ingroup LPCSPIFILIB + * @{ + */ + +/** + * @brief SPIFI controller hardware register structure + */ + +typedef struct LPC_SPIFI_CHIPHW { + volatile uint32_t CTRL; /**< SPIFI control register */ + volatile uint32_t CMD; /**< SPIFI command register */ + volatile uint32_t ADDR; /**< SPIFI address register */ + volatile uint32_t DATINTM; /**< SPIFI intermediate data register */ + volatile uint32_t CACHELIMIT; /**< SPIFI cache limit register */ + union { + volatile uint8_t DAT8; /**< SPIFI 8 bit data */ + volatile uint16_t DAT16; /**< SPIFI 16 bit data */ + volatile uint32_t DAT32; /**< SPIFI 32 bit data */ + }; + + volatile uint32_t MEMCMD; /**< SPIFI memory command register */ + volatile uint32_t STAT; /**< SPIFI status register */ +} LPC_SPIFI_CHIPHW_T; + +/** @defgroup LPCSPIFILIB_HW_PRIM LPCSPIFILIB primative API functions + * @{ + */ + +/** + * @brief SPIFI controller control register bit definitions + */ +#define SPIFI_CTRL_TO(t) ((t) << 0) /**< SPIFI timeout */ +#define SPIFI_CTRL_CSHI(c) ((c) << 16) /**< SPIFI chip select minimum high time */ +#define SPIFI_CTRL_DATA_PREFETCH_DISABLE(d) ((d) << 21) /**< SPIFI memMode prefetch enable*/ +#define SPIFI_CTRL_INTEN(i) ((i) << 22) /**< SPIFI cmdComplete irq enable */ +#define SPIFI_CTRL_MODE3(m) ((m) << 23) /**< SPIFI mode3 config */ +#define SPIFI_CTRL_PREFETCH_DISABLE(d) ((d) << 27) /**< SPIFI cache prefetch enable */ +#define SPIFI_CTRL_DUAL(d) ((d) << 28) /**< SPIFI enable dual */ +#define SPIFI_CTRL_RFCLK(m) ((m) << 29) /**< SPIFI clock edge config */ +#define SPIFI_CTRL_FBCLK(m) ((m) << 30) /**< SPIFI feedback clock select */ +#define SPIFI_CTRL_DMAEN(m) ((m) << 31) /**< SPIFI dma enable */ + +/** + * @brief Write SPIFI controller control register + * @param pSpifi : Base address of SPIFI controller + * @param ctrl : Control value to write + * @return Nothing + */ +static INLINE void spifi_HW_SetCtrl(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t ctrl) +{ + pSpifi->CTRL = ctrl; +} + +/** + * @brief Read SPIFI controller control register + * @param pSpifi : Base address of SPIFI controller + * @return Current CTRL register values + */ +static INLINE uint32_t spifi_HW_GetCtrl(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->CTRL; +} + +/** + * @brief SPIFI controller status register bit definitions + */ +#define SPIFI_STAT_RESET (1 << 4) /**< SPIFI reset */ +#define SPIFI_STAT_INTRQ (1 << 5) /**< SPIFI interrupt request */ +#define SPIFI_STAT_CMD (1 << 1) /**< SPIFI command in progress */ +#define SPIFI_STAT_MCINIT (1) /**< SPIFI MCINIT */ + +/** + * @brief Write SPIFI controller status register + * @param pSpifi : Base address of SPIFI controller + * @param stat : Status bits to write + * @return Nothing + */ +static INLINE void spifi_HW_SetStat(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t stat) +{ + pSpifi->STAT = stat; +} + +/** + * @brief Read SPIFI controller status register + * @param pSpifi : Base address of SPIFI controller + * @return Current STAT register values + */ +static INLINE uint32_t spifi_HW_GetStat(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->STAT; +} + +/** + * @brief SPIFI controller command register bit definitions + */ +#define SPIFI_CMD_DATALEN(l) ((l) << 0) /**< SPIFI bytes to send or receive */ +#define SPIFI_CMD_POLLRS(p) ((p) << 14) /**< SPIFI enable poll */ +#define SPIFI_CMD_DOUT(d) ((d) << 15) /**< SPIFI data direction is out */ +#define SPIFI_CMD_INTER(i) ((i) << 16) /**< SPIFI intermediate bit length */ +#define SPIFI_CMD_FIELDFORM(p) ((p) << 19) /**< SPIFI 2 bit data/cmd mode control */ +#define SPIFI_CMD_FRAMEFORM(f) ((f) << 21) /**< SPIFI op and adr field config */ +#define SPIFI_CMD_OPCODE(o) ((uint32_t) (o) << 24) /**< SPIFI 8-bit command code */ + +/** + * @brief frame form definitions + */ +typedef enum { + SPIFI_FRAMEFORM_OP = 1, + SPIFI_FRAMEFORM_OP_1ADDRESS = 2, + SPIFI_FRAMEFORM_OP_2ADDRESS = 3, + SPIFI_FRAMEFORM_OP_3ADDRESS = 4, + SPIFI_FRAMEFORM_OP_4ADDRESS = 5, + SPIFI_FRAMEFORM_NOOP_3ADDRESS = 6, + SPIFI_FRAMEFORM_NOOP_4ADDRESS = 7 +} SPIFI_FRAMEFORM_T; + +/** + * @brief serial type definitions + */ +typedef enum { + SPIFI_FIELDFORM_ALL_SERIAL = 0, + SPIFI_FIELDFORM_SERIAL_OPCODE_ADDRESS = 1, + SPIFI_FIELDFORM_SERIAL_OPCODE = 2, + SPIFI_FIELDFORM_NO_SERIAL = 3 +} SPIFI_FIELDFORM_T; + +/** + * @brief Read SPIFI controller command register + * @param pSpifi : Base address of SPIFI controller + * @return 32-bit value read from the command register + */ +static INLINE uint32_t spifi_HW_GetCmd(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->CMD; +} + +/** + * @brief Write SPIFI controller command register + * @param pSpifi : Base address of SPIFI controller + * @param cmd : Command to write + * @return Nothing + */ +static INLINE void spifi_HW_SetCmd(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t cmd) +{ + pSpifi->CMD = cmd; +} + +/** + * @brief Write SPIFI controller address register + * @param pSpifi : Base address of SPIFI controller + * @param addr : address (offset) to write + * @return Nothing + */ +static INLINE void spifi_HW_SetAddr(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t addr) +{ + pSpifi->ADDR = addr; +} + +/** + * @brief Read an 8-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @return 8-bit value read from the data register + */ +static INLINE uint8_t spifi_HW_GetData8(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->DAT8; +} + +/** + * @brief Read an 16-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @return 16-bit value read from the data register + */ +static INLINE uint16_t spifi_HW_GetData16(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->DAT16; +} + +/** + * @brief Read an 32-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @return 32-bit value read from the data register + */ +static INLINE uint32_t spifi_HW_GetData32(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + return pSpifi->DAT32; +} + +/** + * @brief Write an 8-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @param data : 8-bit data value to write + * @return Nothing + */ +static INLINE void spifi_HW_SetData8(LPC_SPIFI_CHIPHW_T *pSpifi, uint8_t data) +{ + pSpifi->DAT8 = data; +} + +/** + * @brief Write an 16-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @param data : 16-bit data value to write + * @return Nothing + */ +static INLINE void spifi_HW_SetData16(LPC_SPIFI_CHIPHW_T *pSpifi, uint16_t data) +{ + pSpifi->DAT16 = data; +} + +/** + * @brief Write an 32-bit value from the controller data register + * @param pSpifi : Base address of SPIFI controller + * @param data : 32-bit data value to write + * @return Nothing + */ +static INLINE void spifi_HW_SetData32(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t data) +{ + pSpifi->DAT32 = data; +} + +/** + * @brief Write IDATA register + * @param pSpifi : Base address of SPIFI controller + * @param mode : value to write. Used to specify value used for intermediate + data value when enabled. + * @return Nothing + */ +static INLINE void spifi_HW_SetIDATA(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t mode) +{ + pSpifi->DATINTM = mode; +} + +/** + * @brief Write MEMCMD register + * @param pSpifi : Base address of SPIFI controller + * @param cmd : Command value to write + * @return Nothing + */ +static INLINE void spifi_HW_SetMEMCMD(LPC_SPIFI_CHIPHW_T *pSpifi, uint32_t cmd) +{ + pSpifi->MEMCMD = cmd; +} + +/** + * @} + */ + +/** @defgroup LPCSPIFILIB_HW_L2 LPCSPIFILIB hardware support API functions + * @{ + */ + +/** + * @brief Reset SPIFI controller + * @param pSpifi : Base address of SPIFI controller + * @return Nothing + */ +static INLINE void spifi_HW_ResetController(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + pSpifi->STAT = SPIFI_STAT_RESET; + while ((pSpifi->STAT & SPIFI_STAT_RESET) != 0) {} +} + +/** + * @brief Wait for a command to complete + * @param pSpifi : Base address of SPIFI controller + * @return Nothing + */ +static INLINE void spifi_HW_WaitCMD(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + while ((spifi_HW_GetStat(pSpifi) & SPIFI_STAT_CMD) != 0) {} +} + +/** + * @brief Wait for a RESET bit to clear + * @param pSpifi : Base address of SPIFI controller + * @return Nothing + */ +static INLINE void spifi_HW_WaitRESET(LPC_SPIFI_CHIPHW_T *pSpifi) +{ + while ((spifi_HW_GetStat(pSpifi) & SPIFI_STAT_RESET) != 0) {} +} + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SPIFILIB_CHIPHW_H_ */ diff --git a/arch/arm/src/lpc43xx/spifi/inc/spifilib_api.h b/arch/arm/src/lpc43xx/spifi/inc/spifilib_api.h new file mode 100644 index 0000000000..67d3a480d2 --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/inc/spifilib_api.h @@ -0,0 +1,438 @@ +/* + * @brief LPCSPIFILIB driver definitions and functions + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licenser disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#ifndef __SPIFILIB_API_H_ +#define __SPIFILIB_API_H_ + +#include "spifilib_dev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup LPCSPIFILIB_API LPCSPIFILIB common API functions + * @ingroup LPCSPIFILIB + * These LPCSPIFILIB functions provide an abstracted interface to + * the LPCSPIFILIB functions. The device API is a private API which should + * only used to interface with the LPCSPIFILIB core library. + * @{ + */ + +/** @defgroup LPCSPIFILIB_CMNAPI LPCSPIFILIB library support functions + * Library support functions are not tied to any specific LPCSPIFILIB device. + * @{ + */ + +/** + * @brief Report the SPIFILIB version + * @return SPIFI library version in format MMmm where MM is major number + * and mm is minor number. + */ +uint16_t spifiGetLibVersion(void); + +/** + * @brief Initialize the SPIFILIB driver + * @param spifiCtrlAddr : Base address of SPIFI controller + * @param reset : true to reset the SPIFI controller, or false to not reset + * @return SPIFI library error code + * @note This function should be called prior to any other SPIFILIB functions. + * In most cases, a reset isn't needed. Before calling this function, all board + * specific functions related to the SPIFI interface must be setup and the SPIFI + * clock must be enabled. If booting from SPIFI FLASH, this will already be done. + * If not booting from SPIFI FLASH, the SPIFI FLASH pin muxing and SPIFI controller + * clock need to be enabled prior to this call. + */ +SPIFI_ERR_T spifiInit(uint32_t spifiCtrlAddr, uint8_t reset); + +/** + * @brief Register a SPIFILIB family driver + * @param regFx : A function which returns persistent device specific data structure. + * @return Handle to device specific data structure. + * @note This function should be called prior to calling spifiGetHandleMemSize() or + * spifiInitDevice(). + */ +SPIFI_FAM_NODE_T *spifiRegisterFamily(SPIFI_FAM_NODE_T *(*regFx)(void)); + +/** + * @brief Converts a SPIFILIB error code into a meaningful string + * @param errCode : Error code to get string pointer to + * @return Pointer to string for the passed error code + */ +const char *spifiReturnErrString(SPIFI_ERR_T errCode); + +/** + * @brief Return the number of registered device families in this driver + * @return number of registered device families in this driver + */ +uint32_t spifiGetSuppFamilyCount(void); + +/** + * @brief Return the driver device family name for a specific index + * @param index : Index (0 - n) where n = number of families returned + * by spifiGetSuppFamilyCount() -1 + * @return a string pointer to the generic device name + * @note Can be used with the spifiGetSuppFamilyCount() to get a list of + * device families the library is configured for. + */ +const char *spifiGetSuppFamilyName(uint32_t index); + +/** + * @brief Detect and return memory needed for device handle at passed address + * @param spifiCtrlAddr : Base address of SPIFI controller + * @return The size in bytes this device needs for the call to InitDevice(). + * If no supported device is detected 0 will be returned. + * @note Selects the first matching device in the library. + */ +uint32_t spifiGetHandleMemSize(uint32_t spifiCtrlAddr); + +/** + * @brief Initialize driver and hardware for a specific device + * @param pMem : Pointer to a 32-bit aligned buffer with a size returned from spifiGetHandleMemSize() + * @param sizePMem : Size of the buffer in bytes pass in pMem + * @param spifiCtrlAddr : Base address of SPIFI controller + * @param baseAddr : Base address of device + * @return Returns a pointer to a device handle if successful, or NULL on an error. + */ +SPIFI_HANDLE_T *spifiInitDevice(void *pMem, uint32_t sizePMem, uint32_t spifiCtrlAddr, uint32_t baseAddr); + +/** + * @brief Set or unset driver options + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param options : Options to set or unset, an OR'ed value of SPIFI_OPT_xxx values + * (example #SPIFI_OPT_USE_QUAD | #SPIFI_OPT_NOBLOCK) + * @param set : true to set the passed options, false to clear them + * @return Nothing + * @note Only options that are supported in the capabilities of the driver can be + * set or unset. + */ +SPIFI_ERR_T spifiDevSetOpts(SPIFI_HANDLE_T *pHandle, uint32_t options, uint8_t set); + +/** + * @} + */ + +/** @defgroup LPCSPIFILIB_DEVAPI LPCSPIFILIB library device functions + * Device functions are used to perform LPCSPIFILIB device operations. + * @{ + */ + +/** + * @brief Add device to family driver + * @param pFamily : Pointer to a SPIFI_DEV_FAMILY_T family handle + * @param pDevData : Pointer to a persistent SPIFI_DEV_DATA_T device structure + * @return A SPIFI_ERR_T error code (SPIFI_ERR_NONE for no errors) + * @note This function MUST be called prior to spifiGetHandleMemSize() or spifiInitDevice() + */ +SPIFI_ERR_T spifiDevRegister(const SPIFI_FAM_NODE_T *pFamily, SPIFI_DEV_NODE_T *pDevData); + +/** + * @brief Returns the number of supported devices within a family + * @param pFamily : Pointer to a SPIFI_DEV_FAMILY_T family handle + * @return The number of registered devices. + */ +static INLINE uint32_t spifiDevGetCount(const SPIFI_FAM_NODE_T *pFamily) +{ + return *(pFamily->pDesc->pDevCount); +} + +/** + * @brief Enumerates the friendly names of supported devices + * @param pContext : Pointer to a SPIFI_DEV_ENUMERATOR_T context structure + * @param reset : 0 enumerates next device, 1 resets list to beginning and returns first device + * @return A friendly string representing the device, NULL when list has been exhausted. + */ +const char *spifiDevEnumerateName(SPIFI_DEV_ENUMERATOR_T *pContext, uint8_t reset); + +/** + * @brief Initialize a detected LPCSPIFILIB device + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +SPIFI_ERR_T spifiDevInit(const SPIFI_HANDLE_T *pHandle); + +/** + * @brief De-initialize a detected LPCSPIFILIB device + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +SPIFI_ERR_T spifiDevDeInit(const SPIFI_HANDLE_T *pHandle); + +/** + * @brief Sets or clears memory mode + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param enMMode : true to enable memory mode, false to disable + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + * @note Enter memory mode to enable direct read access for Execute in + * place code and memory mapped data. Memory mode must be disabled + * for most operations. + */ +SPIFI_ERR_T spifiDevSetMemMode(const SPIFI_HANDLE_T *pHandle, uint8_t enMMode); + +/** + * @brief Return status of memory mode + * @param pSpifi : Base address of SPIFI controller + * @return state of memory mode (false = off, true = on) + */ +uint8_t spifiDevGetMemoryMode(const SPIFI_HANDLE_T *pSpifi); + +/** + * @brief Full LPCSPIFILIB device unlock + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevUnlockDevice(const SPIFI_HANDLE_T *pHandle) +{ + return pHandle->pFamFx->lockCmd(pHandle, SPIFI_PCMD_UNLOCK_DEVICE, 0); +} + +/** + * @brief Full LPCSPIFILIB device lock + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevLockDevice(const SPIFI_HANDLE_T *pHandle) +{ + return pHandle->pFamFx->lockCmd(pHandle, SPIFI_PCMD_LOCK_DEVICE, 0); +} + +/** + * @brief Unlock a single device block + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param block : Block number to unlock + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevUnlockBlock(const SPIFI_HANDLE_T *pHandle, uint32_t block) +{ + return pHandle->pFamFx->lockCmd(pHandle, SPIFI_PCMD_UNLOCK_BLOCK, block); +} + +/** + * @brief Lock a single device block + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param block : Block number to lock + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevLockBlock(const SPIFI_HANDLE_T *pHandle, uint32_t block) +{ + return pHandle->pFamFx->lockCmd(pHandle, SPIFI_PCMD_LOCK_BLOCK, block); +} + +/** + * @brief Full LPCSPIFILIB device erase + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevEraseAll(const SPIFI_HANDLE_T *pHandle) +{ + return pHandle->pFamFx->eraseAll(pHandle); +} + +/** + * @brief Erase a sub-block + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param blknum : Sub-block number to erase + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + */ +static INLINE SPIFI_ERR_T spifiDevEraseSubBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blknum) +{ + return pHandle->pFamFx->eraseSubBlock(pHandle, blknum); +} + +/** + * @brief Program up to a page of data at an address + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : LPCSPIFILIB device address to start write at + * @param writeBuff : Address of buffer to write, must be 32-bit aligned + * @param bytes : Number of bytes to write, must not exceed page length + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + * @note Only use this function to program data up to the page size. + */ +static INLINE SPIFI_ERR_T spifiDevPageProgram(const SPIFI_HANDLE_T *pHandle, + uint32_t addr, + uint32_t *writeBuff, + uint32_t bytes) +{ + return pHandle->pFamFx->pageProgram(pHandle, addr, writeBuff, bytes); +} + +/** + * @brief Read data from a LPCSPIFILIB device + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : LPCSPIFILIB device address to read from + * @param readBuff : Address of buffer to fill, must be 32-bit aligned + * @param bytes : Number of bytes to read + * @return A SPIFI_NO_* error code (SPIFI_ERR_NONE is no errors) + * @note Maximum read size is limited to the max single read size + */ +static INLINE SPIFI_ERR_T spifiDevRead(const SPIFI_HANDLE_T *pHandle, uint32_t addr, uint32_t *readBuff, uint32_t bytes) +{ + return pHandle->pFamFx->read(pHandle, addr, readBuff, bytes); +} + +/** + * @brief Reset the device + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return Nothing + * @note Will set the device into read mode + */ +static INLINE void spifiDevReset(const SPIFI_HANDLE_T *pHandle) +{ + pHandle->pFamFx->reset(pHandle); +} + +/** + * @brief Returns a string pointer to the generic device family name + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @return a string pointer to the generic device family name + */ +static INLINE const char *spifiDevGetDeviceName(const SPIFI_HANDLE_T *pHandle) +{ + return pHandle->pInfoData->pDevName; +} + +#define spifiDevGetFamilyName spifiDevGetDeviceName /**< Deprecated! Do NOT use for new development */ + +/** + * @brief Returns information on the device + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param infoId : Info to get about the device + * @return Return value varies per selected function + */ +uint32_t spifiDevGetInfo(const SPIFI_HANDLE_T *pHandle, SPIFI_INFO_ID_T infoId); + +/** + * @} + */ + +/** @defgroup LPCSPIFILIB_HELPAPI LPCSPIFILIB library helper functions + * @{ + */ + +/** + * @brief Returns the starting address of a block number + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param blockNum : Block number fo get starting address for + * @return The starting address for the block, or 0xFFFFFFFF if the block number if invalid + */ +uint32_t spifiGetAddrFromBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blockNum); + +/** + * @brief Returns the starting address of a sub-block number + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param subBlockNum : Sub-block number fo get starting address for + * @return The starting address for the sub-block, or 0xFFFFFFFF if the block number if invalid + */ +uint32_t spifiGetAddrFromSubBlock(const SPIFI_HANDLE_T *pHandle, uint32_t subBlockNum); + +/** + * @brief Returns the block number the passed address is located in + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : Address to get block number for + * @return The block number the passed address is in, 0xFFFFFFFF is the address is invalid + */ +uint32_t spifiGetBlockFromAddr(const SPIFI_HANDLE_T *pHandle, uint32_t addr); + +/** + * @brief Returns the sub-block number the passed address is located in + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : Address to get sub-block number for + * @return The sub-block number the passed address is in, 0xFFFFFFFF is the address is invalid + */ +uint32_t spifiGetSubBlockFromAddr(const SPIFI_HANDLE_T *pHandle, uint32_t addr); + +/** + * @brief Returns the first sub-block for a block + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param blockNum : Block number to get first sub-block for + * @return The first sub-block number in passed block, 0xFFFFFFFF if the block number if invalid + */ +uint32_t spifiGetSubBlockFromBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blockNum); + +/** + * @brief Program the device with the passed buffer + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : LPCSPIFILIB device address to start write at + * @param writeBuff : Address of buffer to write, must be 32-bit aligned + * @param bytes : Number of bytes to write + * @return A SPIFI_ERR_xxx error code (SPIFI_ERR_NONE is no errors) + * @note This function has no size limit. This function only works in blocking mode. + */ +SPIFI_ERR_T spifiProgram(const SPIFI_HANDLE_T *pHandle, uint32_t addr, const uint32_t *writeBuff, uint32_t bytes); + +/** + * @brief Read the device into the passed buffer + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param addr : LPCSPIFILIB device address to start read at + * @param readBuff : Address of buffer to read into, must be 32-bit aligned + * @param bytes : Number of bytes to read + * @return A SPIFI_ERR_xxx error code (SPIFI_ERR_NONE is no errors) + * @note This function has no size limit. Optionally, the device can be placed into memory + * mode and accessed directly via memory mapped reads without using this function. This + * function only works in blocking mode. + */ +SPIFI_ERR_T spifiRead(const SPIFI_HANDLE_T *pHandle, uint32_t addr, uint32_t *readBuff, uint32_t bytes); + +/** + * @brief Erase multiple blocks + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param firstBlock : First block number to erase + * @param numBlocks : Number of blocks to erase + * @return A SPIFI_ERR_xxx error code (SPIFI_ERR_NONE is no errors) + * @note If any of the specified params are invalid, the operation is aborted + * before any sectors are erased. This function only works in blocking mode. + */ +SPIFI_ERR_T spifiErase(const SPIFI_HANDLE_T *pHandle, uint32_t firstBlock, uint32_t numBlocks); + +/** + * @brief Erase multiple blocks by address range + * @param pHandle : Pointer to a LPCSPIFILIB device handle + * @param firstAddr : Starting address range for block erase + * @param lastAddr : Ending address range for block erase + * @return A SPIFI_ERR_xxx error code (SPIFI_ERR_NONE is no errors) + * @note This function will erase blocks inside the passed address + * range if and only if the address range is valid. + * This function only works in blocking mode. + */ +SPIFI_ERR_T spifiEraseByAddr(const SPIFI_HANDLE_T *pHandle, uint32_t firstAddr, uint32_t lastAddr); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SPIFILIB_API_H_ */ diff --git a/arch/arm/src/lpc43xx/spifi/inc/spifilib_dev.h b/arch/arm/src/lpc43xx/spifi/inc/spifilib_dev.h new file mode 100644 index 0000000000..0c499e91ff --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/inc/spifilib_dev.h @@ -0,0 +1,416 @@ +/* + * @brief LPCSPIFILIB FLASH library device specific functions + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licenser disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#ifndef __SPIFILIB_DEV_H_ +#define __SPIFILIB_DEV_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define for inline functions */ +#ifndef INLINE +#ifdef __CC_ARM +#define INLINE __inline +#else +#define INLINE inline +#endif /* __CC_ARM */ +#endif /* !INLINE */ + +/** @defgroup LPCSPIFILIB_DEV LPCSPIFILIB device driver API functions + * @ingroup LPCSPIFILIB + * @{ + */ +/** + * @brief Possible error codes that can be returned from functions + */ +typedef enum { + SPIFI_ERR_NONE = 0, /**< No error */ + SPIFI_ERR_BUSY, /**< Device is busy */ + SPIFI_ERR_GEN, /**< General error */ + SPIFI_ERR_NOTSUPPORTED, /**< Capability not supported */ + SPIFI_ERR_ALIGNERR, /**< Attempted to do an operation on an unaligned section of the device */ + SPIFI_ERR_LOCKED, /**< Device was locked and a program/erase operation was attempted */ + SPIFI_ERR_PROGERR, /**< Error programming device (blocking mode only) */ + SPIFI_ERR_ERASEERR, /**< Erase error (blocking mode only) */ + SPIFI_ERR_NOTBLANK, /**< Program operation on block that is not blank */ + SPIFI_ERR_PAGESIZE, /**< PageProgram write size exceeds page size */ + SPIFI_ERR_VAL, /**< Program operation failed validation or readback compare */ + SPIFI_ERR_RANGE, /**< Range error, bad block number, address out of range, etc. */ + SPIFI_ERR_MEMMODE, /**< Library calls not allowed while in memory mode. */ + /** @cond INTERNAL */ + SPIFI_ERR_LASTINDEX /* Internal use to count number of errors */ + /** @endcond */ +} SPIFI_ERR_T; + +/** + * @brief Possible device capabilities returned from getInfo() + */ +#define SPIFI_CAP_DUAL_READ (1 << 0) /**< Supports DUAL read mode */ +#define SPIFI_CAP_DUAL_WRITE (1 << 1) /**< Supports DUAL write mode */ +#define SPIFI_CAP_QUAD_READ (1 << 2) /**< Supports QUAD read mode */ +#define SPIFI_CAP_QUAD_WRITE (1 << 3) /**< Supports QUAD write mode */ +#define SPIFI_CAP_FULLLOCK (1 << 4) /**< Full device lock supported */ +#define SPIFI_CAP_BLOCKLOCK (1 << 5) /**< Individual block device lock supported */ +#define SPIFI_CAP_SUBBLKERASE (1 << 6) /**< Sub-block erase supported */ +#define SPIFI_CAP_4BYTE_ADDR (1 << 7) /**< Supports 4 Byte addressing */ +#define SPIFI_CAP_NOBLOCK (1 << 16) /**< Non-blocking mode supported */ + +/** + * @brief Possible driver options, may not be supported by all drivers + */ +#define SPIFI_OPT_USE_DUAL (3 << 0) /**< Enable DUAL read / write if option is supported */ +#define SPIFI_OPT_USE_QUAD (3 << 2) /**< Enable QUAD read / write if option is supported */ +#define SPIFI_OPT_NOBLOCK (1 << 16) /**< Will not block on program and erase operations, poll device status manually */ + +/** + * @brief Possible device statuses returned from getInfo() + */ +#define SPIFI_STAT_BUSY (1 << 0) /**< Device is busy erasing or programming */ +#define SPIFI_STAT_ISWP (1 << 1) /**< Device is write protected (software or hardware) */ +#define SPIFI_STAT_FULLLOCK (1 << 2) /**< Device is fully locked */ +#define SPIFI_STAT_PARTLOCK (1 << 3) /**< Device is partially locked (device specific) */ +#define SPIFI_STAT_PROGERR (1 << 4) /**< Device status shows a program error (non-blocking mode only) */ +#define SPIFI_STAT_ERASEERR (1 << 5) /**< Device status shows a erase error (non-blocking mode only) */ + +/** + * @brief Possible info lookup requests + */ +typedef enum { + SPIFI_INFO_BASE_ADDRESS = 0, /**< Device physical memory address */ + SPIFI_INFO_DEVSIZE, /**< Device size in Bytes */ + SPIFI_INFO_ERASE_BLOCKS, /**< Number of erase blocks */ + SPIFI_INFO_ERASE_BLOCKSIZE, /**< Size of erase blocks */ + SPIFI_INFO_ERASE_SUBBLOCKS, /**< Number of erase sub-blocks */ + SPIFI_INFO_ERASE_SUBBLOCKSIZE, /**< Size of erase sub-blocks */ + SPIFI_INFO_PAGESIZE, /**< Size of a page, page write size limit */ + SPIFI_INFO_MAXREADSIZE, /**< Maximum read size, read size limit in bytes */ + SPIFI_INFO_MAXCLOCK, /**< Maximum device speed in Hz */ + SPIFI_INFO_MAX_READ_CLOCK, /**< Maximum device speed for read cmd in Hz */ + SPIFI_INFO_MAX_HSREAD_CLOCK, /**< Maximum device speed for quad / dual read cmd in Hz */ + SPIFI_INFO_MAX_PROG_CLOCK, /**< Maximum device speed for program cmd in Hz */ + SPIFI_INFO_MAX_HSPROG_CLOCK, /**< Maximum device speed for quad program cmd in Hz */ + SPIFI_INFO_CAPS, /**< Device capabilities, OR'ed SPIFI_CAP_* values */ + SPIFI_INFO_STATUS, /**< Or'ed SPIFI_STAT_xxx values. Any persistent hardware bits will be cleared */ + SPIFI_INFO_STATUS_RETAIN, /**< Or'ed SPIFI_STAT_xxx values. Any persistent hardware bits will be retained */ + SPIFI_INFO_OPTIONS, /**< Device capabilities, Or'ed SPIFI_OPT_* values */ + + SPIFI_INFO_LASTINDEX +} SPIFI_INFO_ID_T; + +/** + * @brief SPIFI_INFO_QUADREAD_CLOCK Depricated! Do NOT use for new development + */ +#define SPIFI_INFO_QUADREAD_CLOCK SPIFI_INFO_MAX_HSREAD_CLOCK + +/** + * @brief SPIFI_INFO_QUADPROG_CLOCK Depricated! Do NOT use for new development + */ +#define SPIFI_INFO_QUADPROG_CLOCK SPIFI_INFO_MAX_HSPROG_CLOCK +/** + * @brief Possible device specific lock / un-lock commands + */ +typedef enum { + SPIFI_PCMD_UNLOCK_DEVICE = 0, /**< unlock device */ + SPIFI_PCMD_LOCK_DEVICE, /**< lock device */ + SPIFI_PCMD_UNLOCK_BLOCK, /**< unlock specified block */ + SPIFI_PCMD_LOCK_BLOCK /**< lock specified block */ + +} SPIFI_PCMD_LOCK_UNLOCK_T; + +/** + * @brief Possible device specific sub-block commands + */ +typedef enum { + SPIFI_PCMD_ADDR_TO_SUB_BLOCK = 0, /**< Convert address to a sub-block */ + SPIFI_PCMD_SUB_BLOCK_TO_ADDR, /**< Convert sub-block to address */ + SPIFI_PCMD_BLOCK_TO_SUB_BLOCK /**< Convert block to sub-block */ + +} SPIFI_PCMD_SUBBLK_T; + +/** + * @brief Enumeration of device specific functions. + */ +typedef enum { + FX_spifiDeviceDataInitDeinit = 0, /**< Generic device init / de-init function */ + FX_spifiDeviceDataInitDeinitS25FL164K, /**< S25FL164K specific device init / de-init function */ + + FX_spifiDeviceDataClearStatusNone, /**< General do nothing I.e no status bits to clear */ + FX_spifiDeviceDataClearStatusS25FL032P, /**< S25FL032P (and similar) clear status bits function */ + + FX_spifiDeviceDataGetStatusS25FL032P, /**< S25FL032P (and similar) get status function */ + FX_spifiDeviceDataGetStatusS25FL164K, /**< S25FL164K (and similar) get status function */ + FX_spifiDeviceDataGetStatusMX25L3235E, /**< MX25L3235E (and similar) get status function */ + FX_spifiDeviceDataGetStatusW25Q80BV, /**< W25Q80BV (and similar) get status function */ + + FX_spifiDeviceDataSetStatusS25FL032P, /**< S25FL032P (and similar) set status function */ + FX_spifiDeviceDataSetStatusS25FL164K, /**< S25FL164K (and similar) set status function */ + FX_spifiDeviceDataSetStatusMX25L3235E, /**< MX25L3235E (and similar) set sttus function */ + + FX_spifiDeviceDataSetOptsQuadModeBit9, /**< Set bit 9 when enabling Quad mode */ + FX_spifiDeviceDataSetOptsQuadModeBit6, /**< Set bit 6 when enabling Quad mode */ + + FX_spifiDeviceInitReadCommand, /**< General return cmdReg value for read */ + FX_spifiDevice4BInitReadCommand, /**< General return cmdReg value for read w/ 4Byte address */ + + FX_spifiDeviceInitWriteCommand, /**< General return cmdReg value for write */ + FX_spifiDevice4BInitWriteCommand, /**< General return cmdReg value for write w/ 4Byte address */ + FX_spifiDeviceInitWriteCommandMacronix /**< Macronix return cmdReg value for write */ + +} SPIFI_DEVFX_T; + +/* Forward type declaration */ +struct SPIFI_HANDLE; + +struct SPIFI_DEVICE_DATA; + +struct SPIFI_FAM_DESC; + +struct SPIFI_DEVICE_ID; + +/** + * @brief LPCSPIFILIB family data. + */ +typedef struct SPIFI_FAM_NODE { + const struct SPIFI_FAM_DESC *pDesc; /**< Pointer to device descriptor */ + + struct SPIFI_FAM_NODE *pNext; /**< Reserved list pointer */ + +} SPIFI_FAM_NODE_T; + +/** + * @brief LPCSPIFILIB family descriptor, used to describe devices to non-device specific functions + */ +typedef struct SPIFI_FAM_DESC { + const char *pFamName; /**< (required) Pointer to generic family name */ + struct SPIFI_DEV_NODE *pDevList; /**< (required) Pointer to device list */ + + uint32_t prvContextSize; /**< Number of bytes needed for driver context allocation */ + uint32_t *pDevCount; /**< (required) Pointer to device count */ + void (*pPrvDevGetID)(uint32_t baseAddr, struct SPIFI_DEVICE_ID *pID); /**< (NULL allowed) Pointer to method that queries deviceID */ + + SPIFI_ERR_T (*pPrvDevSetup)(struct SPIFI_HANDLE *pHandle, uint32_t spifiCtrlAddr, uint32_t baseAddr); /**< (required) Pointer to device specific device initialization */ + +} SPIFI_FAM_DESC_T; + +/** + * @brief Register device data node + */ +typedef struct SPIFI_DEV_NODE { + const struct SPIFI_DEVICE_DATA *pDevData; /**< (required) Pointer to device specific data */ + + struct SPIFI_DEV_NODE *pNext; /**< Reserved */ + +} SPIFI_DEV_NODE_T; + +typedef SPIFI_ERR_T (*deviceInitDeInitFx)(const struct SPIFI_HANDLE *, uint32_t); /**< Fx* to handle init / de-init */ + +typedef void (*devClearStatusFx)(const struct SPIFI_HANDLE *); /**< Fx* to clear status */ + +typedef uint32_t (*devGetStatusFx)(const struct SPIFI_HANDLE *); /**< Fx* to get status */ + +typedef void (*devSetStatusFx)(const struct SPIFI_HANDLE *, uint32_t); /**< Fx* to set status */ + +typedef SPIFI_ERR_T (*devSetOptsFx)(const struct SPIFI_HANDLE *, uint32_t, uint32_t); /**< Fx* to set options */ + +typedef void (*devGetReadCmdFx)(const struct SPIFI_HANDLE *, uint8_t, uint32_t *, uint32_t *); /**< Fx* to return read commandReg value */ + +typedef void (*devGetWriteCmdFx)(const struct SPIFI_HANDLE *, uint32_t *); /**< Fx* to return write commandReg value */ + +/** + * @brief Device specific function pointers + */ +typedef struct SPIFI_FAM_FX { + /* Device init and de-initialization */ + + SPIFI_ERR_T (*lockCmd)(const struct SPIFI_HANDLE *, SPIFI_PCMD_LOCK_UNLOCK_T, uint32_t); /**< (required) Lock / unlock handler */ + + SPIFI_ERR_T (*eraseAll)(const struct SPIFI_HANDLE *); /**< (required) Full device erase */ + + SPIFI_ERR_T (*eraseBlock)(const struct SPIFI_HANDLE *, uint32_t); /**< (required) Erase a block by block number */ + + SPIFI_ERR_T (*eraseSubBlock)(const struct SPIFI_HANDLE *, uint32_t); /**< (required) Erase a sub-block by block number */ + + SPIFI_ERR_T (*pageProgram)(const struct SPIFI_HANDLE *, uint32_t, const uint32_t *, uint32_t); /**< (required) Program up to a page of data at an address */ + + SPIFI_ERR_T (*read)(const struct SPIFI_HANDLE *, uint32_t, uint32_t *, uint32_t); /**< (required) Read an address range */ + + SPIFI_ERR_T (*reset)(const struct SPIFI_HANDLE *); /**< (required) Reset SPIFI device */ + + /* Info query functions */ + uint32_t (*getStatus)(const struct SPIFI_HANDLE *, uint8_t); /**< (required) Returns device status */ + + uint32_t (*subBlockCmd)(const struct SPIFI_HANDLE *, SPIFI_PCMD_SUBBLK_T, uint32_t); /**< (NULL allowed) Performs specified cmd */ + + /* Device specific functions */ + deviceInitDeInitFx devInitDeInit; /**< run-time assigned Fx* device init de-init */ + devClearStatusFx devClearStatus; /**< run-time assigned Fx* to clear status */ + devGetStatusFx devGetStatus; /**< run-time assigned Fx* to get status */ + devSetStatusFx devSetStatus; /**< run-time assigned Fx* to set status */ + devSetOptsFx devSetOpts; /**< run-time assigned Fx* to set quad mode */ + devGetReadCmdFx devGetReadCmd; /**< run-time assigned Fx* to return read cmd */ + devGetWriteCmdFx devGetWriteCmd; /**< run-time assigned Fx* to return write cmd */ +} SPIFI_FAM_FX_T; + +/** + * @brief Device identification data + */ +typedef struct SPIFI_DEVICE_ID { + uint8_t mfgId[3]; /**< JEDEC ID data */ + uint8_t extCount; /**< Number of extended bytes to check */ + uint8_t extId[8]; /**< extended data */ +} SPIFI_DEVICE_ID_T; + +/** + * @brief Register device data. + */ +typedef struct SPIFI_DEVICE_DATA { + const char *pDevName; /**< (required) Device friendly name */ + SPIFI_DEVICE_ID_T id; /**< Device id structure */ + uint32_t caps; /**< capabilities supported */ + uint16_t blks; /**< # of blocks */ + uint32_t blkSize; /**< size of block */ + uint16_t subBlks; /**< # of sub-blocks */ + uint16_t subBlkSize; /**< size of sub-block */ + uint16_t pageSize; /**< page size */ + uint32_t maxReadSize; /**< max read allowed in one operation */ + uint8_t maxClkRate; /**< (in Mhz) maximum clock rate (max common speed) */ + uint8_t maxReadRate; /**< (in Mhz) max clock rate for read (driver may utilize fast read) */ + uint8_t maxHSReadRate; /**< (in Mhz) max clock rate for quad / dual read */ + uint8_t maxProgramRate; /**< (in Mhz) max clock rate for program */ + uint8_t maxHSProgramRate; /**< (in Mhz) max clock rate for quad program */ + uint8_t initDeInitFxId; /**< init/DeInit fx_id */ + uint8_t clearStatusFxId; /**< clearStatus fx_id */ + uint8_t getStatusFxId; /**< getStatus fx_id */ + uint8_t setStatusFxId; /**< setStatus fx_id */ + uint8_t setOptionsFxId; /**< setOptions fx_id */ + uint8_t getReadCmdFxId; /**< getReadCommand fx_id */ + uint8_t getWriteCmdFxId; /**< getWriteCommand fx_id */ +} SPIFI_DEVICE_DATA_T; + +/** + * @brief LPCSPIFILIB device handle, used with all device and info functions + */ +typedef struct SPIFI_HANDLE { + const struct SPIFI_FAM_FX *pFamFx; /**< (required) Pointer to device specific functions */ + + struct SPIFI_INFODATA *pInfoData; /**< (required) Pointer to info data area */ + + void *pDevContext; /**< (NULL allowed) Pointer to device context (used by device functions) */ +} SPIFI_HANDLE_T; + +/** + * @brief Common data applicable to all devices + */ +typedef struct SPIFI_INFODATA { + uint32_t spifiCtrlAddr; /**< SPIFI controller base address */ + uint32_t baseAddr; /**< Physical base address for the device */ + uint32_t numBlocks; /**< Number of blocks on the device */ + uint32_t blockSize; /**< Size of blocks on the device */ + uint32_t numSubBlocks; /**< Number of sub-blocks on the device */ + uint32_t subBlockSize; /**< Size of sub-blocks on the device */ + uint32_t pageSize; /**< Size of a page, usually denotes maximum write size in bytes for a single write operation */ + uint32_t maxReadSize; /**< Maximum read size in bytes for a single read operation */ + const struct SPIFI_DEVICE_DATA *pDeviceData; /**< (required) Pointer to device specific data */ + + uint32_t opts; /**< Device options of values SPIFI_OPT_* */ + const char *pDevName; /**< (required) Pointer to device name */ + SPIFI_ERR_T lastErr; /**< Last error for the driver */ + const SPIFI_DEVICE_ID_T *pId; /**< (required) Device id structure (JEDEC ID etc) */ +} SPIFI_INFODATA_T; + +/** + * @brief Context for enumerating devices + */ +typedef struct SPIFI_DEV_ENUMERATOR { + SPIFI_FAM_NODE_T *pFamily; /**< pointer to family node */ + SPIFI_DEV_NODE_T *pDevice; /**< pointer to device structure */ +} SPIFI_DEV_ENUMERATOR_T; + +/** + * @} + */ + +/** @defgroup LPCSPIFILIB_REGISTERHELPER LPCSPIFILIB family registration functions + * @ingroup LPCSPIFILIB + * @{ + */ + +/** + * @brief Family registration function + * @return A pointer to a persistent SPIFI_DEV_FAMILY_T initialized for family. + * @note This function constructs and returns a non-volitile SPIFI_DEV_FAMILY_T + * structure that contains family specific information needed to register family. + * This function MUST NOT be called directly and should only be passed to the + * registration function spifiRegisterFamily() + */ +SPIFI_FAM_NODE_T *spifi_REG_FAMILY_CommonCommandSet(void); + +/** + * @brief SPIFI_REG_FAMILY_Spansion_2Byte_PStatus Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_Spansion_2Byte_PStatus spifi_REG_FAMILY_CommonCommandSet + +/** + * @brief SPIFI_REG_FAMILY_Spansion_3Byte_Status Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_Spansion_3Byte_Status spifi_REG_FAMILY_CommonCommandSet + +/** + * @brief SPIFI_REG_FAMILY_Macronix_2Byte_Status Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_Macronix_2Byte_Status spifi_REG_FAMILY_CommonCommandSet + +/** + * @brief SPIFI_REG_FAMILY_SpansionS25FLP Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_SpansionS25FLP spifi_REG_FAMILY_CommonCommandSet + +/** + * @brief SPIFI_REG_FAMILY_SpansionS25FL1 Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_SpansionS25FL1 spifi_REG_FAMILY_CommonCommandSet + +/** + * @brief SPIFI_REG_FAMILY_MacronixMX25L Depricated! Do NOT use for new development + */ +#define SPIFI_REG_FAMILY_MacronixMX25L spifi_REG_FAMILY_CommonCommandSet + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __SPIFILIB_DEV_H_ */ diff --git a/arch/arm/src/lpc43xx/spifi/liblinks.xml b/arch/arm/src/lpc43xx/spifi/liblinks.xml new file mode 100644 index 0000000000..31566302a4 --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/liblinks.xml @@ -0,0 +1,32 @@ + + + + + ${workspace_loc:/spifilib_m4f_hard/inc} + + + ${workspace_loc:/spifilib_m4f_hard/inc} + + + spifilib_m4f_hard + + + ${workspace_loc:/spifilib_m4f_hard/Debug} + + + ${workspace_loc:/spifilib_m4f_hard/Release} + + + spifilib_m4f_hard + + + diff --git a/arch/arm/src/lpc43xx/spifi/src/Make.defs b/arch/arm/src/lpc43xx/spifi/src/Make.defs new file mode 100644 index 0000000000..8c2865247f --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/src/Make.defs @@ -0,0 +1,39 @@ +############################################################################ +# configs/lpc4330-xplorer/src/Makefile +# +# Copyright (C) 2015 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. +# +############################################################################ + +ifeq ($(CONFIG_SPIFI_LIBRARY),y) +CHIP_CSRCS += spifi/src/spifilib_fam_standard_cmd.c +CHIP_CSRCS += spifi/src/spifilib_dev_common.c +endif diff --git a/arch/arm/src/lpc43xx/spifi/src/spifilib_dev_common.c b/arch/arm/src/lpc43xx/spifi/src/spifilib_dev_common.c new file mode 100644 index 0000000000..8adc8f762b --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/src/spifilib_dev_common.c @@ -0,0 +1,864 @@ +/* + * @brief LPCSPIFILIB driver functions and structures that are not visible + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licenser disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#include "spifi/inc/spifilib_api.h" +#include "spifi/inc/private/spifilib_chiphw.h" + +/***************************************************************************** + * Private types/enumerations/variables + ****************************************************************************/ +#ifndef NULL +#define NULL 0L +#endif + +/* Declare the version numbers */ +#define LIBRARY_VERSION_MAJOR (1) +#define LIBRARY_VERSION_MINOR (03) + +/* device node count and linked list header */ +static uint32_t famCount = 0; +static SPIFI_FAM_NODE_T famListHead = {0}; + +/* Generic device OP Codes */ +#define SPIFI_OP_CODE_RDID 0x9F + +/* Number of supported devices */ +#define NUMSUPPDEVS (sizeof(pPrvDevs) / sizeof(SPIFI_DEVDESC_T *)) + +/* Mapped error strings to error codes */ +static const char *spifiErrStrings[SPIFI_ERR_LASTINDEX] = { + "No error", + "Device is busy", + "General error", + "Capability not supported", + "Alignment error", + "Device is locked", + "Program error", + "Erase error", + "Program region not blank", + "Page size exceeded", + "Validation error", + "Range exceeded", + "Not Allowed in Memory Mode" +}; + +static const char noName[] = "Invalid index"; + +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Private functions + ****************************************************************************/ +static uint8_t spifiPrvCheckExtendedMatch(SPIFI_DEV_NODE_T *pNode, SPIFI_DEVICE_ID_T *pID) +{ + uint32_t x; + + if (pID->extCount != pNode->pDevData->id.extCount) { + return 0; + } + + if (pNode->pDevData->id.extCount) { + for (x = 0; x < pID->extCount; ++x) { + if (pNode->pDevData->id.extId[x] != pID->extId[x]) { + return 0; + } + } + } + + return 1; +} + +static SPIFI_DEV_NODE_T *spifiPrvFindDeviceMatch(SPIFI_DEV_NODE_T *pHead, SPIFI_DEVICE_ID_T *pID, uint8_t checkExtended) +{ + SPIFI_DEV_NODE_T *pNode; + + /* search the list looking for a match. Skip over head node since + it is a dummy node and NEVER contains data */ + for (pNode = pHead->pNext; pNode != NULL; pNode = pNode->pNext) { + /* Manufacturer and part match? */ + if ((pID->mfgId[0] == pNode->pDevData->id.mfgId[0]) && + (pID->mfgId[1] == pNode->pDevData->id.mfgId[1]) && + (pID->mfgId[2] == pNode->pDevData->id.mfgId[2])) { + /* If extended data check it */ + uint8_t matchFound = 1; + if (checkExtended) { + matchFound = spifiPrvCheckExtendedMatch(pNode, pID); + + } + /* Match, time to exit */ + if (matchFound) { + return pNode; + } + } + } + return NULL; +} + +/* Read Identification */ +static void spifiPrvDevGetID(uint32_t spifiAddr, SPIFI_DEVICE_ID_T *pID) +{ + uint8_t idx; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) spifiAddr; + + /* Read ID command, plus read 3 bytes on data */ + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(SPIFI_OP_CODE_RDID) | + SPIFI_CMD_DATALEN(3 + pID->extCount) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + /* Get info from the device */ + pID->mfgId[0] = spifi_HW_GetData8(pSpifiCtrlAddr); /* Manufacturers ID */ + pID->mfgId[1] = spifi_HW_GetData8(pSpifiCtrlAddr); /* Memory Type */ + pID->mfgId[2] = spifi_HW_GetData8(pSpifiCtrlAddr); /* Memmory Capacity */ + + /* Read the specified number of extended bytes */ + for (idx = 0; idx < pID->extCount; ++idx) { + pID->extId[idx] = spifi_HW_GetData8(pSpifiCtrlAddr); + } + + spifi_HW_WaitCMD(pSpifiCtrlAddr); +} + +/* Detect if this device exists at the passed base address, returns 0 if the + device doesn't exist of the required memory allocation size for the device + context if the device exists. */ +static SPIFI_DEV_NODE_T *spifiPrvDevDetect(uint32_t spifiCtrlAddr, SPIFI_FAM_NODE_T *familyNode) +{ + SPIFI_DEV_NODE_T *devNode; + uint32_t idx; + SPIFI_DEVICE_ID_T id; + SPIFI_DEVICE_ID_T idVerify; + void (*pPrvspifiPrvDevGetID)(uint32_t baseAddr, SPIFI_DEVICE_ID_T *pID) = spifiPrvDevGetID; + + /* Do not ask for extended ID information yet */ + id.extCount = 0; + idVerify.extCount = 0; + + /* If the family has a specific readID routine, use it instead */ + if (familyNode->pDesc->pPrvDevGetID) { + pPrvspifiPrvDevGetID = familyNode->pDesc->pPrvDevGetID; + } + + /* Read device ID three times to validate. First read on a hard reset isn't reliable */ + pPrvspifiPrvDevGetID(spifiCtrlAddr, &id); + pPrvspifiPrvDevGetID(spifiCtrlAddr, &id); + pPrvspifiPrvDevGetID(spifiCtrlAddr, &idVerify); + + /* Compare both reads to make sure they match. If any byte doesn't compare, abort. */ + for (idx = 0; idx < sizeof(id.mfgId); ++idx) { + if (id.mfgId[idx] != idVerify.mfgId[idx]) { + return NULL; + } + } + + /* Find match for 3 bytes. If found, check to see if there is extended id information */ + devNode = spifiPrvFindDeviceMatch(familyNode->pDesc->pDevList, &id, 0); + if ((devNode) && (devNode->pDevData->id.extCount)) { + + /* read ID + extended ID data */ + id.extCount = devNode->pDevData->id.extCount; + pPrvspifiPrvDevGetID(spifiCtrlAddr, &id); + + /* Now get the node that matches JEDEC and extended data */ + devNode = spifiPrvFindDeviceMatch(familyNode->pDesc->pDevList, &id, 1); + } + + return devNode; +} + +/* Detect first SPIFI FLASH device at the passed base address */ +static SPIFI_FAM_NODE_T *spifiPrvPartDetect(uint32_t spifiCtrlAddr, SPIFI_DEV_NODE_T * *devData) +{ + SPIFI_FAM_NODE_T *pNode; + + /* Loop through the library and check for detected devices. + skip over head node because it is NEVER used. */ + for (pNode = famListHead.pNext; pNode != NULL; pNode = pNode->pNext) { + /* Match at this index */ + if ((*devData = spifiPrvDevDetect(spifiCtrlAddr, pNode)) != NULL) { + return pNode; + } + } + + return NULL; +} + +static uint32_t spifiPrvCalculateHandleSize(SPIFI_FAM_NODE_T *devData) +{ + /* This is the size needed for the device context instance by the driver */ + return sizeof(SPIFI_HANDLE_T) + sizeof(SPIFI_INFODATA_T) + + devData->pDesc->prvContextSize; +} + +static void *spifiPrvMemset(void *bufPtr, uint8_t value, uint32_t count) +{ + uint8_t *dest = (uint8_t *) bufPtr; + uint32_t index; + + for (index = 0; index < count; ++index) { + dest[index] = value; + } + return bufPtr; +} + +static void spifiPrvInitContext(SPIFI_DEV_ENUMERATOR_T *pContext, SPIFI_FAM_NODE_T *pFamily) +{ + /* Save the new family passed */ + pContext->pFamily = pFamily; + + /* Save pointer to device or NULL if No devices */ + if (pFamily) { + pContext->pDevice = pFamily->pDesc->pDevList->pNext; + } + else { + pContext->pDevice = NULL; + } +} + +/***************************************************************************** + * Public functions + ****************************************************************************/ +SPIFI_FAM_NODE_T *spifiRegisterFamily(SPIFI_FAM_NODE_T *(*regFx)(void)) +{ + SPIFI_FAM_NODE_T *pFam; + + /* Get the family node from the user */ + pFam = regFx(); + + /* If not a valid family return NULL and don't process */ + if (!pFam) { + return NULL; + } + + /* Insert the node into the beginning of the list */ + pFam->pNext = famListHead.pNext; + famListHead.pNext = pFam; + + /* update the count of known families */ + ++famCount; + + /* Return handle */ + return pFam; +} + +/* register a device (i.e append to the list of known devices) */ +SPIFI_ERR_T spifiDevRegister(const SPIFI_FAM_NODE_T *pDevFamily, SPIFI_DEV_NODE_T *pDevData) +{ + /* insert into the beginning of the list */ + pDevData->pNext = pDevFamily->pDesc->pDevList->pNext; + pDevFamily->pDesc->pDevList->pNext = pDevData; + + /* update the number of devices in the list */ + (*pDevFamily->pDesc->pDevCount) += 1; + + /* Nothing to do here yet */ + return SPIFI_ERR_NONE; +} + +/* enumerate the friendly names of supported devices */ +const char *spifiDevEnumerateName(SPIFI_DEV_ENUMERATOR_T *pContext, uint8_t reset) +{ + const char *retValue = NULL; + + /* If user requested reset, point back to the beginning of the list */ + if (reset) { + /* Initialize the device list from new family */ + spifiPrvInitContext(pContext, famListHead.pNext); + } + + /* Now get the friendly name of the current device and increment to the next device. */ + if (pContext->pDevice) { + /* Retrieve friendly name */ + retValue = pContext->pDevice->pDevData->pDevName; + + /* Point at next device */ + pContext->pDevice = pContext->pDevice->pNext; + + /* Point at next family if at end of device list */ + if (!pContext->pDevice) { + + /* Initialize the device list from new family */ + spifiPrvInitContext(pContext, pContext->pFamily->pNext); + } + } + return retValue; +} + +/* Report the library version number */ +uint16_t spifiGetLibVersion(void) +{ + return (LIBRARY_VERSION_MAJOR << 8) | LIBRARY_VERSION_MINOR; +} + +/* Initialize the SPIFILIB driver */ +SPIFI_ERR_T spifiInit(uint32_t spifiCtrlAddr, uint8_t reset) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) spifiCtrlAddr; + + if (reset) { + /* Reset controller */ + spifi_HW_ResetController(pSpifiCtrlAddr); + + /* Set intermediate data and memcmd registers. */ + spifi_HW_SetIDATA(pSpifiCtrlAddr, 0x0); + spifi_HW_SetMEMCMD(pSpifiCtrlAddr, 0); + + spifi_HW_ResetController(pSpifiCtrlAddr); + + /* Setup SPIFI controller */ + spifi_HW_SetCtrl(pSpifiCtrlAddr, + (SPIFI_CTRL_TO(1000) | + SPIFI_CTRL_CSHI(15) | + SPIFI_CTRL_RFCLK(1) | + SPIFI_CTRL_FBCLK(1))); + } + + /* Nothing to do here yet */ + return SPIFI_ERR_NONE; +} + +/* performs device specific initialization */ +SPIFI_ERR_T spifiDevInit(const SPIFI_HANDLE_T *pHandle) +{ + SPIFI_ERR_T retValue = SPIFI_ERR_NONE; + + /* call device specific initialization if provided */ + pHandle->pFamFx->devInitDeInit(pHandle, 1); + + /* make sure the controller is not in memMode */ + spifiDevSetMemMode(pHandle, 0); + + return retValue; +} + +/* performs device specific de-initialization */ +SPIFI_ERR_T spifiDevDeInit(const SPIFI_HANDLE_T *pHandle) +{ + SPIFI_ERR_T retValue = SPIFI_ERR_NONE; + + /* call device specific de-init if provided */ + pHandle->pFamFx->devInitDeInit(pHandle, 0); + + /* make sure the controller is in memMode */ + spifiDevSetMemMode(pHandle, 1); + + return retValue; +} + +/* Converts a SPIFILIB error code into a meaningful string */ +const char *spifiReturnErrString(SPIFI_ERR_T errCode) +{ + if (((unsigned int) errCode) < SPIFI_ERR_LASTINDEX) { + return spifiErrStrings[errCode]; + } + + return noName; +} + +/* Returns information on the device */ +uint32_t spifiDevGetInfo(const SPIFI_HANDLE_T *pHandle, SPIFI_INFO_ID_T infoId) +{ + uint32_t val = 0; + + /* Don't use switch statement to prevent including clib helpers */ + if (infoId == SPIFI_INFO_BASE_ADDRESS) { + val = pHandle->pInfoData->baseAddr; + } + else if (infoId == SPIFI_INFO_DEVSIZE) { + val = pHandle->pInfoData->numBlocks * pHandle->pInfoData->blockSize; + + } + else if (infoId == SPIFI_INFO_ERASE_BLOCKS) { + val = pHandle->pInfoData->numBlocks; + + } + else if (infoId == SPIFI_INFO_ERASE_BLOCKSIZE) { + val = pHandle->pInfoData->blockSize; + + } + else if (infoId == SPIFI_INFO_ERASE_SUBBLOCKS) { + val = pHandle->pInfoData->numSubBlocks; + + } + else if (infoId == SPIFI_INFO_ERASE_SUBBLOCKSIZE) { + val = pHandle->pInfoData->subBlockSize; + + } + else if (infoId == SPIFI_INFO_PAGESIZE) { + val = pHandle->pInfoData->pageSize; + + } + else if (infoId == SPIFI_INFO_MAXREADSIZE) { + val = pHandle->pInfoData->maxReadSize; + + } + else if (infoId == SPIFI_INFO_MAXCLOCK) { + val = (pHandle->pInfoData->pDeviceData->maxClkRate * 1000000); + + } + else if (infoId == SPIFI_INFO_MAX_READ_CLOCK) { + val = (pHandle->pInfoData->pDeviceData->maxReadRate * 1000000); + + } + else if (infoId == SPIFI_INFO_MAX_HSREAD_CLOCK) { + val = (pHandle->pInfoData->pDeviceData->maxHSReadRate * 1000000); + + } + else if (infoId == SPIFI_INFO_MAX_PROG_CLOCK) { + val = (pHandle->pInfoData->pDeviceData->maxProgramRate * 1000000); + + } + else if (infoId == SPIFI_INFO_MAX_HSPROG_CLOCK) { + val = (pHandle->pInfoData->pDeviceData->maxHSProgramRate * 1000000); + + } + else if (infoId == SPIFI_INFO_CAPS) { + val = pHandle->pInfoData->pDeviceData->caps; + + } + else if (infoId == SPIFI_INFO_STATUS) { + val = pHandle->pFamFx->getStatus(pHandle, 1); + + } + else if (infoId == SPIFI_INFO_STATUS_RETAIN) { + val = pHandle->pFamFx->getStatus(pHandle, 0); + + } + else if (infoId == SPIFI_INFO_OPTIONS) { + val = pHandle->pInfoData->opts; + } + + return val; +} + +/* Returns status of memory mode */ +uint8_t spifiDevGetMemoryMode(const SPIFI_HANDLE_T *pHandle) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + return (spifi_HW_GetStat(pSpifiCtrlAddr) & SPIFI_STAT_MCINIT) != 0; +} + +SPIFI_ERR_T spifiDevSetMemMode(const SPIFI_HANDLE_T *pHandle, uint8_t enMMode) +{ + uint32_t cmdValue; + uint32_t iDataValue; + uint32_t ctrlReg; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + /* RESET the memMode controller */ + spifi_HW_ResetController(pSpifiCtrlAddr); + + /* Wait for HW to acknowledge the reset. */ + spifi_HW_WaitRESET(pSpifiCtrlAddr); + + /* First off set the HW mode based on current option */ + ctrlReg = spifi_HW_GetCtrl(pSpifiCtrlAddr); + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_READ) { + ctrlReg &= ~(SPIFI_CTRL_DUAL(1)); + } + else if (pHandle->pInfoData->opts & SPIFI_CAP_DUAL_READ) { + ctrlReg |= SPIFI_CTRL_DUAL(1); + } + spifi_HW_SetCtrl(pSpifiCtrlAddr, ctrlReg); + + if (enMMode) { + /* Get the device specific memory mode command and iData values */ + pHandle->pFamFx->devGetReadCmd(pHandle, enMMode, &cmdValue, &iDataValue); + + /* Specify the intermediate data byte. */ + spifi_HW_SetIDATA(pSpifiCtrlAddr, iDataValue); + + /* Set the appropriate values in the command reg. */ + spifi_HW_SetCmd(pSpifiCtrlAddr, cmdValue); + spifi_HW_WaitCMD(pSpifiCtrlAddr); + spifi_HW_SetMEMCMD(pSpifiCtrlAddr, cmdValue); + } + else { + spifi_HW_SetIDATA(pSpifiCtrlAddr, 0xFF); + spifi_HW_SetMEMCMD(pSpifiCtrlAddr, 0); + + /* RESET the memMode controller */ + spifi_HW_ResetController(pSpifiCtrlAddr); + + /* Wait for HW to acknowledge the reset. */ + spifi_HW_WaitRESET(pSpifiCtrlAddr); + } + return SPIFI_ERR_NONE; +} + +/* Return the number of supported device families in this driver */ +uint32_t spifiGetSuppFamilyCount(void) +{ + /* return number of registered devices */ + return famCount; +} + +/* Return the driver family name for a specific index */ +const char *spifiGetSuppFamilyName(uint32_t index) +{ + uint32_t idx; + SPIFI_FAM_NODE_T *pNode; + + if (index >= famCount) { + return noName; + } + + /* cycle through the list of families skipping over head node since it + is NEVER used. Once we break out of this loop pNode should be + pointing at the correct node. */ + pNode = famListHead.pNext; + for (idx = 0; idx < index; ++idx) { + pNode = pNode->pNext; + } + + return pNode->pDesc->pFamName; +} + +/* Detect and return memory needed for device handle at passed address */ +uint32_t spifiGetHandleMemSize(uint32_t spifiCtrlAddr) +{ + uint32_t bytesNeeded = 0; + SPIFI_FAM_NODE_T *detectedPart; + SPIFI_DEV_NODE_T *devData; + + /* Find first device at the base address */ + detectedPart = spifiPrvPartDetect(spifiCtrlAddr, &devData); + if (detectedPart) { + /* This is the size needed for the device context instance by the driver */ + bytesNeeded = spifiPrvCalculateHandleSize(detectedPart); + } + + return bytesNeeded; +} + +/* Initialize driver and hardware for a specific device */ +SPIFI_HANDLE_T *spifiInitDevice(void *pMem, uint32_t sizePMem, uint32_t spifiCtrlAddr, uint32_t baseAddr) +{ + SPIFI_FAM_NODE_T *detectedPart; + SPIFI_DEV_NODE_T *devData; + SPIFI_HANDLE_T *pSpifiHandle; + uint32_t *pMem32 = (uint32_t *) pMem; + + /* Is the passed buffer size aligned on a 32-bit boundary? */ + if (((uint32_t) pMem32 & 0x3) != 0) { + return NULL; + } + + /* Detect the device at at the base address and abort on error. */ + detectedPart = spifiPrvPartDetect(spifiCtrlAddr, &devData); + if (!detectedPart) { + return NULL; + } + + /* Is passed memory space big enough? */ + if (spifiPrvCalculateHandleSize(detectedPart) > sizePMem) { + return NULL; + } + + /* Setup handle */ + pSpifiHandle = (SPIFI_HANDLE_T *) pMem; + + /* Clear entire device context areas */ + spifiPrvMemset(pMem, 0, sizePMem); + + /* Setup device info region */ + pMem32 += (sizeof(SPIFI_HANDLE_T) / sizeof(uint32_t)); + pSpifiHandle->pInfoData = (SPIFI_INFODATA_T *) pMem32; + + /* Save ptr to the detected device specific data into the handle */ + pSpifiHandle->pInfoData->pId = &devData->pDevData->id; + + /* Setup device private data region */ + pMem32 += (sizeof(SPIFI_INFODATA_T) / sizeof(uint32_t)); + pSpifiHandle->pDevContext = (void *) pMem32; + + /* Setup device specific data */ + pSpifiHandle->pInfoData->spifiCtrlAddr = spifiCtrlAddr; + pSpifiHandle->pInfoData->baseAddr = baseAddr; + pSpifiHandle->pInfoData->numBlocks = devData->pDevData->blks; + pSpifiHandle->pInfoData->blockSize = devData->pDevData->blkSize; + pSpifiHandle->pInfoData->numSubBlocks = devData->pDevData->subBlks; + pSpifiHandle->pInfoData->subBlockSize = devData->pDevData->subBlkSize; + pSpifiHandle->pInfoData->pageSize = devData->pDevData->pageSize; + pSpifiHandle->pInfoData->maxReadSize = devData->pDevData->maxReadSize; + pSpifiHandle->pInfoData->pDeviceData = devData->pDevData; + pSpifiHandle->pInfoData->pDevName = devData->pDevData->pDevName; + + /* Call device setup */ + pSpifiHandle->pInfoData->lastErr = detectedPart->pDesc->pPrvDevSetup(pSpifiHandle, spifiCtrlAddr, baseAddr); + + if (pSpifiHandle->pInfoData->lastErr != SPIFI_ERR_NONE) { + return NULL; + } + + /* Call the device specific init */ + pSpifiHandle->pInfoData->lastErr = spifiDevInit(pSpifiHandle); + if (pSpifiHandle->pInfoData->lastErr != SPIFI_ERR_NONE) { + return NULL; + } + + return pSpifiHandle; +} + +SPIFI_ERR_T spifiDevSetOpts(SPIFI_HANDLE_T *pHandle, uint32_t options, uint8_t set) +{ + /* default to not supported */ + SPIFI_ERR_T retValue = SPIFI_ERR_NOTSUPPORTED; + + /* If changing any of the high speed modes process seperately */ + if (options & (SPIFI_CAP_DUAL_READ | SPIFI_CAP_DUAL_WRITE | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE)) { + uint32_t hsOptions; + uint8_t memMode; + + /* first get the current memory mode */ + memMode = spifiDevGetMemoryMode(pHandle); + + /* First clear ALL high speed mode options */ + pHandle->pInfoData->opts &= + ~(SPIFI_CAP_DUAL_READ | SPIFI_CAP_DUAL_WRITE | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE); + + /* sanitize the change list */ + hsOptions = options & + (pHandle->pInfoData->pDeviceData->caps & + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_DUAL_WRITE | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE)); + + /* Now set the high speed options */ + if (set) { + pHandle->pInfoData->opts |= hsOptions; + } + + /* Perform device specific setup for the option */ + retValue = pHandle->pFamFx->devSetOpts(pHandle, hsOptions, set); + + /* remove so that it won't be interpreted as an error */ + options &= ~(SPIFI_CAP_DUAL_READ | SPIFI_CAP_DUAL_WRITE | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE); + + /* update memory mode when changing the high speed options */ + spifiDevSetMemMode(pHandle, memMode); + } + + /* If the remaining options are valid, process them */ + if ((options & pHandle->pInfoData->pDeviceData->caps) == options) { + retValue = SPIFI_ERR_NONE; + + /* Set the option in the driver so other routines will act accordingly */ + if (set) { + pHandle->pInfoData->opts |= options; + } + else { + pHandle->pInfoData->opts &= ~options; + } + + /* Perform device specific setup for the option if defined */ + if (pHandle->pFamFx->devSetOpts) { + retValue = pHandle->pFamFx->devSetOpts(pHandle, options, set); + } + + } + return retValue; +} + +/* Returns the address mapped to an block number */ +uint32_t spifiGetAddrFromBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blockNum) +{ + uint32_t baseAddr = 0xFFFFFFFF; + + if (blockNum < pHandle->pInfoData->numBlocks) { + baseAddr = pHandle->pInfoData->baseAddr + (blockNum * pHandle->pInfoData->blockSize); + } + + return baseAddr; +} + +/* Returns the starting address of a sub-block number */ +uint32_t spifiGetAddrFromSubBlock(const SPIFI_HANDLE_T *pHandle, uint32_t subBlockNum) +{ + uint32_t baseAddr = ~0UL; + + /* If the device provides a specific method for calculating the address use it. */ + if (!pHandle->pFamFx->subBlockCmd) { + /* If sub-blocks are not supported (.e numSubBlocks = 0) then return error */ + if (subBlockNum < pHandle->pInfoData->numSubBlocks) { + baseAddr = pHandle->pInfoData->baseAddr + (subBlockNum * pHandle->pInfoData->subBlockSize); + } + } + else { + baseAddr = pHandle->pFamFx->subBlockCmd(pHandle, SPIFI_PCMD_SUB_BLOCK_TO_ADDR, subBlockNum); + } + + return baseAddr; +} + +/* Returns the block number the passedd= address is located in */ +uint32_t spifiGetBlockFromAddr(const SPIFI_HANDLE_T *pHandle, uint32_t addr) +{ + uint32_t block; + block = (addr - pHandle->pInfoData->baseAddr) / pHandle->pInfoData->blockSize; + + if (block >= pHandle->pInfoData->numBlocks) { + return ~0UL; + } + + return block; +} + +/* Returns the sub-block number the passed address is located in */ +uint32_t spifiGetSubBlockFromAddr(const SPIFI_HANDLE_T *pHandle, uint32_t addr) +{ + uint32_t subBlock; + + /* If device does not support sub-blocks return error */ + if (!pHandle->pInfoData->subBlockSize) { + return ~0UL; + } + + if (!pHandle->pFamFx->subBlockCmd) { + subBlock = (addr - pHandle->pInfoData->baseAddr) / pHandle->pInfoData->subBlockSize; + + if (subBlock >= pHandle->pInfoData->numSubBlocks) { + return ~0UL; + } + } + else { + subBlock = pHandle->pFamFx->subBlockCmd(pHandle, SPIFI_PCMD_ADDR_TO_SUB_BLOCK, addr); + } + + return subBlock; +} + +/* Returns the first sub-block in hte passed block */ +uint32_t spifiGetSubBlockFromBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blockNum) +{ + uint32_t subBlock = ~0UL; + + if (!pHandle->pFamFx->subBlockCmd) { + /* If the blockNum passed is larger than this device, + or if sub-blocks are not supported report error */ + if ((blockNum >= pHandle->pInfoData->numBlocks) || + (!pHandle->pInfoData->subBlockSize)) { + return subBlock; + } + /* Calculate the sub-block number based on detected params */ + subBlock = (blockNum * (pHandle->pInfoData->blockSize / pHandle->pInfoData->subBlockSize)); + } + else { + + subBlock = pHandle->pFamFx->subBlockCmd(pHandle, SPIFI_PCMD_BLOCK_TO_SUB_BLOCK, blockNum); + } + + return subBlock; +} + +/* Program the device with the passed buffer */ +SPIFI_ERR_T spifiProgram(const SPIFI_HANDLE_T *pHandle, uint32_t addr, const uint32_t *writeBuff, uint32_t bytes) +{ + uint32_t sendBytes; + SPIFI_ERR_T err = SPIFI_ERR_NONE; + + /* Program using up to page size */ + while ((bytes > 0) && (err == SPIFI_ERR_NONE)) { + sendBytes = bytes; + if (sendBytes > pHandle->pInfoData->pageSize) { + sendBytes = pHandle->pInfoData->pageSize; + } + + err = pHandle->pFamFx->pageProgram(pHandle, addr, writeBuff, sendBytes); + addr += sendBytes; + writeBuff += (sendBytes >> 2); + bytes -= sendBytes; + } + + return err; +} + +/* Read the device into the passed buffer */ +SPIFI_ERR_T spifiRead(const SPIFI_HANDLE_T *pHandle, uint32_t addr, uint32_t *readBuff, uint32_t bytes) +{ + uint32_t readBytes; + SPIFI_ERR_T err = SPIFI_ERR_NONE; + + /* Read using up to the maximum read size */ + while ((bytes > 0) && (err == SPIFI_ERR_NONE)) { + readBytes = bytes; + if (readBytes > pHandle->pInfoData->maxReadSize) { + readBytes = pHandle->pInfoData->maxReadSize; + } + + err = pHandle->pFamFx->read(pHandle, addr, readBuff, readBytes); + addr += readBytes; + readBuff += (readBytes / sizeof(uint32_t)); + bytes -= readBytes; + } + + return err; +} + +/* Erase multiple blocks */ +SPIFI_ERR_T spifiErase(const SPIFI_HANDLE_T *pHandle, uint32_t firstBlock, uint32_t numBlocks) +{ + SPIFI_ERR_T err = SPIFI_ERR_NONE; + + if ((firstBlock + numBlocks) > pHandle->pInfoData->numBlocks) { + return SPIFI_ERR_RANGE; + } + + /* Only perform erase if numBlocks is != 0 */ + for (; (numBlocks); ++firstBlock, --numBlocks) { + err = pHandle->pFamFx->eraseBlock(pHandle, firstBlock); + if (err != SPIFI_ERR_NONE) { + break; + } + } + + return err; +} + +/* Erase multiple blocks by address range */ +SPIFI_ERR_T spifiEraseByAddr(const SPIFI_HANDLE_T *pHandle, uint32_t firstAddr, uint32_t lastAddr) +{ + uint32_t firstBlock, lastBlock; + SPIFI_ERR_T err = SPIFI_ERR_RANGE; + + /* Get block numbers for addresses */ + firstBlock = spifiGetBlockFromAddr(pHandle, firstAddr); + lastBlock = spifiGetBlockFromAddr(pHandle, lastAddr); + + /* Limit to legal address range */ + if ((firstBlock != ~0UL) && (lastBlock != ~0UL)) { + err = spifiErase(pHandle, firstBlock, ((lastBlock - firstBlock) + 1)); + } + + return err; +} diff --git a/arch/arm/src/lpc43xx/spifi/src/spifilib_fam_standard_cmd.c b/arch/arm/src/lpc43xx/spifi/src/spifilib_fam_standard_cmd.c new file mode 100644 index 0000000000..d51cb3a67c --- /dev/null +++ b/arch/arm/src/lpc43xx/spifi/src/spifilib_fam_standard_cmd.c @@ -0,0 +1,1866 @@ +/* + * @brief Common Command Set Family driver + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licenser disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ +#include + +#include "spifi/inc/spifilib_dev.h" +#include "spifi/inc/private/spifilib_chiphw.h" +#include +#include + +/* need access to the device register Fx without importing the whole API */ +extern SPIFI_ERR_T spifiDevRegister(SPIFI_FAM_NODE_T *pFamily, SPIFI_DEV_NODE_T *pDevData); + +/** @defgroup LPCSPIFILIB_CONFIG_STANDARD_CMD_SET LPCSPIFILIB Common Command set driver + * @ingroup LPCSPIFILIB_DRIVERS + * This driver includes support for the following devices. (Clones within {} brackets).
+ * S25FL016K {W25Q16DV}
+ * S25FL032P
+ * S25FL064P
+ * S25FL129P 64k Sector
+ * S25FL129P 256k Sector {S25FL128S}
+ * S25FL164K
+ * S25FL256S
+ * S25FL512S
+ * MX25L1635E
+ * MX25L3235E
+ * MX25L6435E
+ * MX25L8035E
+ * W25Q32FV
+ * W25Q64FV
+ * W25Q80BV {W25Q80DV}
+ * + * Driver Feature Specifics:
+ * - common command set
+ * + * Optimization: Ram / code size optimizations can be enabled by enabling specific + * devices in lieu of the default (all devices enabled). Change the setting of + * SPIFI_DEVICE_ALL to 0 and enable specific devices by changing the setting + * of the appropriate SPIFI_DEVICE_XXX to 1. + * @{ + */ + +/** + * @} + */ + +/***************************************************************************** + * Private types/enumerations/variables + ****************************************************************************/ +/** + * @brief The following set of defines allows fine tuning where specific device support + * can be pre determined and space is at a premium. To Reduce code / iRam requirements + * change the SPIFI_DEVICE_ALL to 0 and change the desired device definition(s) to 1 + */ +//#define SPIFI_DEVICE_ALL 0 /**< Enables all devices in family */ +//#define SPIFI_DEVICE_S25FL016K 0 /**< Enables Spansion S25FL016K device */ +//#define SPIFI_DEVICE_S25FL032P 0 /**< Enables Spansion S25FL032P device */ +//#define SPIFI_DEVICE_S25FL064P 0 /**< Enables Spansion S25FL064P device */ +//#define SPIFI_DEVICE_S25FL129P_64K 0 /**< Enables Spansion S25FL129P (64K block) device */ +//#define SPIFI_DEVICE_S25FL129P_256K 0 /**< Enables Spansion S25FL129P (256K block) device */ +//#define SPIFI_DEVICE_S25FL164K 0 /**< Enables Spansion S25FL164K device */ +//#define SPIFI_DEVICE_S25FL256S_64K 0 /**< Enables Spansion S25FL256S (64K block) device */ +//#define SPIFI_DEVICE_S25FL256S_256K 0 /**< Enables Spansion S25FL256S (256K block) device */ +//#define SPIFI_DEVICE_S25FL512S 0 /**< Enables Spansion S25FL512S device */ +//#define SPIFI_DEVICE_MX25L1635E 0 /**< Enables Macronix MX25L1635E device */ +//#define SPIFI_DEVICE_MX25L3235E 0 /**< Enables Macronix MX25L3235E device */ +//#define SPIFI_DEVICE_MX25L8035E 0 /**< Enables Macronix MX25L8035E device */ +//#define SPIFI_DEVICE_MX25L6435E 0 /**< Enables Macronix MX25L6435E device */ +//#define SPIFI_DEVICE_W25Q32FV 0 /**< Enables Winbond W25Q32FV device */ +//#define SPIFI_DEVICE_W25Q64FV 0 /**< Enables Winbond W25Q32V device */ +//#define SPIFI_DEVICE_W25Q80BV 0 /**< Enables Winbond W25Q80BV device */ + +/* Required private data size for this family */ +#define PRVDATASIZE 0 + +#define MAX_SINGLE_READ 16128 + +/* Command definitions. Only used commands are defined. */ +#define CMD_0B_FAST_READ 0x0B /**< Read Data bytes at Fast Speed */ +#define CMD_BB_DIOR 0xBB /**< Dual IORead (all dual except op code( */ +#define CMD_EB_QIOR 0xEB /**< Quad IORead (all quad except op code) */ +#define CMD_0C_FAST_READ 0x0C /**< Read Data (4B addr) bytes at Fast Speed */ +#define CMD_BC_DIOR 0xBC /**< Dual IORead (4B addr) (all dual except op code( */ +#define CMD_EC_QIOR 0xEC /**< Quad IORead (4B addr) (all quad except op code) */ +#define CMD_06_WREN 0x06 /**< Write Enable */ +#define CMD_20_P4E 0x20 /**< 4 KB Parameter Sector Erase */ +#define CMD_C7_BE 0xC7 /**< Bulk Erase */ +#define CMD_D8_SE 0xD8 /**< Sector Erase */ +#define CMD_DC_SE 0xDC /**< Sector erase (4B addr) */ +#define CMD_02_PP 0x02 /**< Page Programming */ +#define CMD_12_PP 0x12 /**< Page Programming (4B addr) */ +#define CMD_05_RDSR1 0x05 /**< Read Status Register 1 */ +#define CMD_35_RDSR2 0x35 /**< Read Status Register 2 */ +#define CMD_33_RDSR3 0x33 /**< Read Status Register 3 */ +#define CMD_01_WSR 0x01 /**< Write Status Registers */ +#define CMD_30_CSR 0x30 /**< Reset the Erase and Program Fail Flag (SR5 and SR6) and restore normal operation) */ +#define CMD_32_QPP 0x32 /**< Quad Page Programming */ +#define CMD_34_QPP 0x34 /**< Quad Page Programming (4B addr) */ +#define CMD_38_QPP_MACRONIX 0x38 /**< Quad Page Programming for 25L3235E */ + +/* Common status register definitions */ +/* Status Register Write Disable, + 1 = Protects when W# is low, + 0 = No protection, even when W# is low */ +#define STATUS_SRWD (1 << 7) + +/* Block protect bits, + Protects upper half of address range in 5 sizes */ +#define STATUS_BPMASK (7 << 2) +/* Write Enable Latch, + 1 = Device accepts Write Status Register, program, or erase commands, + 0 = Ignores Write Status Register, program, or erase commands */ +#define STATUS_WEL (1 << 1) +/* Write in Progress, + 1 = Device Busy. A Write Status Register, program, or erase, + 0 = Ready. Device is in standby mode and can accept commands. */ +#define STATUS_WIP (1 << 0) + +/* Virtual status bits + (i.e moved to byte 4 so they don't conflict with bits in lower 3 bytes */ +/* Programming Error Occurred, + 0 = No Error, + 1 = Error occurred */ +#define STATUS_P_ERR (1 << 24) +/* Erase Error Occurred, + 0 = No Error, + 1 = Error occurred */ +#define STATUS_W_ERR (1 << 25) + +/* Functions used macro definitions */ +/* Macros to control conditional use functions */ +#define NEED_spifiDeviceDataGetStatusS25FL032P (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S) + +#define NEED_spifiDeviceDataGetStatusS25FL164K (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL164K) + +#define NEED_spifiDeviceDataGetStatusMX25L3235E (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceDataGetStatusW25Q80BV (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV) + +#define NEED_spifiDeviceDataClearStatusNone (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceDataClearStatusS25FL032P (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL164K | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S) + +#define NEED_spifiDeviceDataSetStatusS25FL032P (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV) + +#define NEED_spifiDeviceDataSetStatusS25FL164K (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL164K) + +#define NEED_spifiDeviceDataSetStatusMX25L3235E (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceDataSetOptsQuadModeBit6 (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceDataSetOptsQuadModeBit9 (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL164K | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV) + +#define NEED_spifiDeviceDataInitDeinit (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceDataInitDeinitS25FL164K (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL164K) + +#define NEED_spifiDevice4BInitReadCommand (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S) + +#define NEED_spifiDeviceInitReadCommand (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL164K | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L8035E | \ + SPIFI_DEVICE_MX25L6435E) + +#define NEED_spifiDeviceInitWriteCommand (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL016K | \ + SPIFI_DEVICE_S25FL032P | \ + SPIFI_DEVICE_S25FL064P | \ + SPIFI_DEVICE_S25FL129P_64K | \ + SPIFI_DEVICE_S25FL129P_256K | \ + SPIFI_DEVICE_S25FL164K | \ + SPIFI_DEVICE_W25Q80BV | \ + SPIFI_DEVICE_W25Q32FV | \ + SPIFI_DEVICE_W25Q64FV | \ + SPIFI_DEVICE_MX25L8035E) + +#define NEED_spifiDevice4BInitWriteCommand (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_S25FL256S_64K | \ + SPIFI_DEVICE_S25FL256S_256K | \ + SPIFI_DEVICE_S25FL512S) + +#define NEED_spifiDeviceInitWriteCommandMacronix (SPIFI_DEVICE_ALL | \ + SPIFI_DEVICE_MX25L1635E | \ + SPIFI_DEVICE_MX25L3235E | \ + SPIFI_DEVICE_MX25L6435E) + +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Private functions + ****************************************************************************/ + +/* Software write Enable */ +static void spifiPrvSetWREN(LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr) +{ + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_06_WREN) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + spifi_HW_WaitCMD(pSpifiCtrlAddr); +} + +/* Wait for device to complete operation (I.e not busy) */ +static void spifiPrvWaitUnBusy(const SPIFI_HANDLE_T *pHandle) +{ + /* Device wait for device to be ready */ + while ((pHandle->pFamFx->devGetStatus(pHandle) & STATUS_WIP) != 0) {} +} + +static void spifiPrvSetQuadModeBitPosition(const SPIFI_HANDLE_T *pHandle, uint32_t bitPosition, uint8_t enQuadMode) +{ + uint32_t statusRegs; + + /* Read the device specific status bytes */ + statusRegs = pHandle->pFamFx->devGetStatus(pHandle); + + /* Set / clear bit x */ + if (enQuadMode) { + statusRegs |= (1 << bitPosition); + } + else { + statusRegs &= ~(1 << bitPosition); + } + + /* Write status back out */ + pHandle->pFamFx->devSetStatus(pHandle, statusRegs); +} + +/* Checks to see if the device is writable and not busy */ +static SPIFI_ERR_T spifiPrvCheckWriteState(const SPIFI_HANDLE_T *pHandle) +{ + uint32_t stat; + + /* Get status */ + stat = pHandle->pFamFx->devGetStatus(pHandle); + + /* Exit if blocks are locked or WIP in progress */ + if ((stat & STATUS_BPMASK) != 0) { + return SPIFI_ERR_LOCKED; + } + else if ((stat & STATUS_WIP) != 0) { + return SPIFI_ERR_BUSY; + } + + return SPIFI_ERR_NONE; +} + +/***************************************************************************** + * Semi-Private functions + * Functions may be assigned to SPIFI_DEVICE_DATA_T function pointers. + ****************************************************************************/ + +/* Read the status bytes for the following device(s)... */ +#if NEED_spifiDeviceDataGetStatusS25FL032P +static uint32_t spifiDeviceDataGetStatusS25FL032P(const SPIFI_HANDLE_T *pHandle) +{ + static const uint8_t spifiCmdOp[2] = {CMD_05_RDSR1, CMD_35_RDSR2}; + uint32_t statusReg = 0; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + uint32_t index; + + /* Read the status bytes needed */ + for (index = 0; index < (sizeof(spifiCmdOp) / sizeof(spifiCmdOp[0])); ++index) { + + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(spifiCmdOp[index]) | + SPIFI_CMD_DATALEN(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + statusReg |= (spifi_HW_GetData8(pSpifiCtrlAddr) << (8 * index)); + + /* Wait for command to complete */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + + /* Move the error bits to generic location */ + if (statusReg & (1 << 5)) { + statusReg |= STATUS_W_ERR; + } + if (statusReg & (1 << 6)) { + statusReg |= STATUS_P_ERR; + } + + /* Finally remove the error bits from the original location */ + statusReg &= ~(3 << 5); + + return statusReg; +} + +#endif + +/* Read the status bytes for the following device(s)... */ +#if NEED_spifiDeviceDataGetStatusS25FL164K +static uint32_t spifiDeviceDataGetStatusS25FL164K(const SPIFI_HANDLE_T *pHandle) +{ + static const uint8_t spifiCmdOp[3] = {CMD_05_RDSR1, CMD_35_RDSR2, CMD_33_RDSR3}; + uint32_t statusRegs = 0; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + uint32_t idx; + + for (idx = 0; idx < sizeof(spifiCmdOp) / sizeof(spifiCmdOp[0]); ++idx) { + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(spifiCmdOp[idx]) | + SPIFI_CMD_DATALEN(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + statusRegs |= (spifi_HW_GetData8(pSpifiCtrlAddr) << (8 * idx)); + + /* Wait for command to complete */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + + return statusRegs; +} + +#endif + +/* Read the status bytes for the following device(s)... */ +#if NEED_spifiDeviceDataGetStatusMX25L3235E +static uint32_t spifiDeviceDataGetStatusMX25L3235E(const SPIFI_HANDLE_T *pHandle) +{ + uint32_t statRegister; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_05_RDSR1) | + SPIFI_CMD_DATALEN(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + statRegister = spifi_HW_GetData8(pSpifiCtrlAddr); + + /* Wait for command to complete */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + return statRegister; +} + +#endif + +/* Read the status bytes for the following device(s)... */ +#if NEED_spifiDeviceDataGetStatusW25Q80BV +static uint32_t spifiDeviceDataGetStatusW25Q80BV(const SPIFI_HANDLE_T *pHandle) +{ + static const uint8_t spifiCmdOp[2] = {CMD_05_RDSR1, CMD_35_RDSR2}; + uint32_t statusReg = 0; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + uint32_t index; + + /* Read the status bytes needed */ + for (index = 0; index < (sizeof(spifiCmdOp) / sizeof(spifiCmdOp[0])); ++index) { + + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(spifiCmdOp[index]) | + SPIFI_CMD_DATALEN(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + statusReg |= (spifi_HW_GetData8(pSpifiCtrlAddr) << (8 * index)); + + /* Wait for command to complete */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + + return statusReg; +} + +#endif + +/* Software clear status for the following device(s) */ +#if NEED_spifiDeviceDataClearStatusNone +static void spifiDeviceDataClearStatusNone(const SPIFI_HANDLE_T *pHandle) +{ + /* Do nothing */ +} + +#endif + +/* Software clear status for the following device(s) */ +#if NEED_spifiDeviceDataClearStatusS25FL032P +static void spifiDeviceDataClearStatusS25FL032P(const SPIFI_HANDLE_T *pHandle) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_30_CSR) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + spifi_HW_WaitCMD(pSpifiCtrlAddr); +} + +#endif + +/* Write Status / Config Register for the following device(s) */ +#if NEED_spifiDeviceDataSetStatusS25FL032P +static void spifiDeviceDataSetStatusS25FL032P(const SPIFI_HANDLE_T *pHandle, uint32_t status) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + spifiPrvSetWREN(pSpifiCtrlAddr); + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_01_WSR) | + SPIFI_CMD_DATALEN(2) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + /* Write the data out. Don't worry about restoring error bits as they are read only anyway */ + spifi_HW_SetData8(pSpifiCtrlAddr, status); + spifi_HW_SetData8(pSpifiCtrlAddr, (status >> 8)); + + /* Wait for Controller to finish command */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* Wait for flash controller to finish command */ + spifiPrvWaitUnBusy(pHandle); +} + +#endif + +/* Write Status1, 2 and 3 Register for the following device(s) */ +#if NEED_spifiDeviceDataSetStatusS25FL164K +static void spifiDeviceDataSetStatusS25FL164K(const SPIFI_HANDLE_T *pHandle, uint32_t status) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + spifiPrvSetWREN(pSpifiCtrlAddr); + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_01_WSR) | + SPIFI_CMD_DATALEN(3) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + /* Write the data out */ + spifi_HW_SetData8(pSpifiCtrlAddr, status); + spifi_HW_SetData8(pSpifiCtrlAddr, (status >> 8)); + spifi_HW_SetData8(pSpifiCtrlAddr, (status >> 16)); + + /* Wait for Controller to finish command */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* Wait for flash controller to finish command */ + spifiPrvWaitUnBusy(pHandle); +} + +#endif + +/* Write Status / Config Register for the following device(s)*/ +#if NEED_spifiDeviceDataSetStatusMX25L3235E +static void spifiDeviceDataSetStatusMX25L3235E(const SPIFI_HANDLE_T *pHandle, uint32_t status) +{ + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + spifiPrvSetWREN(pSpifiCtrlAddr); + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_01_WSR) | + SPIFI_CMD_DATALEN(1) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + /* Write the data out */ + spifi_HW_SetData8(pSpifiCtrlAddr, status); + + /* Wait for Controller to finish command */ + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* Wait for flash controller to finish command */ + spifiPrvWaitUnBusy(pHandle); +} + +#endif + +/* Function to change bit 6 of status/config register for the following device(s) */ +#if NEED_spifiDeviceDataSetOptsQuadModeBit6 +static SPIFI_ERR_T spifiDeviceDataSetOptsQuadModeBit6(const SPIFI_HANDLE_T *pHandle, uint32_t opts, uint32_t enMode) +{ + /* Do not attempt to set bit if option is not supported */ + if (opts & (SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE)) { + spifiPrvSetQuadModeBitPosition(pHandle, 6, enMode); + } + return SPIFI_ERR_NONE; +} + +#endif + +/* Function to change bit 9 of status/config register for the following device(s) */ +#if NEED_spifiDeviceDataSetOptsQuadModeBit9 +static SPIFI_ERR_T spifiDeviceDataSetOptsQuadModeBit9(const SPIFI_HANDLE_T *pHandle, uint32_t opts, uint32_t enMode) +{ + /* Do not attempt to set bit if option is not supported */ + if (opts & (SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE)) { + spifiPrvSetQuadModeBitPosition(pHandle, 9, enMode); + } + return SPIFI_ERR_NONE; +} + +#endif + +/* Initialize SPIFI device for the following device(s) */ +#if NEED_spifiDeviceDataInitDeinit +static SPIFI_ERR_T spifiDeviceDataInitDeinit(const SPIFI_HANDLE_T *pHandle, uint32_t init) +{ + return SPIFI_ERR_NONE; +} + +#endif + +/* Initialize SPIFI device for the following device(s) */ +#if NEED_spifiDeviceDataInitDeinitS25FL164K +static SPIFI_ERR_T spifiDeviceDataInitDeinitS25FL164K(const SPIFI_HANDLE_T *pHandle, uint32_t init) +{ + uint32_t status; + + /* Disable variable read latency */ + if (init) { + status = pHandle->pFamFx->devGetStatus(pHandle); + status &= ~(0xf << 16); /* Latency control bits for this part */ + pHandle->pFamFx->devSetStatus(pHandle, status); + } + + return SPIFI_ERR_NONE; +} + +#endif + +/* Function to return spifi controller read cmd */ +#if NEED_spifiDeviceInitReadCommand +static void spifiDeviceInitReadCommand(const SPIFI_HANDLE_T *pHandle, uint8_t enable, + uint32_t *cmd, uint32_t *iData) +{ + if (iData) { + *iData = 0xFF; + } + + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_READ) { + *cmd = + (SPIFI_CMD_OPCODE(CMD_EB_QIOR) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(3) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } + else if (pHandle->pInfoData->opts & SPIFI_CAP_DUAL_READ) { + *cmd = + (SPIFI_CMD_OPCODE(CMD_BB_DIOR) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } + /* Default to single lane mode if no other modes enabled */ + else { + *cmd = + (SPIFI_CMD_OPCODE(CMD_0B_FAST_READ) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } +} + +#endif + +/* Function to return spifi controller read cmd */ +#if NEED_spifiDevice4BInitReadCommand +static void spifiDevice4BInitReadCommand(const SPIFI_HANDLE_T *pHandle, uint8_t enable, + uint32_t *cmd, uint32_t *iData) +{ + if (iData) { + *iData = 0xFF; + } + + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_READ) { + *cmd = + (SPIFI_CMD_OPCODE(CMD_EC_QIOR) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(3) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS)); + } + else if (pHandle->pInfoData->opts & SPIFI_CAP_DUAL_READ) { + *cmd = + (SPIFI_CMD_OPCODE(CMD_BC_DIOR) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS)); + } + /* Default to single lane mode if no other modes enabled */ + else { + *cmd = + (SPIFI_CMD_OPCODE(CMD_0C_FAST_READ) | + SPIFI_CMD_DOUT(0) | + SPIFI_CMD_INTER(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS)); + } +} + +#endif + +/* Function to return spifi controller write cmd */ +#if NEED_spifiDeviceInitWriteCommand +static void spifiDeviceInitWriteCommand(const SPIFI_HANDLE_T *pHandle, uint32_t *cmd) +{ + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_WRITE) { + *cmd = (SPIFI_CMD_OPCODE(CMD_32_QPP) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE_ADDRESS) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } + else { + *cmd = (SPIFI_CMD_OPCODE(CMD_02_PP) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } +} + +#endif + +#if NEED_spifiDevice4BInitWriteCommand +static void spifiDevice4BInitWriteCommand(const SPIFI_HANDLE_T *pHandle, uint32_t *cmd) +{ + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_WRITE) { + *cmd = (SPIFI_CMD_OPCODE(CMD_34_QPP) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE_ADDRESS) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS)); + } + else { + *cmd = (SPIFI_CMD_OPCODE(CMD_12_PP) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS)); + } +} + +#endif + +/* Function to return spifi controller write cmd */ +#if NEED_spifiDeviceInitWriteCommandMacronix +static void spifiDeviceInitWriteCommandMacronix(const SPIFI_HANDLE_T *pHandle, uint32_t *cmd) +{ + if (pHandle->pInfoData->opts & SPIFI_CAP_QUAD_WRITE) { + *cmd = (SPIFI_CMD_OPCODE(CMD_38_QPP_MACRONIX) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_SERIAL_OPCODE) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } + else { + *cmd = (SPIFI_CMD_OPCODE(CMD_02_PP) | + SPIFI_CMD_DOUT(1) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS)); + } +} + +#endif + +/* Function to indicate configuration error */ +static void spifiDeviceFxError(void) +{ + while (1) {} +} + +/* Function to return Fx* for initialization */ +static deviceInitDeInitFx spifiDeviceAssignFxInitDeInit(SPIFI_HANDLE_T *pHandle) +{ + if (pHandle->pInfoData->pDeviceData->initDeInitFxId == FX_spifiDeviceDataInitDeinitS25FL164K) { +#if NEED_spifiDeviceDataInitDeinitS25FL164K + return spifiDeviceDataInitDeinitS25FL164K; +#endif + } + else if (pHandle->pInfoData->pDeviceData->initDeInitFxId == FX_spifiDeviceDataInitDeinit ) { +#if NEED_spifiDeviceDataInitDeinit + return spifiDeviceDataInitDeinit; +#endif + } + return (deviceInitDeInitFx) spifiDeviceFxError; +} + +/* Function to return Fx* for clearing status */ +static devClearStatusFx spifiDeviceAssignFxClearStatus(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device clearStatus Fx* */ + if (pHandle->pInfoData->pDeviceData->clearStatusFxId == FX_spifiDeviceDataClearStatusS25FL032P) { +#if NEED_spifiDeviceDataClearStatusS25FL032P + return spifiDeviceDataClearStatusS25FL032P; +#endif + } + else if (pHandle->pInfoData->pDeviceData->clearStatusFxId == FX_spifiDeviceDataClearStatusNone) { +#if NEED_spifiDeviceDataClearStatusNone + return spifiDeviceDataClearStatusNone; +#endif + } + return (devClearStatusFx) spifiDeviceFxError; +} + +/* Function to return Fx* for getting status */ +static devGetStatusFx spifiDeviceAssignFxGetStatus(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device getStatus Fx* */ + if (pHandle->pInfoData->pDeviceData->getStatusFxId == FX_spifiDeviceDataGetStatusS25FL032P) { +#if NEED_spifiDeviceDataGetStatusS25FL032P + return spifiDeviceDataGetStatusS25FL032P; +#endif + } + else if (pHandle->pInfoData->pDeviceData->getStatusFxId == FX_spifiDeviceDataGetStatusS25FL164K) { +#if NEED_spifiDeviceDataGetStatusS25FL164K + return spifiDeviceDataGetStatusS25FL164K; +#endif + } + else if (pHandle->pInfoData->pDeviceData->getStatusFxId == FX_spifiDeviceDataGetStatusMX25L3235E) { +#if NEED_spifiDeviceDataGetStatusMX25L3235E + return spifiDeviceDataGetStatusMX25L3235E; +#endif + } + else if (pHandle->pInfoData->pDeviceData->getStatusFxId == FX_spifiDeviceDataGetStatusW25Q80BV) { +#if NEED_spifiDeviceDataGetStatusW25Q80BV + return spifiDeviceDataGetStatusW25Q80BV; +#endif + } + return (devGetStatusFx) spifiDeviceFxError; +} + +/* Function for returning Fx* for setting status */ +static devSetStatusFx spifiDeviceAssignFxSetStatus(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device setStatus Fx* */ + if (pHandle->pInfoData->pDeviceData->setStatusFxId == FX_spifiDeviceDataSetStatusS25FL032P) { +#if NEED_spifiDeviceDataSetStatusS25FL032P + return spifiDeviceDataSetStatusS25FL032P; +#endif + } + else if (pHandle->pInfoData->pDeviceData->setStatusFxId == FX_spifiDeviceDataSetStatusS25FL164K) { +#if NEED_spifiDeviceDataSetStatusS25FL164K + return spifiDeviceDataSetStatusS25FL164K; +#endif + } + else if (pHandle->pInfoData->pDeviceData->setStatusFxId == FX_spifiDeviceDataSetStatusMX25L3235E) { +#if NEED_spifiDeviceDataSetStatusMX25L3235E + return spifiDeviceDataSetStatusMX25L3235E; +#endif + } + return (devSetStatusFx) spifiDeviceFxError; +} + +/* Function for returning Fx* for setting options */ +static devSetOptsFx spifiDeviceAssignFxSetOptions(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device setOptions Fx* */ + if (pHandle->pInfoData->pDeviceData->setOptionsFxId == FX_spifiDeviceDataSetOptsQuadModeBit9) { +#if NEED_spifiDeviceDataSetOptsQuadModeBit9 + return spifiDeviceDataSetOptsQuadModeBit9; +#endif + } + else if (pHandle->pInfoData->pDeviceData->setOptionsFxId == FX_spifiDeviceDataSetOptsQuadModeBit6) { +#if NEED_spifiDeviceDataSetOptsQuadModeBit6 + return spifiDeviceDataSetOptsQuadModeBit6; +#endif + } + return (devSetOptsFx) spifiDeviceFxError; +} + +/* Function for returning Fx* for getting spifi controller read cmd */ +static devGetReadCmdFx spifiDeviceAssignFxReadCmd(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device getReadCmd Fx* */ + if (pHandle->pInfoData->pDeviceData->getReadCmdFxId == FX_spifiDeviceInitReadCommand) { +#if NEED_spifiDeviceInitReadCommand + return spifiDeviceInitReadCommand; +#endif + } + else if (pHandle->pInfoData->pDeviceData->getReadCmdFxId == FX_spifiDevice4BInitReadCommand) { +#if NEED_spifiDevice4BInitReadCommand + return spifiDevice4BInitReadCommand; +#endif + } + return (devGetReadCmdFx) spifiDeviceFxError; +} + +/* Function for returning Fx* for getting spifi controller write cmd */ +static devGetWriteCmdFx spifiDeviceAssignFxWriteCmd(SPIFI_HANDLE_T *pHandle) +{ + /* Initialize the device getWriteCmd Fx* */ + if (pHandle->pInfoData->pDeviceData->getWriteCmdFxId == FX_spifiDeviceInitWriteCommand) { +#if NEED_spifiDeviceInitWriteCommand + return spifiDeviceInitWriteCommand; +#endif + } + else if (pHandle->pInfoData->pDeviceData->getWriteCmdFxId == FX_spifiDevice4BInitWriteCommand) { + #if NEED_spifiDevice4BInitWriteCommand + return spifiDevice4BInitWriteCommand; + #endif + } + else if (pHandle->pInfoData->pDeviceData->getWriteCmdFxId == FX_spifiDeviceInitWriteCommandMacronix) { +#if NEED_spifiDeviceInitWriteCommandMacronix + return spifiDeviceInitWriteCommandMacronix; +#endif + } + return (devGetWriteCmdFx) spifiDeviceFxError; +} + +/***************************************************************************** + * Semi-Private family functions + * Functions may be assigned to SPIFI_FAM_FX_T function pointers. + ****************************************************************************/ +/* Converts a device status to an OR'ed API status */ +static uint32_t spifiFamFxGetDeviceStatus(const SPIFI_HANDLE_T *pHandle, uint8_t clearStatus) +{ + uint32_t devStat; + uint32_t status = 0; + + /* Read device status word */ + devStat = pHandle->pFamFx->devGetStatus(pHandle); + + /* Convert to standard status values */ + if ((devStat & (STATUS_P_ERR | STATUS_W_ERR)) != 0) { + if ((devStat & STATUS_P_ERR) != 0) { + status |= SPIFI_STAT_PROGERR; + } + if ((devStat & STATUS_W_ERR) != 0) { + status |= SPIFI_STAT_ERASEERR; + } + + /* Only clear status if necessary */ + if (clearStatus) { + pHandle->pFamFx->devClearStatus(pHandle); + } + } + if ((devStat & STATUS_BPMASK) != 0) { + if ((devStat & STATUS_BPMASK) == STATUS_BPMASK) { + status |= SPIFI_STAT_FULLLOCK; + } + else { + status |= SPIFI_STAT_PARTLOCK; + } + } + if ((devStat & STATUS_WIP) != 0) { + status |= SPIFI_STAT_BUSY; + } + + return status; +} + +/* lock/ unlock commands */ +static SPIFI_ERR_T spifiFamFxLockDeviceCmd(const SPIFI_HANDLE_T *pHandle, SPIFI_PCMD_LOCK_UNLOCK_T cmd, uint32_t data) +{ + SPIFI_ERR_T status = SPIFI_ERR_NOTSUPPORTED; + + if ((cmd == SPIFI_PCMD_UNLOCK_DEVICE) || (cmd == SPIFI_PCMD_LOCK_DEVICE)) { + uint32_t stat; + + /* Get current status */ + stat = pHandle->pFamFx->devGetStatus(pHandle); + + if (cmd == SPIFI_PCMD_UNLOCK_DEVICE) { + /* Clear lock bits only if they are locked */ + if ((stat & STATUS_BPMASK) != 0) { + stat &= ~STATUS_BPMASK; + /* Write updated value back to status register */ + pHandle->pFamFx->devSetStatus(pHandle, stat); + } + } + else { + /* Clear lock bits only if they are locked */ + if ((stat & STATUS_BPMASK) != STATUS_BPMASK) { + stat |= STATUS_BPMASK; + /* Write updated value back to status register */ + pHandle->pFamFx->devSetStatus(pHandle, stat); + } + } + status = SPIFI_ERR_NONE; + } + + return status; +} + +/* Bulk Erase*/ +static SPIFI_ERR_T spifiFamFxEraseAll(const SPIFI_HANDLE_T *pHandle) +{ + SPIFI_ERR_T status; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + status = spifiPrvCheckWriteState(pHandle); + if (status == SPIFI_ERR_NONE) { + spifiPrvSetWREN(pSpifiCtrlAddr); + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_C7_BE) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP))); + + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* Device wait for device to become ready */ + spifiPrvWaitUnBusy(pHandle); + } + + return status; +} + +/* Erase a block by block number */ +static SPIFI_ERR_T spifiFamFxEraseBlock(const SPIFI_HANDLE_T *pHandle, uint32_t blockNum) +{ + uint16_t stat; + uint32_t addr; + SPIFI_ERR_T status = SPIFI_ERR_RANGE; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + if (blockNum < pHandle->pInfoData->numBlocks) { + status = spifiPrvCheckWriteState(pHandle); + if (status == SPIFI_ERR_NONE) { + addr = blockNum * pHandle->pInfoData->blockSize; + /* Only clear status if necessary */ + pHandle->pFamFx->devClearStatus(pHandle); + + spifiPrvSetWREN(pSpifiCtrlAddr); + + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + if (pHandle->pInfoData->pDeviceData->caps & SPIFI_CAP_4BYTE_ADDR) { + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_DC_SE) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_4ADDRESS))); + } + else { /* Setup for a 3 Byte address erase */ + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_D8_SE) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS))); + } + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* If blocking is disabled, exit now */ + if ((pHandle->pInfoData->opts & SPIFI_OPT_NOBLOCK) == 0) { + /* Device wait for device to become ready */ + spifiPrvWaitUnBusy(pHandle); + + /* Read status and check error bits */ + stat = spifiFamFxGetDeviceStatus(pHandle, 0); + if ((stat & SPIFI_STAT_ERASEERR) != 0) { + status = SPIFI_ERR_ERASEERR; + } + } + } + } + + return status; +} + +/* Erase a block by sub-block number */ +static SPIFI_ERR_T spifiFamFxEraseSubBlock(const SPIFI_HANDLE_T *pHandle, uint32_t subBlockNum) +{ + uint16_t stat; + uint32_t addr; + SPIFI_ERR_T status = SPIFI_ERR_RANGE; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + + if (subBlockNum < pHandle->pInfoData->numSubBlocks) { + status = spifiPrvCheckWriteState(pHandle); + if (status == SPIFI_ERR_NONE) { + addr = subBlockNum * pHandle->pInfoData->subBlockSize; + /* Only clear status if necessary */ + pHandle->pFamFx->devClearStatus(pHandle); + + spifiPrvSetWREN(pSpifiCtrlAddr); + + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + + spifi_HW_SetCmd(pSpifiCtrlAddr, + (SPIFI_CMD_OPCODE(CMD_20_P4E) | + SPIFI_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_SERIAL) | + SPIFI_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OP_3ADDRESS))); + + spifi_HW_WaitCMD(pSpifiCtrlAddr); + + /* If blocking is disabled, exit now */ + if ((pHandle->pInfoData->opts & SPIFI_OPT_NOBLOCK) == 0) { + /* Device wait for device to become ready */ + spifiPrvWaitUnBusy(pHandle); + + /* Read status and check error bits */ + stat = spifiFamFxGetDeviceStatus(pHandle, 0); + if ((stat & SPIFI_STAT_ERASEERR) != 0) { + status = SPIFI_ERR_ERASEERR; + } + } + } + } + + return status; +} + +/* Program a region */ +static SPIFI_ERR_T spifiFamFxPageProgram(const SPIFI_HANDLE_T *pHandle, + uint32_t addr, + const uint32_t *writeBuff, + uint32_t bytes) +{ + uint16_t stat; + uint8_t *writeBuff8; + SPIFI_ERR_T status = SPIFI_ERR_PAGESIZE; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + uint32_t cmdOnlyValue; + uint32_t dwords; + + if (bytes <= pHandle->pInfoData->pageSize) { + status = spifiPrvCheckWriteState(pHandle); + if (status == SPIFI_ERR_NONE) { + /* Get the program cmd value for this device */ + pHandle->pFamFx->devGetWriteCmd(pHandle, &cmdOnlyValue); + + /* Get the number of dwords to write */ + dwords = bytes >> 2; + + /* process by bytes if amount isn't even number of dwords */ + if (bytes & 0x3) { + + writeBuff8 = (uint8_t *) writeBuff; + + /* Only clear status if the device requires it and set write enable*/ + pHandle->pFamFx->devClearStatus(pHandle); + spifiPrvSetWREN(pSpifiCtrlAddr); + + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + spifi_HW_SetCmd(pSpifiCtrlAddr, cmdOnlyValue | SPIFI_CMD_DATALEN(bytes)); + /* Write data */ + while (bytes) { + spifi_HW_SetData8(pSpifiCtrlAddr, *writeBuff8); + ++writeBuff8; + --bytes; + } + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + else if (dwords) { + uint32_t cmdValue = cmdOnlyValue | SPIFI_CMD_DATALEN(dwords << 2); + + /* Only clear status if the device requires it and set write enable */ + pHandle->pFamFx->devClearStatus(pHandle); + spifiPrvSetWREN(pSpifiCtrlAddr); + + /* Set address and increment for any remaining */ + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + + /* Finally send command and write the data */ + spifi_HW_SetCmd(pSpifiCtrlAddr, cmdValue); + while (dwords) { + spifi_HW_SetData32(pSpifiCtrlAddr, *writeBuff); + ++writeBuff; + --dwords; + } + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + } + + /* If block is disabled, exit now */ + if ((pHandle->pInfoData->opts & SPIFI_OPT_NOBLOCK) == 0) { + /* Device wait for device to become ready */ + spifiPrvWaitUnBusy(pHandle); + + /* Read status and check error bits */ + stat = spifiFamFxGetDeviceStatus(pHandle, 0); + if ((stat & SPIFI_STAT_PROGERR) != 0) { + status = SPIFI_ERR_PROGERR; + } + } + } + + return status; +} + +/* Read a region */ +static SPIFI_ERR_T spifiFamFxReadDevice(const SPIFI_HANDLE_T *pHandle, + uint32_t addr, + uint32_t *readBuff, + uint32_t bytes) +{ + uint8_t *readBuff8 = (uint8_t *) readBuff; + SPIFI_ERR_T status = SPIFI_ERR_RANGE; + LPC_SPIFI_CHIPHW_T *pSpifiCtrlAddr = (LPC_SPIFI_CHIPHW_T *) pHandle->pInfoData->spifiCtrlAddr; + uint32_t cmdOnlyValue; + uint32_t cmdValue; + uint32_t dwords; + + /* Limit read to controller data limit in bytes */ + if (bytes <= pHandle->pInfoData->maxReadSize) { + /* Get the number of dwords to read */ + dwords = bytes >> 2; + bytes -= (dwords << 2); + + /* Get the command value to program the SPIFI controller */ + pHandle->pFamFx->devGetReadCmd(pHandle, 0, &cmdOnlyValue, NULL); + if (dwords) { + cmdValue = cmdOnlyValue | SPIFI_CMD_DATALEN(dwords << 2); + + /* Specify the intermediate data byte (turn off). */ + spifi_HW_SetIDATA(pSpifiCtrlAddr, 0xFF); + + /* Set the address and increment for any remaining bytes */ + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + addr += (dwords << 2); + + spifi_HW_SetCmd(pSpifiCtrlAddr, cmdValue); + while (dwords) { + *readBuff = spifi_HW_GetData32(pSpifiCtrlAddr); + ++readBuff; + --dwords; + } + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + + if (bytes) { + readBuff8 = (uint8_t *) readBuff; + cmdValue = cmdOnlyValue | SPIFI_CMD_DATALEN(bytes); + + /* Specify the intermediate data byte (turn off). */ + spifi_HW_SetIDATA(pSpifiCtrlAddr, 0xFF); + + spifi_HW_SetAddr(pSpifiCtrlAddr, addr); + spifi_HW_SetCmd(pSpifiCtrlAddr, cmdValue); + + /* Read data */ + while (bytes) { + *readBuff8 = spifi_HW_GetData8(pSpifiCtrlAddr); + ++readBuff8; + --bytes; + } + spifi_HW_WaitCMD(pSpifiCtrlAddr); + } + status = SPIFI_ERR_NONE; + } + + return status; +} + +/* Enable or disable software write protect state */ +static SPIFI_ERR_T spifiFamFxResetDevice(const SPIFI_HANDLE_T *pHandle) +{ + return SPIFI_ERR_NOTSUPPORTED; +} + +/* Setup a device */ +static SPIFI_ERR_T spifiFamFxDeviceSetup(SPIFI_HANDLE_T *pHandle, uint32_t spifiCtrlAddr, uint32_t baseAddr) +{ + /* Common Command Set family function table */ + static SPIFI_FAM_FX_T fxTable; + + fxTable.lockCmd = spifiFamFxLockDeviceCmd; + fxTable.eraseAll = spifiFamFxEraseAll; + fxTable.eraseBlock = spifiFamFxEraseBlock; + fxTable.eraseSubBlock = spifiFamFxEraseSubBlock; + fxTable.pageProgram = spifiFamFxPageProgram; + fxTable.read = spifiFamFxReadDevice; + fxTable.reset = spifiFamFxResetDevice; + fxTable.getStatus = spifiFamFxGetDeviceStatus; + fxTable.subBlockCmd = NULL; /* Use generic handler in spifilib_dev_common.c */ + + /* Initialize the device specific function pointers */ + fxTable.devInitDeInit = spifiDeviceAssignFxInitDeInit(pHandle); + fxTable.devClearStatus = spifiDeviceAssignFxClearStatus(pHandle); + fxTable.devGetStatus = spifiDeviceAssignFxGetStatus(pHandle); + fxTable.devSetStatus = spifiDeviceAssignFxSetStatus(pHandle); + fxTable.devSetOpts = spifiDeviceAssignFxSetOptions(pHandle); + fxTable.devGetReadCmd = spifiDeviceAssignFxReadCmd(pHandle); + fxTable.devGetWriteCmd = spifiDeviceAssignFxWriteCmd(pHandle); + + /* save pointer to family function table */ + pHandle->pFamFx = &fxTable; + + return SPIFI_ERR_NONE; +} + +/***************************************************************************** + * Public functions + ****************************************************************************/ +SPIFI_FAM_NODE_T *spifi_REG_FAMILY_CommonCommandSet(void) +{ + /* Variables declared static so they will persist after function returns. */ + /* All members are assigned at run-time so that position independent code + will know the address */ + static SPIFI_DEV_NODE_T devListBase = {0}; /* List base to hold devices */ + static SPIFI_FAM_NODE_T devFamily; /* Family node to hold family descriptor */ + static SPIFI_FAM_DESC_T famDesc; /* Family descriptor (holds all info about family) */ + static uint32_t devCount = 0; /* Variable to keep track of # registered devices */ + + /* Protect against multiple calls to register the same family */ + if (devCount) { + return NULL; + } + + /* Make sure that the base list is empty and the count reflects 0 */ + devListBase.pNext = NULL; + devCount = 0; + + /* Store the device specific info so it can be returned */ + famDesc.pFamName = "Common SPIFI Command Set"; + + /* Save the pointer to the device list and count */ + famDesc.pDevList = &devListBase; + famDesc.pDevCount = &devCount; + + famDesc.prvContextSize = 0; /* Reserve space for private data (this family doesn't need any)*/ + famDesc.pPrvDevGetID = NULL; /* Use the generic readID routine */ + famDesc.pPrvDevSetup = spifiFamFxDeviceSetup; /* Provide Fx to handle setup */ + + /* Save the descriptor in the handle */ + devFamily.pDesc = &famDesc; + + /* Begin Winbond devices */ + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_W25Q80BV + /* Add support for W25Q80BV */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "W25Q80BV", + {{0xEF, 0x40, 0x14}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | + SPIFI_CAP_NOBLOCK | SPIFI_CAP_SUBBLKERASE), + 16, /* # of blocks */ + 0x10000, /* block size */ + 256, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 0x100, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 104, /* max clock rate in Mhz */ + 104, /* max read clock rate in MHz */ + 104, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) Does not have persistent status */ + FX_spifiDeviceDataGetStatusW25Q80BV, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus (uses S25FL032P variant) */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_W25Q64FV + /* Add support for W25Q64FV */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "W25Q64FV", + {{0xEF, 0x40, 0x17}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | + SPIFI_CAP_NOBLOCK | SPIFI_CAP_SUBBLKERASE), + 128, /* # of blocks */ + 0x10000, /* block size */ + 2048, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 0x100, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 104, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 104, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) Does not have persistent status */ + FX_spifiDeviceDataGetStatusW25Q80BV, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus (uses S25FL032P variant) */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_W25Q32FV + /* Add support for W25Q32FV */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "W25Q32FV", + {{0xEF, 0x40, 0x16}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | + SPIFI_CAP_NOBLOCK | SPIFI_CAP_SUBBLKERASE), + 64, /* # of blocks */ + 0x10000, /* block size */ + 1024, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 0x100, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 104, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 104, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) Does not have persistent status */ + FX_spifiDeviceDataGetStatusW25Q80BV, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus (uses S25FL032P variant) */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + /* Begin Spansion devices */ + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL512S + /* Add support for S25FL512S 256K Sector */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL512S", + {{0x01, 0x02, 0x20}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_4BYTE_ADDR | SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), + 256, /* # of blocks */ + 0x40000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size */ + 512, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDevice4BInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDevice4BInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL256S_256K + /* Add support for S25FL256S 256K Sector */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL256S 256kSec", + {{0x01, 0x02, 0x19}, 2, {0x4D, 0x0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_4BYTE_ADDR | SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), + 128, /* # of blocks */ + 0x40000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDevice4BInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDevice4BInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL256S_64K + /* Add support for S25FL256S 64k sector */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL256S 64kSec", + {{0x01, 0x02, 0x19}, 2, {0x4D, 0x01}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_4BYTE_ADDR | SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), + 512, /* # of blocks */ + 0x10000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size 0x1000 */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDevice4BInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDevice4BInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL164K + /* Add support for S25FL164K */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL164K", + {{0x01, 0x40, 0x17}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK | SPIFI_CAP_SUBBLKERASE), /* does NOT support Quad Write */ + 128, /* # of blocks */ + 0x10000, /* block size */ + 2048, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 50, /* max clock rate in MHz */ + 97, /* max read clock rate in MHz */ + 97, /* max high speed read clock rate in MHz */ + 97, /* max program clock rate in MHz */ + 97, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinitS25FL164K, /* (Fx Id) device init / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) No persistent status */ + FX_spifiDeviceDataGetStatusS25FL164K, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL164K, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL129P_256K + /* Add support for S25FL129P 256K Sector. Clone: S25FL128S */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL129P 256kSec", + {{0x01, 0x20, 0x18}, 2, {0x4D, 0x0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), + 64, /* # of blocks */ + 0x40000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL129P_64K + /* Add support for S25FL129P 64k sector */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL129P 64kSec", + {{0x01, 0x20, 0x18}, 2, {0x4D, 0x01}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), + 256, /* # of blocks */ + 0x10000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size 0x1000 */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL064P + /* Add support for S25FL064P */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL064P", + {{0x01, 0x02, 0x16}, 1, {0x4d}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), /* Capabilities */ + 128, /* # of blocks */ + 0x10000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size 0x1000 */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL032P + /* Add support for S25FL032P */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL032P", + {{0x01, 0x02, 0x15}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | SPIFI_CAP_NOBLOCK), /* Capabilities */ + 64, /* # of blocks */ + 0x10000, /* block size */ + 0, /* # of sub-blocks (Does NOT support full sub-block erase) */ + 0, /* sub-block size 0x1000 */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusS25FL032P, /* (Fx Id) has persistent bits in status register */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* Fx* to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_S25FL016K + /* Add support for S25FL016K */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "S25FL016K", + {{0xef, 0x40, 0x15}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_FULLLOCK | + SPIFI_CAP_NOBLOCK | SPIFI_CAP_SUBBLKERASE), /* Capabilities */ + 32, /* # of blocks */ + 0x10000, /* block size */ + 512, /* # of sub-blocks (Does NOT support full sub-block erase)*/ + 0x1000, /* sub-block size 0x1000 */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 80, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 80, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) Does not have persistent status */ + FX_spifiDeviceDataGetStatusS25FL032P, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusS25FL032P, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit9, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommand /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + /* Begin Maxronix devices */ + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_MX25L8035E + /* Add support for MX25L8035E */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "MX25L8035E", + {{0xC2, 0x20, 0x14}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_NOBLOCK | + SPIFI_CAP_SUBBLKERASE), /* capabilities */ + 16, /* # of blocks */ + 0x10000, /* block size */ + 256, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 108, /* max read clock rate in MHz */ + 108, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) no persistent status */ + FX_spifiDeviceDataGetStatusMX25L3235E, /* (Fx Id) getStatus */ + FX_spifiDeviceDataSetStatusMX25L3235E, /* (Fx Id) setStatus */ + FX_spifiDeviceDataSetOptsQuadModeBit6, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommandMacronix /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_MX25L6435E + /* Add support for MX25L6435E */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "MX25L6435E", + {{0xC2, 0x20, 0x17}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_NOBLOCK | + SPIFI_CAP_SUBBLKERASE), /* capabilities */ + 128, /* # of blocks */ + 0x10000, /* block size */ + 2048, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 86, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) no persistent status */ + FX_spifiDeviceDataGetStatusMX25L3235E, /* (Fx Id) getStatus function */ + FX_spifiDeviceDataSetStatusMX25L3235E, /* (Fx Id) setStatus function */ + FX_spifiDeviceDataSetOptsQuadModeBit6, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommandMacronix /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_MX25L3235E + /* Add support for MX25L3235E */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "MX25L3235E", + {{0xC2, 0x20, 0x16}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_NOBLOCK | + SPIFI_CAP_SUBBLKERASE), /* capabilities */ + 64, /* # of blocks */ + 0x10000, /* block size */ + 1024, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 86, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) no persistent status */ + FX_spifiDeviceDataGetStatusMX25L3235E, /* (Fx Id) getStatus function */ + FX_spifiDeviceDataSetStatusMX25L3235E, /* (Fx Id) setStatus function */ + FX_spifiDeviceDataSetOptsQuadModeBit6, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommandMacronix /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + #if SPIFI_DEVICE_ALL || SPIFI_DEVICE_MX25L1635E + /* Add support for MX25L1635E */ + { + static const SPIFI_DEVICE_DATA_T pData = { + "MX25L1635E", + {{0xC2, 0x25, 0x15}, 0, {0}}, /* JEDEC ID, extCount, ext data */ + (SPIFI_CAP_DUAL_READ | SPIFI_CAP_QUAD_READ | SPIFI_CAP_QUAD_WRITE | SPIFI_CAP_NOBLOCK | + SPIFI_CAP_SUBBLKERASE), /* capabilities */ + 32, /* # of blocks */ + 0x10000, /* block size */ + 512, /* # of sub-blocks */ + 0x1000, /* sub-block size */ + 256, /* page size */ + MAX_SINGLE_READ, /* max single read bytes */ + 80, /* max clock rate in MHz */ + 104, /* max read clock rate in MHz */ + 86, /* max high speed read clock rate in MHz */ + 104, /* max program clock rate in MHz */ + 104, /* max high speed program clock rate in MHz */ + FX_spifiDeviceDataInitDeinit, /* (Fx Id) use generic deviceInit / deInit */ + FX_spifiDeviceDataClearStatusNone, /* (Fx Id) no persistent status */ + FX_spifiDeviceDataGetStatusMX25L3235E, /* (Fx Id) getStatus function */ + FX_spifiDeviceDataSetStatusMX25L3235E, /* (Fx Id) setStatus function */ + FX_spifiDeviceDataSetOptsQuadModeBit6, /* (Fx Id) to set/clr options */ + FX_spifiDeviceInitReadCommand, /* (Fx Id) to get memoryMode Cmd */ + FX_spifiDeviceInitWriteCommandMacronix /* (Fx Id) to get program Cmd */ + }; + static SPIFI_DEV_NODE_T data; /* Create persistent node */ + + data.pDevData = &pData; /* save the data in the node */ + spifiDevRegister(&devFamily, &data); /* Register the new device */ + } + #endif + + /* finally return the family device structure */ + return &devFamily; +}