summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c')
-rw-r--r--FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c b/FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c
new file mode 100644
index 000000000..57e9d4b7c
--- /dev/null
+++ b/FreeRTOS/Demo/CORTEX_MPU_LPC54018_MCUXpresso/NXP_Code/drivers/fsl_emc.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_emc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.emc"
+#endif
+
+/*! @brief Define macros for EMC driver. */
+#define EMC_REFRESH_CLOCK_PARAM (16U)
+#define EMC_SDRAM_WAIT_CYCLES (2000U)
+#define EMC_DYNCTL_COLUMNBASE_OFFSET (0U)
+#define EMC_DYNCTL_COLUMNBASE_MASK (0x3U)
+#define EMC_DYNCTL_COLUMNPLUS_OFFSET (3U)
+#define EMC_DYNCTL_COLUMNPLUS_MASK (0x18U)
+#define EMC_DYNCTL_BUSWIDTH_MASK (0x80U)
+#define EMC_DYNCTL_BUSADDRMAP_MASK (0x20U)
+#define EMC_DYNCTL_DEVBANKS_BITS_MASK (0x1cU)
+#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_DIV_ROUND_UP(n, m) (((n) + (m)-1U) / (m))
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for EMC module.
+ *
+ * @param base EMC peripheral base address
+ */
+static uint32_t EMC_GetInstance(EMC_Type *base);
+
+/*!
+ * @brief Get the clock cycles of EMC clock.
+ * The function is used to calculate the multiple of the
+ * 16 EMCCLKs between the timer_Ns period.
+ *
+ * @param base EMC peripheral base address
+ * @param timer_Ns The timer/period in unit of nanosecond
+ * @param plus The plus added to the register settings to reach the calculated cycles.
+ * @return The calculated cycles.
+ */
+static uint32_t EMC_CalculateTimerCycles(EMC_Type *base, uint32_t timer_Ns, uint32_t plus);
+
+/*!
+ * @brief Get the shift value to shift the mode register content by.
+ *
+ * @param addrMap EMC address map for the dynamic memory configuration.
+ * It is the bit 14 ~ bit 7 of the EMC_DYNAMICCONFIG.
+ * @return The offset value to shift the mode register content by.
+ */
+static uint32_t EMC_ModeOffset(uint32_t addrMap);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to EMC clocks for each instance. */
+static const clock_ip_name_t s_EMCClock[FSL_FEATURE_SOC_EMC_COUNT] = EMC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if !(defined(FSL_FEATURE_EMC_HAS_NO_RESET) && FSL_FEATURE_EMC_HAS_NO_RESET)
+/*! @brief Pointers to EMC resets for each instance. */
+static const reset_ip_name_t s_emcResets[] = EMC_RSTS;
+#endif
+
+/*! @brief Pointers to EMC bases for each instance. */
+static const EMC_Type *const s_EMCBases[] = EMC_BASE_PTRS;
+
+/*! @brief Define the start address for each chip controlled by EMC. */
+static const uint32_t s_EMCDYCSBases[] = EMC_DYCS_ADDRESS;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t EMC_GetInstance(EMC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_EMCBases); instance++)
+ {
+ if (s_EMCBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_EMCBases));
+
+ return instance;
+}
+
+static uint32_t EMC_CalculateTimerCycles(EMC_Type *base, uint32_t timer_Ns, uint32_t plus)
+{
+ uint32_t cycles;
+
+ cycles = CLOCK_GetEmcClkFreq() / EMC_HZ_ONEMHZ * timer_Ns;
+ cycles = EMC_DIV_ROUND_UP(cycles, EMC_MILLISECS_ONESEC); /* Round up. */
+
+ /* Decrese according to the plus. */
+ if (cycles >= plus)
+ {
+ cycles = cycles - plus;
+ }
+ else
+ {
+ cycles = 0;
+ }
+
+ return cycles;
+}
+
+static uint32_t EMC_ModeOffset(uint32_t addrMap)
+{
+ uint8_t offset = 0;
+ uint32_t columbase = addrMap & EMC_DYNCTL_COLUMNBASE_MASK;
+
+ /* First calculate the column length. */
+ if (columbase == 2U)
+ {
+ offset = 8;
+ }
+ else
+ {
+ if (0U == columbase)
+ {
+ offset = 9;
+ }
+ else
+ {
+ offset = 8;
+ }
+
+ /* Add column length increase check. */
+ offset += (uint8_t)((addrMap & EMC_DYNCTL_COLUMNPLUS_MASK) >> EMC_DYNCTL_COLUMNPLUS_OFFSET);
+ }
+
+ /* Add Buswidth/16. */
+ if (0U != (addrMap & EMC_DYNCTL_BUSWIDTH_MASK))
+ {
+ offset += 2U;
+ }
+ else
+ {
+ offset += 1U;
+ }
+
+ /* Add bank select bit if the sdram address map mode is RBC(row-bank-column) mode. */
+ if (0U == (addrMap & EMC_DYNCTL_BUSADDRMAP_MASK))
+ {
+ if (0U == (addrMap & EMC_DYNCTL_DEVBANKS_BITS_MASK))
+ {
+ offset += 1U;
+ }
+ else
+ {
+ offset += 2U;
+ }
+ }
+
+ return offset;
+}
+
+/*!
+ * brief Initializes the basic for EMC.
+ * This function ungates the EMC clock, initializes the emc system configure
+ * and enable the EMC module. This function must be called in the first step to initialize
+ * the external memory.
+ *
+ * param base EMC peripheral base address.
+ * param config The EMC basic configuration.
+ */
+void EMC_Init(EMC_Type *base, emc_basic_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock((s_EMCClock[EMC_GetInstance(base)]));
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if !(defined(FSL_FEATURE_EMC_HAS_NO_RESET) && FSL_FEATURE_EMC_HAS_NO_RESET)
+ /* Reset the EMC module */
+ RESET_PeripheralReset(s_emcResets[EMC_GetInstance(base)]);
+#endif
+
+ /* Reset the EMC. */
+ SYSCON->PRESETCTRL[2] |= SYSCON_PRESETCTRL_EMC_RESET_MASK;
+ SYSCON->PRESETCTRL[2] &= ~SYSCON_PRESETCTRL_EMC_RESET_MASK;
+
+ /* Set the EMC sytem configure. */
+ SYSCON->EMCCLKDIV = SYSCON_EMCCLKDIV_DIV(config->emcClkDiv);
+
+ SYSCON->EMCSYSCTRL = SYSCON_EMCSYSCTRL_EMCFBCLKINSEL(config->fbClkSrc);
+
+ /* Set the endian mode. */
+ base->CONFIG = (uint32_t)config->endian;
+ /* Enable the EMC module with normal memory map mode and normal work mode. */
+ base->CONTROL = EMC_CONTROL_E_MASK;
+}
+
+/*!
+ * brief Initializes the dynamic memory controller.
+ * This function initializes the dynamic memory controller in external memory controller.
+ * This function must be called after EMC_Init and before accessing the external dynamic memory.
+ *
+ * param base EMC peripheral base address.
+ * param timing The timing and latency for dynamica memory controller setting. It shall
+ * be used for all dynamica memory chips, threfore the worst timing value for all
+ * used chips must be given.
+ * param configure The EMC dynamic memory controller chip independent configuration pointer.
+ * This configuration pointer is actually pointer to a configration array. the array number
+ * depends on the "totalChips".
+ * param totalChips The total dynamic memory chip numbers been used or the length of the
+ * "emc_dynamic_chip_config_t" type memory.
+ */
+void EMC_DynamicMemInit(EMC_Type *base,
+ emc_dynamic_timing_config_t *timing,
+ emc_dynamic_chip_config_t *config,
+ uint32_t totalChips)
+{
+ assert(NULL != config);
+ assert(NULL != timing);
+ assert(totalChips <= EMC_DYNAMIC_MEMDEV_NUM);
+
+ uint32_t count;
+ uint32_t casLatency;
+ uint32_t addr;
+ uint32_t offset;
+ uint32_t data;
+ emc_dynamic_chip_config_t *dynamicConfig = config;
+
+ /* Setting for dynamic memory controller chip independent configuration. */
+ for (count = 0; (count < totalChips); count++)
+ {
+ if (NULL == dynamicConfig)
+ {
+ break;
+ }
+ else
+ {
+ base->DYNAMIC[dynamicConfig->chipIndex].DYNAMICCONFIG =
+ EMC_DYNAMIC_DYNAMICCONFIG_MD(dynamicConfig->dynamicDevice) | EMC_ADDRMAP(dynamicConfig->devAddrMap);
+ /* Abstract CAS latency from the sdram mode reigster setting values. */
+ casLatency = ((uint32_t)dynamicConfig->sdramModeReg & EMC_SDRAM_MODE_CL_MASK) >> EMC_SDRAM_MODE_CL_SHIFT;
+ base->DYNAMIC[dynamicConfig->chipIndex].DYNAMICRASCAS =
+ EMC_DYNAMIC_DYNAMICRASCAS_RAS(dynamicConfig->rAS_Nclk) | EMC_DYNAMIC_DYNAMICRASCAS_CAS(casLatency);
+
+ dynamicConfig++;
+ }
+ }
+
+ /* Configure the Dynamic Memory controller timing/latency for all chips. */
+ base->DYNAMICREADCONFIG = EMC_DYNAMICREADCONFIG_RD(timing->readConfig);
+ base->DYNAMICRP = EMC_CalculateTimerCycles(base, timing->tRp_Ns, 1) & EMC_DYNAMICRP_TRP_MASK;
+ base->DYNAMICRAS = EMC_CalculateTimerCycles(base, timing->tRas_Ns, 1) & EMC_DYNAMICRAS_TRAS_MASK;
+ base->DYNAMICSREX = EMC_CalculateTimerCycles(base, timing->tSrex_Ns, 1) & EMC_DYNAMICSREX_TSREX_MASK;
+ base->DYNAMICAPR = EMC_CalculateTimerCycles(base, timing->tApr_Ns, 1) & EMC_DYNAMICAPR_TAPR_MASK;
+ base->DYNAMICDAL = EMC_CalculateTimerCycles(base, timing->tDal_Ns, 0) & EMC_DYNAMICDAL_TDAL_MASK;
+ base->DYNAMICWR = EMC_CalculateTimerCycles(base, timing->tWr_Ns, 1) & EMC_DYNAMICWR_TWR_MASK;
+ base->DYNAMICRC = EMC_CalculateTimerCycles(base, timing->tRc_Ns, 1) & EMC_DYNAMICRC_TRC_MASK;
+ base->DYNAMICRFC = EMC_CalculateTimerCycles(base, timing->tRfc_Ns, 1) & EMC_DYNAMICRFC_TRFC_MASK;
+ base->DYNAMICXSR = EMC_CalculateTimerCycles(base, timing->tXsr_Ns, 1) & EMC_DYNAMICXSR_TXSR_MASK;
+ base->DYNAMICRRD = EMC_CalculateTimerCycles(base, timing->tRrd_Ns, 1) & EMC_DYNAMICRRD_TRRD_MASK;
+ base->DYNAMICMRD = EMC_DYNAMICMRD_TMRD((timing->tMrd_Nclk > 0U) ? timing->tMrd_Nclk - 1UL : 0UL);
+
+ SDK_DelayAtLeastUs(EMC_SDRAM_NOP_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+ /* Step 2. issue nop command. */
+ base->DYNAMICCONTROL = 0x00000183;
+
+ SDK_DelayAtLeastUs(EMC_SDRAM_PRECHARGE_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+ /* Step 3. issue precharge all command. */
+ base->DYNAMICCONTROL = 0x00000103;
+
+ /* Step 4. issue two auto-refresh command. */
+ base->DYNAMICREFRESH = 2;
+ SDK_DelayAtLeastUs(EMC_SDRAM_AUTO_REFRESH_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+
+ base->DYNAMICREFRESH = EMC_CalculateTimerCycles(base, timing->refreshPeriod_Nanosec, 0) / EMC_REFRESH_CLOCK_PARAM;
+
+ /* Step 5. issue a mode command and set the mode value. */
+ base->DYNAMICCONTROL = 0x00000083;
+
+ /* Calculate the mode settings here and to reach the 8 auto-refresh time requirement. */
+ dynamicConfig = config;
+ for (count = 0; (count < totalChips); count++)
+ {
+ if (NULL == dynamicConfig)
+ {
+ break;
+ }
+ else
+ {
+ /* Get the shift value first. */
+ offset = EMC_ModeOffset(dynamicConfig->devAddrMap);
+ addr = (s_EMCDYCSBases[dynamicConfig->chipIndex] |
+ ((uint32_t)(dynamicConfig->sdramModeReg & ~EMC_SDRAM_BANKCS_BA_MASK) << offset));
+ /* Set the right mode setting value. */
+ data = *(volatile uint32_t *)addr;
+ data = data;
+ dynamicConfig++;
+ }
+ }
+
+ if (kEMC_Sdram != config->dynamicDevice)
+ {
+ /* Add extended mode register if the low-power sdram is used. */
+ base->DYNAMICCONTROL = 0x00000083;
+ /* Calculate the mode settings for extended mode register. */
+ dynamicConfig = config;
+ for (count = 0; (count < totalChips); count++)
+ {
+ if (NULL == dynamicConfig)
+ {
+ break;
+ }
+ else
+ {
+ /* Get the shift value first. */
+ offset = EMC_ModeOffset(dynamicConfig->devAddrMap);
+ addr = (s_EMCDYCSBases[dynamicConfig->chipIndex] |
+ (((uint32_t)(dynamicConfig->sdramExtModeReg & ~EMC_SDRAM_BANKCS_BA_MASK) |
+ EMC_SDRAM_BANKCS_BA1_MASK)
+ << offset));
+ /* Set the right mode setting value. */
+ data = *(volatile uint32_t *)addr;
+ data = data;
+ dynamicConfig++;
+ }
+ }
+ }
+
+ /* Step 6. issue normal operation command. */
+ base->DYNAMICCONTROL = 0x00000000; /* Issue NORMAL command */
+
+ /* The buffer shall be disabled when do the sdram initialization and
+ * enabled after the initialization during normal opeation.
+ */
+ dynamicConfig = config;
+ for (count = 0; (count < totalChips); count++)
+ {
+ if (NULL == dynamicConfig)
+ {
+ break;
+ }
+ else
+ {
+ base->DYNAMIC[dynamicConfig->chipIndex].DYNAMICCONFIG |= EMC_DYNAMIC_DYNAMICCONFIG_B_MASK;
+ dynamicConfig++;
+ }
+ }
+}
+
+/*!
+ * brief Initializes the static memory controller.
+ * This function initializes the static memory controller in external memory controller.
+ * This function must be called after EMC_Init and before accessing the external static memory.
+ *
+ * param base EMC peripheral base address.
+ * param extWait_Ns 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.
+ * param configure The EMC static memory controller chip independent configuration pointer.
+ * This configuration pointer is actually pointer to a configration array. the array number
+ * depends on the "totalChips".
+ * param totalChips The total static memory chip numbers been used or the length of the
+ * "emc_static_chip_config_t" type memory.
+ */
+void EMC_StaticMemInit(EMC_Type *base, uint32_t *extWait_Ns, emc_static_chip_config_t *config, uint32_t totalChips)
+{
+ assert(NULL != config);
+
+ uint32_t count;
+ emc_static_chip_config_t *staticConfig = config;
+
+ /* Initialize extended wait. */
+ if (NULL != extWait_Ns)
+ {
+ for (count = 0; (count < totalChips) && (staticConfig != NULL); count++)
+ {
+ assert(0U != (staticConfig->specailConfig & (uint32_t)kEMC_AsynchronosPageEnable));
+ }
+
+ base->STATICEXTENDEDWAIT = EMC_CalculateTimerCycles(base, *extWait_Ns, 1);
+ staticConfig++;
+ }
+
+ /* Initialize the static memory chip specific configure. */
+ staticConfig = config;
+ for (count = 0; (count < totalChips); count++)
+ {
+ if (NULL == staticConfig)
+ {
+ break;
+ }
+ else
+ {
+ base->STATIC[staticConfig->chipIndex].STATICCONFIG =
+ (staticConfig->specailConfig | (uint32_t)staticConfig->memWidth);
+ base->STATIC[staticConfig->chipIndex].STATICWAITWEN =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitWriteEn_Ns, 1);
+ base->STATIC[staticConfig->chipIndex].STATICWAITOEN =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitOutEn_Ns, 0);
+ base->STATIC[staticConfig->chipIndex].STATICWAITRD =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitReadNoPage_Ns, 1);
+ base->STATIC[staticConfig->chipIndex].STATICWAITPAGE =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitReadPage_Ns, 1);
+ base->STATIC[staticConfig->chipIndex].STATICWAITWR =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitWrite_Ns, 2);
+ base->STATIC[staticConfig->chipIndex].STATICWAITTURN =
+ EMC_CalculateTimerCycles(base, staticConfig->tWaitTurn_Ns, 1);
+
+ staticConfig++;
+ }
+ }
+}
+
+/*!
+ * brief Deinitializes the EMC module and gates the clock.
+ * This function gates the EMC controller clock. As a result, the EMC
+ * module doesn't work after calling this function.
+ *
+ * param base EMC peripheral base address.
+ */
+void EMC_Deinit(EMC_Type *base)
+{
+ /* Deinit the EMC. */
+ base->CONTROL &= ~EMC_CONTROL_E_MASK;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_EMCClock[EMC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}