7990f90915
follow the code style convention Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
347 lines
11 KiB
C
347 lines
11 KiB
C
/****************************************************************************
|
|
* boards/arm/lpc31xx/ea3131/src/lpc31_mem.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* References:
|
|
* - NXP UM10314 LPC3130/31 User manual Rev. 1.01 - 9 September 2009
|
|
* - NXP lpc313x.cdl.drivers.zip example driver code
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <arch/board/board.h>
|
|
|
|
#include "chip.h"
|
|
#include "arm_internal.h"
|
|
#include "lpc31_syscreg.h"
|
|
#include "lpc31_cgudrvr.h"
|
|
#include "lpc31_mpmc.h"
|
|
#include "ea3131.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.
|
|
*/
|
|
|
|
#define EA3131_MPMC_DELAY 0x824
|
|
|
|
/* Delay constants in nanosecondss for MT48LC32M16LF SDRAM on board */
|
|
|
|
#define EA3131_SDRAM_TRP (20)
|
|
#define EA3131_SDRAM_TRFC (66)
|
|
#define EA3131_SDRAM_TRAS (44)
|
|
#define EA3131_SDRAM_TREX (75)
|
|
#define EA3131_SDRAM_TARP 4
|
|
#define EA3131_SDRAM_TWR (75)
|
|
#define EA3131_SDRAM_TRC (66)
|
|
#define EA3131_SDRAM_TRRD (15)
|
|
#define EA3131_SDRAM_TMRD (20)
|
|
#define EA3131_SDRAM_TXSR (75)
|
|
#define EA3131_SDRAM_TDAL (50)
|
|
#define EA3131_SDRAM_REFRESH (100)
|
|
#define EA3131_SDRAM_OPERREFRESH (7812)
|
|
|
|
/* Macro used to convert the above values (in nanoseconds) into units of
|
|
* the HCLK.
|
|
*/
|
|
|
|
#define NS2HCLKS(ns, hclk2, mask) \
|
|
((uint32_t)(((uint64_t)ns *(uint64_t)hclk2) / 1000000000ull) & mask)
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: lpc31_sdraminitialize
|
|
*
|
|
* Description:
|
|
* Configure SDRAM on the EA3131 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
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void lpc31_sdraminitialize(void)
|
|
{
|
|
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 startergy */
|
|
|
|
putreg32(MPMC_DYNREADCONFIG_CMDDEL, LPC31_MPMC_DYNREADCONFIG);
|
|
|
|
/* Configure device config register nSDCE0 for proper width SDRAM */
|
|
|
|
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(EA3131_SDRAM_TRP, HCLK2, MPMC_DYNTRP_MASK),
|
|
LPC31_MPMC_DYNTRP);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TRAS, HCLK2, MPMC_DYNTRAS_MASK),
|
|
LPC31_MPMC_DYNTRAS);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TREX, HCLK2, MPMC_DYNTSREX_MASK),
|
|
LPC31_MPMC_DYNTSREX);
|
|
putreg32(EA3131_SDRAM_TARP,
|
|
LPC31_MPMC_DYNTAPR);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TDAL, HCLK2, MPMC_DYNTDAL_MASK),
|
|
LPC31_MPMC_DYNTDAL);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TWR, HCLK2, MPMC_DYNTWR_MASK),
|
|
LPC31_MPMC_DYNTWR);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TRC, HCLK2, MPMC_DYNTRC_MASK),
|
|
LPC31_MPMC_DYNTRC);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TRFC, HCLK2, MPMC_DYNTRFC_MASK),
|
|
LPC31_MPMC_DYNTRFC);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TXSR, HCLK2, MPMC_DYNTXSR_MASK),
|
|
LPC31_MPMC_DYNTXSR);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TRRD, HCLK2, MPMC_DYNTRRD_MASK),
|
|
LPC31_MPMC_DYNTRRD);
|
|
putreg32(NS2HCLKS(EA3131_SDRAM_TMRD, HCLK2, MPMC_DYNTMRD_MASK),
|
|
LPC31_MPMC_DYNTMRD);
|
|
up_udelay(100);
|
|
|
|
/* Issue continuous NOP commands */
|
|
|
|
putreg32((MPMC_DYNCONTROL_CE | MPMC_DYNCONTROL_CS |
|
|
MPMC_DYNCONTROL_INOP), LPC31_MPMC_DYNCONTROL);
|
|
|
|
/* Wait ~200us */
|
|
|
|
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(EA3131_SDRAM_REFRESH, HCLK, MPMC_DYNREFRESH_TIMER_MASK),
|
|
LPC31_MPMC_DYNREFRESH);
|
|
|
|
/* Wait ~250us */
|
|
|
|
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(EA3131_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
|
|
*/
|
|
|
|
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(EA3131_MPMC_DELAY, LPC31_SYSCREG_MPMC_DELAYMODES);
|
|
|
|
/* Configure Micron MT48LC32M16A2 SDRAM on the EA3131 board */
|
|
|
|
lpc31_sdraminitialize();
|
|
}
|
|
#endif /* CONFIG_LPC31_EXTDRAM */
|