From 38042f641ac81480c26fa6c921d07752da031647 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 21 Nov 2013 06:37:50 -0600 Subject: [PATCH] LPC-H3131: SDRAM support (untested) --- ChangeLog | 4 +- configs/olimex-lpc-h3131/src/Makefile | 4 + configs/olimex-lpc-h3131/src/lpc31_mmcsd.c | 2 +- configs/olimex-lpc-h3131/src/lpc31_sdram.c | 382 +++++++++++++++++++++ 4 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 configs/olimex-lpc-h3131/src/lpc31_sdram.c diff --git a/ChangeLog b/ChangeLog index 19b6214aaa..5860d25e14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6097,5 +6097,7 @@ fast as the Embedded Artists EA3131 at the same clocking. (2013-11-19). * arch/arm/src/arm/up_cache.S and cache.h: More cache management - functions. + functions (2013-11-20). + * configs/olimex-lpc-h3131/src/Makefile: Add SDRAM support. + Untested and probably needs some fine tuining (2013-11-21) diff --git a/configs/olimex-lpc-h3131/src/Makefile b/configs/olimex-lpc-h3131/src/Makefile index 01bc475726..379ca529f2 100644 --- a/configs/olimex-lpc-h3131/src/Makefile +++ b/configs/olimex-lpc-h3131/src/Makefile @@ -42,6 +42,10 @@ AOBJS = $(ASRCS:.S=$(OBJEXT)) CSRCS = lpc31_boot.c lpc31_clkinit.c +ifeq ($(CONFIG_LPC31_EXTDRAM),y) +CSRCS += lpc31_mem.c +endif + ifeq ($(CONFIG_ARCH_LEDS),y) CSRCS += lpc31_leds.c endif diff --git a/configs/olimex-lpc-h3131/src/lpc31_mmcsd.c b/configs/olimex-lpc-h3131/src/lpc31_mmcsd.c index 9608690f1f..241a8a4c15 100644 --- a/configs/olimex-lpc-h3131/src/lpc31_mmcsd.c +++ b/configs/olimex-lpc-h3131/src/lpc31_mmcsd.c @@ -95,7 +95,7 @@ int lpc31_mmcsd_initialize(int slot, int minor) } fvdbg("Successfully bound SDIO to the MMC/SD driver\n"); - + /* Then let's guess and say that there is a card in the slot. I need to check to * see if the LPC-H3131 board supports a GPIO to detect if there is a card in * the slot. diff --git a/configs/olimex-lpc-h3131/src/lpc31_sdram.c b/configs/olimex-lpc-h3131/src/lpc31_sdram.c new file mode 100644 index 0000000000..470571a681 --- /dev/null +++ b/configs/olimex-lpc-h3131/src/lpc31_sdram.c @@ -0,0 +1,382 @@ +/**************************************************************************** + * configs/ea3131/src/up_mem.c + * arch/arm/src/board/up_mem.c + * + * Copyright (C) 2009-2010,2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * - NXP UM10314 LPC3130/31 User manual Rev. 1.01 — 9 September 2009 + * - NXP lpc313x.cdl.drivers.zip example driver code + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "up_arch.h" + +#include "lpc31_syscreg.h" +#include "lpc31_cgudrvr.h" +#include "lpc31_mpmc.h" +#include "lpc_h3131.h" + +#ifdef CONFIG_LPC31_EXTDRAM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The MPMC delay based on trace lengths between SDRAM and the chip and on + * the delay strategy used for SDRAM. + */ + +/* Command, address, and data delay (DEL2) */ + +#define H3131_MPMC_DELAY (0x00 << SYSCREG_MPMC_DELAYMODES_DEL1_SHIFT) | \ + (0x20 << SYSCREG_MPMC_DELAYMODES_DEL2_SHIFT) | \ + (0x24 << SYSCREG_MPMC_DELAYMODES_DEL3_SHIFT); + + +/* Delay constants in nanosecondss for MT48LC32M16LF SDRAM on board */ +/* 90MHz SDRAM Clock */ + +#define H3131_SDRAM_TRP (20) /* ns */ +#define H3131_SDRAM_TRFC (80) /* ns */ +#define H3131_SDRAM_TRAS (48) /* ns */ +#define H3131_SDRAM_TREX (80) /* ns */ +#define H3131_SDRAM_TAPR 2 +#define H3131_SDRAM_TWR (15) /* ns */ +#define H3131_SDRAM_TRC (72) /* ns */ +#define H3131_SDRAM_TRRD (2) /* clocks */ +#define H3131_SDRAM_TMRD (2) /* clocks */ +#define H3131_SDRAM_TXSR (80) /* ns */ +#define H3131_SDRAM_TDAL (5) /* clocks */ + +#define H3131_SDRAM_REFRESH (15625) +#define H3131_SDRAM_OPERREFRESH (7812) + +#if 1 +/* Macro used to convert the above values (in nanoseconds) into units of + * the HCLK. + */ + +# define _NS2HCLKS(ns,hclk2) \ + (uint32_t)(((uint64_t)ns * (uint64_t)hclk2) / 1000000000ull) + +#else +/* At 90MHz, the the clock period is: */ + +# define SDRAM_PERIOD 11.11111 /* ns */ +# define _NS2HCLKS(ns,hclk2) \ + (((ns < SDRAM_PERIOD) ? 0 : (uint32_t)((float)ns / SDRAM_PERIOD)) + 1) + +#endif + +#define NS2HCLKS(ns,hclk2,mask) (_NS2HCLKS & mask) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc31_sdraminitialize + * + * Description: + * Configure SDRAM on the Olimex LPC-H3131 board + * + * Micron Initialization Sequence from their data sheet for the Micron + * MT48LC32M16A2 32M x 16 SDRAM chip: + * + * "SDRAMs must be powered up and initialized in a predefined manner. + * Operational procedures other than those specified may result in + * undefined operation. Once power is applied to VDD and VDDQ + * (simultaneously) and the clock is stable (stable clock is defined as + * a signal cycling within timing constraints specified for the clock + * pin), the SDRAM requires a 100µs delay prior to issuing any command + * other than a COMMAND INHIBIT or NOP. + * + * "Starting at some point during this 100µs period and continuing at least + * through the end of this period, COMMAND INHIBIT or NOP commands should + * be applied. Once the 100µs delay has been satisfied with at least one + * COMMAND INHIBIT or NOP command having been applied, a PRECHARGE command + * should be applied. All banks must then be precharged, thereby placing + * the device in the all banks idle state. + * + * "Once in the idle state, two AUTO REFRESH cycles must be performed. After + * the AUTO REFRESH cycles are complete, the SDRAM is ready for mode + * register programming. + * + * "Because the mode register will power up in an unknown state, it should + * be loaded prior to applying any operational command." + * + * The JEDEC recommendation for initializing SDRAM is: + * + * APPLY POWER (Vdd/Vddq equally, and CLK is stable) + * Wait 200uS + * PRECHARGE all + * 8 AUTO REFRESH COMMANDS + * LOAD MODE REGISTER + * SDRAM is ready for operation + * + * The Micron SDRAM parts will work fine with the JEDEC sequence, but also + * allow for a quicker init sequence of: + * + * APPLY POWER (Vdd/Vddq equally, and CLK is stable) + * Wait at least 100uS (during which time start applying and + * continue applying NOP or COMMAND INHIBIT) + * PRECHARGE all + * 2 AUTO REFRESH COMMANDS (min requirement, more than 2 is also ok) + * LOAD MODE REGISTER + * SDRAM is ready for operation + * + ****************************************************************************/ + +{ + uint32_t tmp; + uint32_t regval; + + /* These run-time calculations can be reduced dramatically if hclk is + * replaced with an apriori value. + */ + +#ifdef CONFIG_LPC31_SDRAMHCLK +# define HCLK CONFIG_LPC31_SDRAMHCLK +#else + uint32_t hclk = lpc31_clkfreq(CLKID_MPMCCFGCLK2, DOMAINID_SYS); +# define HCLK hclk +#endif + + /* Check RTL for divide by 2 possible. If so change then enable the following logic */ +#if 0 + uint32_t hclk2 = hclk; + + if (((getreg32(LPC31_MPMC_CONFIG) & MPMC_CONFIG_CLK)) != 0) + { + hclk2 >>= 1; + } +# define HCLK2 hclk2 +#else +# define HCLK2 hclk +#endif + up_udelay(100); + + /* Set command delay strategy */ + + putreg32(MPMC_DYNREADCONFIG_CMDDEL, LPC31_MPMC_DYNREADCONFIG); + + /* Configure device config register nSDCE0 for proper width SDRAM: + * Type: SDRAM, 512Mb (32Mx16), 4 banks, row length = 13, column length = 9 + * Buffer disabled, writes not protected. + */ + + putreg32((MPMC_DYNCONFIG0_MDSDRAM | MPMC_DYNCONFIG_HP16_32MX16), + LPC31_MPMC_DYNCONFIG0); + putreg32((MPMC_DYNRASCAS0_RAS2CLK | MPMC_DYNRASCAS0_CAS2CLK), + LPC31_MPMC_DYNRASCAS0); + + /* Min 20ns program 1 so that at least 2 HCLKs are used */ + + putreg32(NS2HCLKS(H3131_SDRAM_TRP, HCLK2, MPMC_DYNTRP_MASK), + LPC31_MPMC_DYNTRP); + putreg32(NS2HCLKS(H3131_SDRAM_TRAS, HCLK2, MPMC_DYNTRAS_MASK), + LPC31_MPMC_DYNTRAS); + putreg32(NS2HCLKS(H3131_SDRAM_TREX, HCLK2, MPMC_DYNTSREX_MASK), + LPC31_MPMC_DYNTSREX); + putreg32(H3131_SDRAM_TAPR, LPC31_MPMC_DYNTAPR); + putreg32(((H3131_SDRAM_TDAL + _NS2HCLKS(H3131_SDRAM_TRP, HCLK2)) MPMC_DYNTDAL_MASK), + LPC31_MPMC_DYNTDAL); + putreg32(NS2HCLKS(H3131_SDRAM_TWR, HCLK2, MPMC_DYNTWR_MASK), + LPC31_MPMC_DYNTWR); + putreg32(NS2HCLKS(H3131_SDRAM_TRC, HCLK2, MPMC_DYNTRC_MASK), + LPC31_MPMC_DYNTRC); + putreg32(NS2HCLKS(H3131_SDRAM_TRFC, HCLK2, MPMC_DYNTRFC_MASK), + LPC31_MPMC_DYNTRFC); + putreg32(NS2HCLKS(H3131_SDRAM_TXSR, HCLK2, MPMC_DYNTXSR_MASK), + LPC31_MPMC_DYNTXSR); + putreg32(H3131_SDRAM_TRRD, LPC31_MPMC_DYNTRRD); + putreg32(H3131_SDRAM_TMRD, LPC31_MPMC_DYNTMRD); + + /* JEDEC General SDRAM Initialization Sequence DELAY to allow power and + * clocks to stabilize ~100 us NOP + */ + + up_udelay(100); + + /* Issue continuous NOP commands */ + + putreg32((MPMC_DYNCONTROL_CE|MPMC_DYNCONTROL_CS|MPMC_DYNCONTROL_INOP), + LPC31_MPMC_DYNCONTROL); + + /* Load ~200us delay value to timer1 */ + + up_udelay(200); + + /* Issue a "pre-charge all" command */ + + putreg32((MPMC_DYNCONTROL_CE|MPMC_DYNCONTROL_CS|MPMC_DYNCONTROL_IPALL), + LPC31_MPMC_DYNCONTROL); + + /* Minimum refresh pulse interval (tRFC) for MT48LC32M16A2=80nsec, + * 100nsec provides more than adequate interval. + */ + + putreg32(NS2HCLKS(H3131_SDRAM_REFRESH, HCLK, MPMC_DYNREFRESH_TIMER_MASK), + LPC31_MPMC_DYNREFRESH); + + /* Load ~250us delay value to timer1 */ + + up_udelay(250); + + /* Recommended refresh interval for normal operation of the Micron + * MT48LC16LFFG = 7.8125usec (128KHz rate). ((HCLK / 128000) - 1) = + * refresh counter interval rate, (subtract one for safety margin). + */ + + putreg32(NS2HCLKS(H3131_SDRAM_OPERREFRESH, HCLK, MPMC_DYNREFRESH_TIMER_MASK), + LPC31_MPMC_DYNREFRESH); + + /* Select mode register update mode */ + + putreg32((MPMC_DYNCONTROL_CE|MPMC_DYNCONTROL_CS|MPMC_DYNCONTROL_IMODE), + LPC31_MPMC_DYNCONTROL); + + /* Program the SDRAM internal mode registers on bank nSDCE0 and reconfigure + * the SDRAM chips. Bus speeds up to 90MHz requires use of a CAS latency = 2. + * To get correct value on address bus CAS cycle, requires a shift by 13 for + * 16bit mode + */ + + tmp = getreg32(LPC31_EXTSDRAM0_VSECTION | (0x23 << 13)); + + putreg32((MPMC_DYNCONFIG0_MDSDRAM|MPMC_DYNCONFIG_HP16_32MX16), + LPC31_MPMC_DYNCONFIG0); + putreg32((MPMC_DYNRASCAS0_RAS2CLK|MPMC_DYNRASCAS0_CAS2CLK), + LPC31_MPMC_DYNRASCAS0); + + /* Select normal operating mode */ + + putreg32((MPMC_DYNCONTROL_CE|MPMC_DYNCONTROL_CS|MPMC_DYNCONTROL_INORMAL), + LPC31_MPMC_DYNCONTROL); + + /* Enable buffers */ + + regval = getreg32(LPC31_MPMC_DYNCONFIG0); + regval |= MPMC_DYNCONFIG0_B; + putreg32(regval, LPC31_MPMC_DYNCONFIG0); + + putreg32((MPMC_DYNCONTROL_INORMAL|MPMC_DYNCONTROL_CS), + LPC31_MPMC_DYNCONTROL); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc31_meminitialize + * + * Description: + * Initialize external memory resources (sram, sdram, nand, nor, etc.) + * + ****************************************************************************/ + +void lpc31_meminitialize(void) +{ + /* Configure the LCD pins in external bus interface (EBI/MPMC) memory mode. + * + * LCD_CSB -> MPMC_NSTCS_0 + * LCD_DB_1 -> MPMC_NSTCS_1 + * LCD_DB_0 -> MPMC_CLKOUT + * LCD_E_RD -> MPMC_CKE + * LCD_RS -> MPMC_NDYCS + * LCD_RW_WR -> MPMC_DQM_1 + * LCD_DB_2 -> EBI_A_2 + * LCD_DB_3 -> EBI_A_3 l + * LCD_DB_4 -> EBI_A_4 l + * LCD_DB_5 -> EBI_A_5 l + * LCD_DB_6 -> EBI_A_6 + * LCD_DB_7 -> EBI_A_7 + * LCD_DB_8 -> EBI_A_8 + * LCD_DB_9 -> EBI_A_9 + * LCD_DB_10 -> EBI_A_10 + * LCD_DB_11 -> EBI_A_11 + * LCD_DB_12 -> EBI_A_12 + * LCD_DB_13 -> EBI_A_13 + * LCD_DB_14 -> EBI_A_14 + * LCD_DB_15 -> EBI_A_15 + */ + + putreg32(SYSCREG_MUX_LCDEBISEL_EBIMPMC, LPC31_SYSCREG_MUX_LCDEBISEL); + + /* Enable EBI clock */ + + lpc31_enableclock(CLKID_EBICLK); + + /* Enable MPMC controller clocks */ + + lpc31_enableclock(CLKID_MPMCCFGCLK); + lpc31_enableclock(CLKID_MPMCCFGCLK2); + lpc31_enableclock(CLKID_MPMCCFGCLK3); + + /* Enable the external memory controller */ + + putreg32(MPMC_CONTROL_E, LPC31_MPMC_CONTROL); + + /* Force HCLK to MPMC_CLK to 1:1 ratio, little-endian mode */ + + putreg32(0, LPC31_MPMC_CONFIG); + + /* Set MPMC delay based on trace lengths between SDRAM and the chip + * and on the delay strategy used for SDRAM. + */ + + putreg32(H3131_MPMC_DELAY, LPC31_SYSCREG_MPMC_DELAYMODES); + + /* Configure Micron MT48LC32M16A2 SDRAM on the H3131 board */ + + lpc31_sdraminitialize(); +} +#endif /* CONFIG_LPC31_EXTDRAM */