arch/arm/src/lpc54xx: Bring in NXP support for external SDRAM.

This commit is contained in:
Gregory Nutt 2017-12-10 16:07:30 -06:00
parent 77728f49f1
commit dab97de4ea
10 changed files with 558 additions and 47 deletions

View File

@ -253,6 +253,6 @@ config LPC54_EMC_STATIC
config LPC54_EMC_DYNAMIC
bool "EMC dynamic memory support"
default n
default y
endmenu # LPC54xx Peripheral Selection

View File

@ -98,11 +98,11 @@ ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y)
CHIP_CSRCS += lpc54_idle.c
endif
ifneq ($(CONFIG_LPC54_GPIOIRQ),y)
ifeq ($(CONFIG_LPC54_GPIOIRQ),y)
CHIP_CSRCS += lpc54_gpioirq.c
endif
ifneq ($(CONFIG_LPC54_EMC),y)
ifeq ($(CONFIG_LPC54_EMC),y)
CHIP_CSRCS += lpc54_emc.c
endif

View File

@ -47,10 +47,11 @@
* Pre-processor Definitions
****************************************************************************************************/
#define LPC54_EMC_CS0 0
#define LPC54_EMC_CS1 1
#define LPC54_EMC_CS2 2
#define LPC54_EMC_CS3 3
#define LPC54_EMC_CS0 0
#define LPC54_EMC_CS1 1
#define LPC54_EMC_CS2 2
#define LPC54_EMC_CS3 3
#define LPC54_EMC_NCS 4
/* Register offsets *********************************************************************************/
@ -75,16 +76,16 @@
/* Per-chip select dynamic memory registers */
#define LPC54_EMC_DYNCS_OFFSET(n) (0x0100 + (n) << 5)
#define LPC54_EMC_DYNCS_OFFSET(n) (0x0100 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_DYNCONFIG_OFFSET 0x0000 /* Configuration information for CSn */
#define LPC54_EMC_DYNRASCAS_OFFSET 0x0004 /* RAS and CAS latencies for CSn */
#define LPC54_EMC_DYNCONFIGn_OFFSET(n) (0x0100 + (n) << 5)
#define LPC54_EMC_DYNRASCASn_OFFSET(n) (0x0104 + (n) << 5)
#define LPC54_EMC_DYNCONFIGn_OFFSET(n) (0x0100 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_DYNRASCASn_OFFSET(n) (0x0104 + ((uintptr_t)(n) << 5))
/* Per-chip select static memory registers */
#define LPC54_EMC_STATCS_OFFSET(n) (0x0200 + (n) << 5)
#define LPC54_EMC_STATCS_OFFSET(n) (0x0200 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATCONFIG_OFFSET 0x0000 /* Configuration for CSn */
#define LPC54_EMC_STATWAITWEN_OFFSET 0x0004 /* Delay to write enable */
#define LPC54_EMC_STATWAITOEN_OFFSET 0x0008 /* Delay to output enable */
@ -93,13 +94,13 @@
#define LPC54_EMC_STATWAITWR_OFFSET 0x0014 /* Delay from EMC_CS0 to a write access */
#define LPC54_EMC_STATWAITTURN_OFFSET 0x0018 /* Number of bus turnaround cycles */
#define LPC54_EMC_STATCONFIGn_OFFSET(n) (0x0200 + (n) << 5)
#define LPC54_EMC_STATWAITWENn_OFFSET(n) (0x0204 + (n) << 5)
#define LPC54_EMC_STATWAITOENn_OFFSET(n) (0x0208 + (n) << 5)
#define LPC54_EMC_STATWAITRDn_OFFSET(n) (0x020c + (n) << 5)
#define LPC54_EMC_STATWAITPAGEn_OFFSET(n) (0x0210 + (n) << 5)
#define LPC54_EMC_STATWAITWRn_OFFSET(n) (0x0214 + (n) << 5)
#define LPC54_EMC_STATWAITTURNn_OFFSET(n) (0x0218 + (n) << 5)
#define LPC54_EMC_STATCONFIGn_OFFSET(n) (0x0200 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITWENn_OFFSET(n) (0x0204 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITOENn_OFFSET(n) (0x0208 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITRDn_OFFSET(n) (0x020c + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITPAGEn_OFFSET(n) (0x0210 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITWRn_OFFSET(n) (0x0214 + ((uintptr_t)(n) << 5))
#define LPC54_EMC_STATWAITTURNn_OFFSET(n) (0x0218 + ((uintptr_t)(n) << 5))
/* Register addresses *******************************************************************************/
@ -163,8 +164,8 @@
#define EMC_DYNCONTROL_CE (1 << 0) /* Bit 0: Dynamic memory clock enable */
#define EMC_DYNCONTROL_CS (1 << 1) /* Bit 1: Dynamic memory clock control */
#define EMC_DYNCONTROL_SR (1 << 2) /* Bit 2: Self-refresh request, EMCSREFREQ */
#define EMC_DYNCONTROL_MMC (1 << 5) /* Bit 5 Memory clock control */
#define EMC_DYNCONTROL_I_SHIFT (7) /* Bit 7-8: SDRAM initialization */ */
#define EMC_DYNCONTROL_MMC (1 << 5) /* Bit 5: Memory clock control */
#define EMC_DYNCONTROL_I_SHIFT (7) /* Bit 7-8: SDRAM initialization */
#define EMC_DYNCONTROL_I_MASK (3 << EMC_DYNCONTROL_I_SHIFT)
# define EMC_DYNCONTROL_I_NORMAL (0 << EMC_DYNCONTROL_I_SHIFT) /* Issue SDRAM NORMAL operation command */
# define EMC_DYNCONTROL_I_MODE (1 << EMC_DYNCONTROL_I_SHIFT) /* Issue SDRAM MODE command */
@ -182,9 +183,10 @@
#define EMC_DYNREADCONFIG_SHIFT (0) /* Bits 0-1: Read data strategy */
#define EMC_DYNREADCONFIG_MASK (3 << EMC_DYNREADCONFIG_SHIFT)
# define EMC_DYNREADCONFIG(n) ((uint32_t)(n) << EMC_DYNREADCONFIG_SHIFT)
# define EMC_DYNREADCONFIG_PLUS0 (1 << EMC_DYNREADCONFIG_SHIFT) /* Using EMCCLKDELAY */
# define EMC_DYNREADCONFIG_PLUS1 (2 << EMC_DYNREADCONFIG_SHIFT) /* Plus one clock cycle using EMCCLKDELAY */
# define EMC_DYNREADCONFIG_PLUS2 (3 << EMC_DYNREADCONFIG_SHIFT) /* Plus two clock cycles using EMCCLKDELAY */
# define EMC_DYNREADCONFIG_PLUS1 (2 << EMC_DYNREADCONFIG_SHIFT) /* Plus one clock cycle using EMCCLKDELAY */
# define EMC_DYNREADCONFIG_PLUS2 (3 << EMC_DYNREADCONFIG_SHIFT) /* Plus two clock cycles using EMCCLKDELAY */
/* Precharge command period */
@ -214,7 +216,7 @@
#define EMC_DYNDAL_SHIFT (0) /* Bits 0-3: Data-in to active command */
#define EMC_DYNDAL_MASK (15 << EMC_DYNDAL_SHIFT)
# define EMC_DYNDAL(n) ((uint32_t)((n)-1) << EMC_DYNDAL_SHIFT)
# define EMC_DYNDAL(n) ((uint32_t)(n) << EMC_DYNDAL_SHIFT)
/* Write recovery time */
@ -263,6 +265,7 @@
#define EMC_DYNCONFIG_
#define EMC_DYNCONFIG_MD_SHIFT (3) /* Bits 3-4: Memory device */
#define EMC_DYNCONFIG_MD_MASK (3 << EMC_DYNCONFIG_MD_SHIFT)
# define EMC_DYNCONFIG_MD(n) ((uint32_t)(n) << EMC_DYNCONFIG_MD_SHIFT)
# define EMC_DYNCONFIG_MD_SDRAM (0 << EMC_DYNCONFIG_MD_SHIFT) /* SDRAM */
# define EMC_DYNCONFIG_MD_LPDRAM (1 << EMC_DYNCONFIG_MD_SHIFT) /* Low-power SDRAM */
#define EMC_DYNCONFIG_AM0_SHIFT (7) /* Bits 7-12: See Table 656 in User Manual */
@ -272,12 +275,16 @@
#define EMC_DYNCONFIG_B (1 << 19) /* Bit 19: Buffer enable */
#define EMC_DYNCONFIG_P (1 << 20) /* Bit 20: Write protect */
#define EMC_DYNCONFIG_ADDRMAP_SHIFT EMC_DYNCONFIG_AM0_SHIFT
#define EMC_DYNCONFIG_ADDRMAP_MASK (EMC_DYNCONFIG_AM0_MASK | EMC_DYNCONFIG_AM1)
# define EMC_DYNCONFIG_ADDRMAP(n) ((uint32_t)(n) << EMC_DYNCONFIG_ADDRMAP_SHIFT)
/* Dynamic Memory RAS and CAS Delay registers */
#define EMC_DYNRASCAS_RAS_SHIFT (0) /* Bits 0-1: RAS latency */
#define EMC_DYNRASCAS_RAS_MASK (3 << EMC_DYNRASCAS_RAS_SHIFT)
# define EMC_DYNRASCAS_RAS(n) ((uint32_t)(n) << EMC_DYNRASCAS_RAS_SHIFT)
#define EMC_DYNRASCAS_CAS_SHIFT (8) /* Bits 9-9: CAS latency */
#define EMC_DYNRASCAS_CAS_SHIFT (8) /* Bits 8-9: CAS latency */
#define EMC_DYNRASCAS_CAS_MASK (3 << EMC_DYNRASCAS_CAS_SHIFT)
# define EMC_DYNRASCAS_CAS(n) ((uint32_t)(n) << EMC_DYNRASCAS_CAS_SHIFT)

View File

@ -619,7 +619,7 @@
#define SYSCON_EMCCLKDIV_DIV_SHIFT (9) /* Bits 0-7: Clock divider value */
#define SYSCON_EMCCLKDIV_DIV_MASK (0xff <<SYSCON_EMCCLKDIV_DIV_SHIFT)
# define SYSCON_EMCCLKDIV_DIV(n) ((uint32)((n)-1) <<SYSCON_EMCCLKDIV_DIV_SHIFT)
# define SYSCON_EMCCLKDIV_DIV(n) ((uint32_t)((n)-1) <<SYSCON_EMCCLKDIV_DIV_SHIFT)
#define SYSCON_EMCCLKDIV_RESET (1 << 29) /* Bit 29: Resets the divider counter */
#define SYSCON_EMCCLKDIV_ HALT (1 << 30) /* Bit 30: Halts the divider counter */
#define SYSCON_EMCCLKDIV_REQFLAG (1 << 31) /* Bit 31: Divider status flag */

View File

@ -45,13 +45,174 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/clock.h>
#include "up_arch.h"
#include "chip/lpc54_syscon.h"
#include "chip/lpc54_emc.h"
#include "lpc54_emc.h"
#ifdef CONFIG_LPC54_EMC
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define EMC_SDRAM_MODE_CL_SHIFT (4)
#define EMC_SDRAM_MODE_CL_MASK (7 << EMC_SDRAM_MODE_CL_SHIFT)
#define EMC_DYNCTL_COLUMNBASE_SHIFT (0)
#define EMC_DYNCTL_COLUMNBASE_MASK (3 << EMC_DYNCTL_COLUMNBASE_SHIFT)
#define EMC_DYNCTL_COLUMNPLUS_SHIFT (3)
#define EMC_DYNCTL_COLUMNPLUS_MASK (3 << EMC_DYNCTL_COLUMNPLUS_SHIFT)
#define EMC_DYNCTL_BUSWIDTH_MASK (0x80)
#define EMC_DYNCTL_BUSADDRMAP_MASK (0x20)
#define EMC_DYNCTL_DEVBANKS_BITS_MASK (0x1c)
#define EMC_SDRAM_BANKCS_BA0_MASK (uint32_t)(0x2000)
#define EMC_SDRAM_BANKCS_BA1_MASK (uint32_t)(0x4000)
#define EMC_SDRAM_BANKCS_BA_MASK (EMC_SDRAM_BANKCS_BA0_MASK | EMC_SDRAM_BANKCS_BA1_MASK)
#define EMC_REFRESH_CLOCK_SCALE 16
#define EMC_SDRAM_WAIT_CYCLES 2000
#define MHZ_PER_HZ 1000000
/****************************************************************************
* Private Data
****************************************************************************/
static const uintptr_t g_dram_csbase[LPC54_EMC_NCS] =
{
LPC54_DRAMCS0_BASE, LPC54_DRAMCS1_BASE, LPC54_DRAMCS2_BASE,
LPC54_DRAMCS3_BASE
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: lpc54_emc_timercycles
*
* Description:
* Convert nanoseconds to EMC clock cycles and clip to the provided range.
*
* Input Parameters:
* nsec - Nanoseconds to be converted.
* lower - Lower valid limit
* upper - Upper valid limit
*
****************************************************************************/
static uint32_t lpc54_emc_timercycles(uint32_t nsec, uint32_t lower,
uint32_t upper)
{
uint32_t cycles;
cycles = BOARD_EMC_FREQUENCY / MHZ_PER_HZ * nsec;
return ((cycles + MSEC_PER_SEC - 1) / MSEC_PER_SEC);
/* Decrease according to the plus */
if (cycles < lower)
{
cycles = lower;
}
else if (cycles > upper)
{
cycles = upper;
}
return cycles;
}
/****************************************************************************
* Name: lpc54_emc_timercycles
*
* Description:
* Get the shift value to shift the mode register content by.
*
* Input Parameters:
* addrmap - EMC address map for the dynamic memory configuration. This is
* bit 14 ~ bit 7 of the EMC_DYNCONFIG.
*
* Returned Value:
* The offset value to shift the mode register content by.
*
****************************************************************************/
#ifdef CONFIG_LPC54_EMC_DYNAMIC
static uint32_t lpc54_emc_modeoffset(uint32_t addrmap)
{
uint8_t offset = 0;
uint32_t columbase = addrmap & EMC_DYNCTL_COLUMNBASE_MASK;
/* First calculate the column length. */
if (columbase == 0x10)
{
offset = 8;
}
else
{
if (!columbase)
{
offset = 9;
}
else
{
offset = 8;
}
/* Add column length increase check. */
if (((addrmap & EMC_DYNCTL_COLUMNPLUS_MASK) >> EMC_DYNCTL_COLUMNPLUS_SHIFT) == 1)
{
offset += 1;
}
else if (((addrmap & EMC_DYNCTL_COLUMNPLUS_MASK) >> EMC_DYNCTL_COLUMNPLUS_SHIFT) == 2)
{
offset += 2;
}
else
{
/* To avoid MISRA rule 14.10 error. */
}
}
/* Add Buswidth/16. */
if (addrmap & EMC_DYNCTL_BUSWIDTH_MASK)
{
offset += 2;
}
else
{
offset += 1;
}
/* Add bank select bit if the sdram address map mode is RBC(row-bank-column) mode. */
if (!(addrmap & EMC_DYNCTL_BUSADDRMAP_MASK))
{
if (!(addrmap & EMC_DYNCTL_DEVBANKS_BITS_MASK))
{
offset += 1;
}
else
{
offset += 2;
}
}
return offset;
}
#endif /* CONFIG_LPC54_EMC_DYNAMIC */
/****************************************************************************
* Public Functions
****************************************************************************/
@ -60,13 +221,15 @@
* Name: lpc54_emc_initialize
*
* Description:
* This function enables the EMC clock, initializes the emc system
* This function enables the EMC clock, initializes the emc system
* configuration, and enable the EMC module.
*
* Input Parameters:
* config - Describes the EMC configuration.
*
****************************************************************************/
void lpc54_emc_initialize(uintptr_t base,
FAR const struct emc_config_s *config)
void lpc54_emc_initialize(FAR const struct emc_config_s *config)
{
uint32_t regval;
@ -78,7 +241,7 @@ void lpc54_emc_initialize(uintptr_t base,
putreg32(SYSCON_PRESETCTRL2_EMC, LPC54_SYSCON_PRESETCTRLSET2);
putreg32(SYSCON_PRESETCTRL2_EMC, LPC54_SYSCON_PRESETCTRLCLR2);
/* Set the EMC sytem configure */
putreg32(SYSCON_EMCCLKDIV_DIV(config->clkdiv), LPC54_SYSCON_EMCCLKDIV);
@ -88,7 +251,7 @@ void lpc54_emc_initialize(uintptr_t base,
/* Set the endian mode */
regval = config->endian ? EMC_CONFIG_EM : 0;
regval = config->bigendian ? EMC_CONFIG_EM : 0;
putreg32(regval, LPC54_EMC_CONFIG);
/* Enable the EMC module with normal memory map mode and normal work mode. */
@ -96,4 +259,202 @@ void lpc54_emc_initialize(uintptr_t base,
putreg32(EMC_CONTROL_E, LPC54_EMC_CONTROL);
}
/****************************************************************************
* Name: lpc54_emc_sdram_initialize
*
* Description:
* This function initializes the dynamic memory controller in external
* memory controller. This function must be called after lpc54_emc_initialize
* and before accessing the external dynamic memory.
*
* Input Parameters:
* timing - The timing and latency for dynamica memory controller
* setting. It will be used for all dynamic memory chips,
* therefore the worst timing value for all used chips must be
* given.
* chconfig - The EMC dynamic memory controller chip-independent
* configuration array. The dimension of the array is given by
* nchips.
* nchips - The number of chips to configure and the dimension of the
* chconfig array.
*
****************************************************************************/
#ifdef CONFIG_LPC54_EMC_DYNAMIC
void lpc54_emc_sdram_initialize(FAR struct emc_dynamic_timing_config_s *timing,
FAR struct emc_dynamic_chip_config_s *chconfig,
unsigned int nchips)
{
FAR struct emc_dynamic_chip_config_s *config;
uintptr_t addr;
uint32_t regval;
uint32_t offset;
uint32_t data;
unsigned int i;
volatile unsigned int j;
/* Setting for dynamic memory controller chip independent configuration */
for (i = 0, config = chconfig;
i < nchips && config != NULL;
i++, config++)
{
uint8_t caslat;
regval = EMC_DYNCONFIG_MD(config->dyndev) |
EMC_DYNCONFIG_ADDRMAP(config->addrmap);
putreg32(regval, LPC54_EMC_DYNCONFIG(config->chndx));
/* Abstract CAS latency from the SDRAM mode reigster setting values */
caslat = (config->mode & EMC_SDRAM_MODE_CL_MASK) >> EMC_SDRAM_MODE_CL_SHIFT;
regval = EMC_DYNRASCAS_RAS(config->rasnclk) | EMC_DYNRASCAS_CAS(caslat);
putreg32(regval, LPC54_EMC_DYNRASCAS(config->chndx));
}
/* Configure the Dynamic Memory controller timing/latency for all chips. */
regval = EMC_DYNREADCONFIG(timing->rdconfig);
putreg32(regval, LPC54_EMC_DYNREADCONFIG);
regval = lpc54_emc_timercycles(timing->rp, 1, 16);
putreg32(EMC_DYNRP(regval), LPC54_EMC_DYNRP);
regval = lpc54_emc_timercycles(timing->ras, 1, 16);
putreg32(EMC_DYNRAS(regval), LPC54_EMC_DYNRAS);
regval = lpc54_emc_timercycles(timing->srex, 1, 16);
putreg32(EMC_DYNSREX(regval), LPC54_EMC_DYNSREX);
regval = lpc54_emc_timercycles(timing->apr, 1, 16);
putreg32(EMC_DYNAPR(regval), LPC54_EMC_DYNAPR);
regval = lpc54_emc_timercycles(timing->dal, 0, 15);
putreg32(EMC_DYNDAL(regval), LPC54_EMC_DYNDAL);
regval = lpc54_emc_timercycles(timing->wr, 1, 16);
putreg32(EMC_DYNWR(regval), LPC54_EMC_DYNWR);
regval = lpc54_emc_timercycles(timing->rc, 1, 32);
putreg32(EMC_DYNRC(regval), LPC54_EMC_DYNRC);
regval = lpc54_emc_timercycles(timing->rfc, 1, 32);
putreg32(EMC_DYNRFC(regval), LPC54_EMC_DYNRFC);
regval = lpc54_emc_timercycles(timing->xsr, 1, 32);
putreg32(EMC_DYNXSR(regval), LPC54_EMC_DYNXSR);
regval = lpc54_emc_timercycles(timing->rrd, 1, 16);
putreg32(EMC_DYNRRD(regval), LPC54_EMC_DYNRRD);
regval = EMC_DYNRRD(timing->mrd);
putreg32(regval, LPC54_EMC_DYNMRD);
/* Initialize the SDRAM.*/
for (j = 0; j < EMC_SDRAM_WAIT_CYCLES; j++)
{
}
/* Step 2. Issue NOP command. */
regval = EMC_DYNCONTROL_CE | EMC_DYNCONTROL_CS | EMC_DYNCONTROL_I_MODE;
putreg32(regval, LPC54_EMC_DYNCONTROL);
for (j = 0; j < EMC_SDRAM_WAIT_CYCLES; j++)
{
}
/* Step 3. Issue precharge all command. */
regval = EMC_DYNCONTROL_CE | EMC_DYNCONTROL_CS | EMC_DYNCONTROL_I_PALL;
putreg32(regval, LPC54_EMC_DYNCONTROL);
/* Step 4. Issue two auto-refresh command. */
putreg32(2 * EMC_REFRESH_CLOCK_SCALE, LPC54_EMC_DYNREFRESH);
for (i = 0; i < EMC_SDRAM_WAIT_CYCLES/2; i ++)
{
}
regval = lpc54_emc_timercycles(timing->refresh, 0,
EMC_REFRESH_CLOCK_SCALE * 2047);
putreg32(regval / EMC_REFRESH_CLOCK_SCALE, LPC54_EMC_DYNREFRESH);
/* Step 5. Issue a mode command and set the mode value. */
regval = EMC_DYNCONTROL_CE | EMC_DYNCONTROL_CS | EMC_DYNCONTROL_I_MODE;
putreg32(regval, LPC54_EMC_DYNCONTROL);
/* Calculate the mode settings here and to reach the 8 auto-refresh time
* requirement.
*/
for (i = 0, config = chconfig;
i < nchips && config != NULL;
i++, config++)
{
/* Get the shift value first. */
offset = lpc54_emc_modeoffset(config->addrmap);
addr = g_dram_csbase[config->chndx] |
((uint32_t)(config->mode & ~EMC_SDRAM_BANKCS_BA_MASK ) << offset);
/* Set the right mode setting value. */
data = *(volatile uint32_t *)addr;
data = data;
}
if (config->dyndev)
{
/* Add extended mode register if the low-power sdram is used. */
regval = EMC_DYNCONTROL_CE | EMC_DYNCONTROL_CS |
EMC_DYNCONTROL_I_MODE;
putreg32(regval, LPC54_EMC_DYNCONTROL);
/* Calculate the mode settings for extended mode register. */
for (i = 0, config = chconfig;
i < nchips && config != NULL;
i++, config++)
{
/* Get the shift value first. */
offset = lpc54_emc_modeoffset(config->addrmap);
addr = (g_dram_csbase[config->chndx] |
(((uint32_t)(config->extmode & ~EMC_SDRAM_BANKCS_BA_MASK) |
EMC_SDRAM_BANKCS_BA1_MASK) << offset));
/* Set the right mode setting value. */
data = *(volatile uint32_t *)addr;
data = data;
}
}
/* Step 6. Issue normal operation command. */
regval = EMC_DYNCONTROL_I_NORMAL;
putreg32(regval, LPC54_EMC_DYNCONTROL);
/* The buffer will be disabled when do the sdram initialization and
* enabled after the initialization during normal opeation.
*/
for (i = 0, config = chconfig;
i < nchips && config != NULL;
i++, config++)
{
uintptr_t regaddr = LPC54_EMC_DYNCONFIG(config->chndx);
regval = getreg32(regaddr);
regval |= EMC_DYNCONFIG_B;
putreg32(regval, regaddr);
}
}
#endif /* CONFIG_LPC54_EMC_DYNAMIC */
#endif /* CONFIG_LPC54_EMC */

View File

@ -47,6 +47,10 @@
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include "lpc54_config.h"
#ifdef CONFIG_LPC54_EMC
@ -57,7 +61,7 @@
/* EMC Feedback clock input source selection */
enum _emc_fbclk_src_e
enum emc_fbclksrc_e
{
EMC_INTLOOPBACK = 0, /* Use the internal loop back from EMC_CLK output */
EMC_FBCLLK /* Use the external EMC_FBCLK input */
@ -67,9 +71,70 @@ enum _emc_fbclk_src_e
struct emc_config_s
{
bool bigendian; /* True: Memory is big-endian */
uint8_t clksrc; /* The feedback clock source. */
uint8_t clkdiv; /* EMC_CLK = AHB_CLK / (emc_clkDiv + 1). */
bool bigendian; /* True: Memory is big-endian */
uint8_t clksrc; /* The feedback clock source. */
uint8_t clkdiv; /* EMC_CLK = AHB_CLK / (emc_clkDiv + 1). */
};
/* EMC dynamic read strategy. */
enum emc_dynamic_read_e
{
EMC_NODELAY = 0, /* No delay */
EMC_CMDDELAY, /* Command delayed strategy, using EMCCLKDELAY */
EMC_CMDDELAYPLUS1, /* Command delayed strategy pluse one clock cycle
* using EMCCLKDELAY */
EMC_CMDDELAYPLUS2, /* Command delayed strategy pulse two clock cycle
* using EMCCLKDELAY */
};
/* EMC dynamic timing/delay configure structure. */
struct emc_dynamic_timing_config_s
{
uint8_t rdconfig; /* Dynamic read strategy (see enum emc_dynamic_read_e) */
uint32_t refresh; /* The refresh period in units of nanoseconds */
uint32_t rp; /* Precharge command period in units of nanoseconds */
uint32_t ras; /* Active to precharge command period in units of
* nanoseconds */
uint32_t srex; /* Self-refresh exit time in units of nanoseconds */
uint32_t apr; /* Last data out to active command time in units of
* nanoseconds */
uint32_t dal; /* Data-in to active command in units of nanoseconds */
uint32_t wr; /* Write recovery time in unit of nanosecond */
uint32_t rc; /* Active to active command period in units of
* nanoseconds. */
uint32_t rfc; /* Auto-refresh period and auto-refresh to active
* command period in unit of nanosecond */
uint32_t xsr; /* Exit self-refresh to active command time in units
* of nanoseconds */
uint32_t rrd; /* Active bank A to active bank B latency in units of
* nanoseconds */
uint8_t mrd; /* Load mode register to active command time in units
* of EMCCLK cycles */
};
/* EMC dynamic memory device. */
enum emc_dynamic_device_e
{
EMC_SDRAM = 0, /* Dynamic memory device: SDRAM. */
EMC_LPSDRAM /* Dynamic memory device: Low-power SDRAM. */
};
/* EMC dynamic memory controller independent chip configuration structure */
struct emc_dynamic_chip_config_s
{
uint8_t chndx; /* Chip Index, range from 0 ~ EMC_DYNAMIC_MEMDEV_NUM - 1. */
uint8_t dyndev; /* All chips shall use the same device setting. mixed
* use are not supported. */
uint8_t rasnclk; /* Active to read/write delay tRCD. */
uint16_t mode; /* Sdram mode register setting. */
uint16_t extmode; /* Used for low-power sdram device. The extended mode
* register. */
uint8_t addrmap; /* Dynamic device address mapping, choose the address
* mapping for your specific device. */
};
/****************************************************************************
@ -80,13 +145,42 @@ struct emc_config_s
* Name: lpc54_emc_initialize
*
* Description:
* This function enables the EMC clock, initializes the emc system
* This function enables the EMC clock, initializes the emc system
* configuration, and enable the EMC module.
*
* Input Parameters:
* config - Describes the EMC configuration.
*
****************************************************************************/
void lpc54_emc_initialize(uintptr_t base,
FAR const struct emc_config_s *config);
void lpc54_emc_initialize(FAR const struct emc_config_s *config);
/****************************************************************************
* Name: lpc54_emc_sdram_initialize
*
* Description:
* This function initializes the dynamic memory controller in external
* memory controller. This function must be called after lpc54_emc_initialize
* and before accessing the external dynamic memory.
*
* Input Parameters:
* timing - The timing and latency for dynamica memory controller
* setting. It will be used for all dynamic memory chips,
* therefore the worst timing value for all used chips must be
* given.
* chconfig - The EMC dynamic memory controller chip-independent
* configuration array. The dimension of the array is given by
* nchips.
* nchips - The number of chips to configure and the dimension of the
* chconfig array.
*
****************************************************************************/
#ifdef CONFIG_LPC54_EMC_DYNAMIC
void lpc54_emc_sdram_initialize(FAR struct emc_dynamic_timing_config_s *timing,
FAR struct emc_dynamic_chip_config_s *chconfig,
unsigned int nchips);
#endif /* CONFIG_LPC54_EMC_DYNAMIC */
#endif /* CONFIG_LPC54_EMC */
#endif /* __ARCH_ARM_SRC_LPC54XX_LPC54_EMC_H */

View File

@ -178,6 +178,15 @@
#define BOARD_FLEXCOMM0_CLKSEL SYSCON_FCLKSEL_FRO12M
#define BOARD_FLEXCOMM0_FCLK LPC54_FRO_12MHZ
/* EMC */
#ifdef BOARD_220MHz
#define BOARD_EMC_CLKDIV 3 /* EMC Clock = CPU FREQ/3 */
#else /* if BOARD_180MHz */
#define BOARD_EMC_CLKDIV 2 /* EMC Clock = CPU FREQ/2 */
#endif
#define BOARD_EMC_FREQUENCY (BOARD_CPU_FREQUENCY / BOARD_EMC_CLKDIV)
/* LED definitions *********************************************************/
/* The LPCXpress-LPC54628 has three user LEDs: D9, D11, and D12. These
* LEDs are for application use. They are illuminated when the driving

View File

@ -13,6 +13,8 @@ CONFIG_FAT_LCNAMES=y
CONFIG_FAT_LFN=y
CONFIG_FS_FAT=y
CONFIG_FS_PROCFS=y
CONFIG_LPC54_EMC_DYNAMIC=y
CONFIG_LPC54_EMC=y
CONFIG_LPC54_USART0=y
CONFIG_MAX_TASKS=16
CONFIG_MAX_WDOGPARMS=2

View File

@ -46,4 +46,10 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y)
CSRCS += lpc54_appinit.c
endif
ifeq ($(CONFIG_LPC54_EMC),y)
ifeq ($(CONFIG_LPC54_EMC_DYNAMIC),y)
CSRCS += lpc54_sdram.c
endif
endif
include $(TOPDIR)/configs/Board.mk

View File

@ -44,7 +44,13 @@
#include <arch/board/board.h>
#ifdef CONFIG_LPC54_EMC
#if defined(CONFIG_LPC54_EMC) && defined(CONFIG_LPC54_EMC_DYNAMIC)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define EMC_CLOCK_PERIOD_NS (1000000000 / BOARD_EMC_FREQUENCY)
/****************************************************************************
* Private Data
@ -63,6 +69,37 @@ static const struct emc_config_s g_emc_config =
#endif
};
/* Dynamic memory timing configuration. */
static const struct emc_dynamic_timing_config_s g_emc_dynconfig =
{
.rdconfig = EMC_CMDDELAY;
.refresh = (64 * 1000000 / 4096) /* 4096 rows/ 64ms */;
.rp = 18;
.ras = 42;
.srex = 67;
.apr = 18;
.wr = EMC_CLOCK_PERIOD_NS + 6; /* one clk + 6ns */
.dal = EMC_CLOCK_PERIOD_NS + 24;
.rc = 60;
.rfc = 60;
.xsr = 67;
.rrd = 23;
.mrd = 2;
};
/* Dynamic memory chip specific configuration: Chip 0 - MTL48LC8M16A2B4-6A */
static onst struct emc_dynamic_chip_config_s g_emc_dynchipconfig;
{
.chndx = 0;
.dyndev = EMC_SDRAM;
.rasnclk = 2;
.mode = 0x23;
.extmode = 0; /* LPSDRAM only */
.addrmap = 0x09; /* 128Mbits (8M*16, 4banks, 12 rows, 9 columns)*/
};
/****************************************************************************
* Public Functions
****************************************************************************/
@ -77,18 +114,13 @@ static const struct emc_config_s g_emc_config =
void lpc54_sdram_initialize(void)
{
/* Dynamic memory timing configuration. */
#warning Missing logic
/* Dynamic memory chip specific configuration: Chip 0 - MTL48LC8M16A2B4-6A */
#warning Missing logic
/* EMC Basic configuration. */
lpc54_emc_initialize(EMC, &g_emc_config);
lpc54_emc_initialize(&g_emc_config);
/* EMC Dynamc memory configuration. */
#warning Missing logic
lpc54_emc_dram_initialize(&g_emc_dynconfig, &g_emc_dynchipconfig, 1);
}
#endif /* CONFIG_LPC54_EMC */
#endif /* CONFIG_LPC54_EMC && CONFIG_LPC54_EMC_DYNAMIC */