nuttx/arch/arm/src/lpc54xx/lpc54_emc.c
Alin Jerpelea 20ce2f274a arch: arm: lpc17xx_40xx: fix nxstyle errors
Fix nxstyle errors to pass CI

Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
2021-03-28 00:32:09 -05:00

559 lines
17 KiB
C

/****************************************************************************
* arch/arm/src/lpc54xx/lpc54_emc.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Parts of this file were adapted from sample code provided for the LPC54xx
* family from NXP which has a compatible BSD license.
*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright (c) 2016 - 2017 , NXP
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <nuttx/clock.h>
#include "arm_arch.h"
#include "hardware/lpc54_syscon.h"
#include "hardware/lpc54_emc.h"
#include "lpc54_config.h"
#include "lpc54_enableclk.h"
#include "lpc54_reset.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
****************************************************************************/
/****************************************************************************
* Name: lpc54_emc_initialize
*
* Description:
* 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(FAR const struct emc_config_s *config)
{
uint32_t regval;
/* Enable EMC clock */
lpc54_emc_enableclk();
/* Reset the EMC */
lpc54_reset_emc();
/* Set the EMC system configuration */
putreg32(SYSCON_EMCCLKDIV_DIV(config->clkdiv), LPC54_SYSCON_EMCCLKDIV);
regval = config->clksrc ? SYSCON_EMCSYSCTRL_FBCLKINSEL : 0;
putreg32(regval, LPC54_SYSCON_EMCSYSCTRL);
/* Set the endian mode */
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.
*/
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
* by configuration array. The dimension of the array is given
* 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 const struct emc_dynamic_timing_config_s *timing,
FAR const struct emc_dynamic_chip_config_s *chconfig,
unsigned int nchips)
{
FAR const 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;
DEBUGASSERT(timing != NULL && chconfig != NULL && nchips > 0);
/* 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 register 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 operation.
*/
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 */
/****************************************************************************
* Name: lpc54_emc_sram_initialize
*
* Description:
* This function initializes the static memory controller in external
* memory controller. This function must be called after
* lpc54_emc_initialize and before accessing the external dynamic memory.
*
* Input Parameters:
* extwait - The extended wait timeout or the read/write transfer time.
* This is common for all static memory chips and set with
* NULL if not required.
* statconfig - The EMC static memory controller chip independent
* configuration array. The dimension of the array is nchips.
* nchips - The total static memory chip numbers been used and the
* number of entries in the statconfig array.
*
****************************************************************************/
#ifdef CONFIG_LPC54_EMC_STATIC
void lpc54_emc_sram_initialize(FAR uint32_t *extwait,
FAR const struct emc_static_chip_config_s *statconfig,
uint32_t nchips)
{
FAR const struct emc_static_chip_config_s *config;
uint32_t regval;
unsigned int i;
/* Initialize extended wait. */
DEBUGASSERT(statconfig != NULL && nchips > 0);
if (extwait)
{
#ifdef CONFIG_DEBUG_ASSERTIONS
for (i = 0, config = statconfig;
i < nchips && config != NULL; i++,
config++)
{
DEBUGASSERT(config->specconfig & EMC_ASYNCPAGEENABLE);
}
#endif
regval = lpc54_emc_timercycles(*extwait, 1, 1024);
putreg32(EMC_STATEXTWAIT(regval), LPC54_EMC_STATEXTWAIT);
}
/* Initialize the static memory chip specific configure. */
for (i = 0, config = statconfig;
i < nchips && config != NULL; i++,
config++)
{
regval = config->specconfig | config->memwidth;
putreg32(regval, LPC54_EMC_STATCONFIG(config->chndx));
regval = lpc54_emc_timercycles(config->waitwriteen, 1, 16);
putreg32(EMC_STATWAITWEN(regval),
LPC54_EMC_STATWAITWEN(config->chndx));
regval = lpc54_emc_timercycles(config->waitouten, 0, 15);
putreg32(EMC_STATWAITOEN(regval),
LPC54_EMC_STATWAITOEN(config->chndx));
regval = lpc54_emc_timercycles(config->waitread, 1, 32);
putreg32(EMC_STATWAITRD(regval),
LPC54_EMC_STATWAITRD(config->chndx));
regval = lpc54_emc_timercycles(config->waitreadpage, 1, 32);
putreg32(EMC_STATWAITPAGE(regval),
LPC54_EMC_STATWAITPAGE(config->chndx));
regval = lpc54_emc_timercycles(config->waitwrite, 2, 33);
putreg32(EMC_STATWAITWR(regval),
LPC54_EMC_STATWAITWR(config->chndx));
regval = lpc54_emc_timercycles(config->waitturn, 1, 16);
putreg32(EMC_STATWAITTURN(regval),
LPC54_EMC_STATWAITTURN(config->chndx));
}
}
#endif /* CONFIG_LPC54_EMC_STATIC */
#endif /* CONFIG_LPC54_EMC */