zephyr/soc/arm/nxp_imx/rt/soc.c

302 lines
7.4 KiB
C
Raw Normal View History

/*
* Copyright (c) 2017,2018, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <device.h>
#include <init.h>
#include <soc.h>
#include <linker/sections.h>
#include <fsl_clock.h>
#include <arch/cpu.h>
headers: Refactor kernel and arch headers. This commit refactors kernel and arch headers to establish a boundary between private and public interface headers. The refactoring strategy used in this commit is detailed in the issue This commit introduces the following major changes: 1. Establish a clear boundary between private and public headers by removing "kernel/include" and "arch/*/include" from the global include paths. Ideally, only kernel/ and arch/*/ source files should reference the headers in these directories. If these headers must be used by a component, these include paths shall be manually added to the CMakeLists.txt file of the component. This is intended to discourage applications from including private kernel and arch headers either knowingly and unknowingly. - kernel/include/ (PRIVATE) This directory contains the private headers that provide private kernel definitions which should not be visible outside the kernel and arch source code. All public kernel definitions must be added to an appropriate header located under include/. - arch/*/include/ (PRIVATE) This directory contains the private headers that provide private architecture-specific definitions which should not be visible outside the arch and kernel source code. All public architecture- specific definitions must be added to an appropriate header located under include/arch/*/. - include/ AND include/sys/ (PUBLIC) This directory contains the public headers that provide public kernel definitions which can be referenced by both kernel and application code. - include/arch/*/ (PUBLIC) This directory contains the public headers that provide public architecture-specific definitions which can be referenced by both kernel and application code. 2. Split arch_interface.h into "kernel-to-arch interface" and "public arch interface" divisions. - kernel/include/kernel_arch_interface.h * provides private "kernel-to-arch interface" definition. * includes arch/*/include/kernel_arch_func.h to ensure that the interface function implementations are always available. * includes sys/arch_interface.h so that public arch interface definitions are automatically included when including this file. - arch/*/include/kernel_arch_func.h * provides architecture-specific "kernel-to-arch interface" implementation. * only the functions that will be used in kernel and arch source files are defined here. - include/sys/arch_interface.h * provides "public arch interface" definition. * includes include/arch/arch_inlines.h to ensure that the architecture-specific public inline interface function implementations are always available. - include/arch/arch_inlines.h * includes architecture-specific arch_inlines.h in include/arch/*/arch_inline.h. - include/arch/*/arch_inline.h * provides architecture-specific "public arch interface" inline function implementation. * supersedes include/sys/arch_inline.h. 3. Refactor kernel and the existing architecture implementations. - Remove circular dependency of kernel and arch headers. The following general rules should be observed: * Never include any private headers from public headers * Never include kernel_internal.h in kernel_arch_data.h * Always include kernel_arch_data.h from kernel_arch_func.h * Never include kernel.h from kernel_struct.h either directly or indirectly. Only add the kernel structures that must be referenced from public arch headers in this file. - Relocate syscall_handler.h to include/ so it can be used in the public code. This is necessary because many user-mode public codes reference the functions defined in this header. - Relocate kernel_arch_thread.h to include/arch/*/thread.h. This is necessary to provide architecture-specific thread definition for 'struct k_thread' in kernel.h. - Remove any private header dependencies from public headers using the following methods: * If dependency is not required, simply omit * If dependency is required, - Relocate a portion of the required dependencies from the private header to an appropriate public header OR - Relocate the required private header to make it public. This commit supersedes #20047, addresses #19666, and fixes #3056. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
2019-10-25 00:08:21 +09:00
#include <arch/arm/cortex_m/cmsis.h>
#include <fsl_flexspi_nor_boot.h>
#if CONFIG_USB_DC_NXP_EHCI
#include "usb_phy.h"
#include "usb_dc_mcux.h"
#endif
#ifdef CONFIG_INIT_ARM_PLL
/* ARM PLL configuration for RUN mode */
const clock_arm_pll_config_t armPllConfig = {
.loopDivider = 100U
};
#endif
#ifdef CONFIG_INIT_SYS_PLL
/* SYS PLL configuration for RUN mode */
const clock_sys_pll_config_t sysPllConfig = {
.loopDivider = 1U
};
#endif
#ifdef CONFIG_INIT_USB1_PLL
/* USB1 PLL configuration for RUN mode */
const clock_usb_pll_config_t usb1PllConfig = {
.loopDivider = 0U
};
#endif
#if CONFIG_USB_DC_NXP_EHCI
/* USB PHY condfiguration */
#define BOARD_USB_PHY_D_CAL (0x0CU)
#define BOARD_USB_PHY_TXCAL45DP (0x06U)
#define BOARD_USB_PHY_TXCAL45DM (0x06U)
#endif
#ifdef CONFIG_INIT_ENET_PLL
/* ENET PLL configuration for RUN mode */
const clock_enet_pll_config_t ethPllConfig = {
#if defined(CONFIG_SOC_MIMXRT1021) || defined(CONFIG_SOC_MIMXRT1015)
.enableClkOutput500M = true,
#endif
#ifdef CONFIG_ETH_MCUX
.enableClkOutput = true,
#endif
.enableClkOutput25M = false,
.loopDivider = 1,
};
#endif
#if CONFIG_USB_DC_NXP_EHCI
usb_phy_config_struct_t usbPhyConfig = {
BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM,
};
#endif
#ifdef CONFIG_INIT_VIDEO_PLL
const clock_video_pll_config_t videoPllConfig = {
.loopDivider = 31,
.postDivider = 8,
.numerator = 0,
.denominator = 0,
};
#endif
#ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER
const __imx_boot_data_section BOOT_DATA_T boot_data = {
.start = CONFIG_FLASH_BASE_ADDRESS,
.size = CONFIG_FLASH_SIZE,
.plugin = PLUGIN_FLAG,
.placeholder = 0xFFFFFFFF,
};
const __imx_boot_ivt_section ivt image_vector_table = {
.hdr = IVT_HEADER,
.entry = CONFIG_FLASH_BASE_ADDRESS + CONFIG_TEXT_SECTION_OFFSET,
.reserved1 = IVT_RSVD,
#ifdef CONFIG_DEVICE_CONFIGURATION_DATA
.dcd = (uint32_t) dcd_data,
#else
.dcd = (uint32_t) NULL,
#endif
.boot_data = (uint32_t) &boot_data,
.self = (uint32_t) &image_vector_table,
.csf = (uint32_t)CSF_ADDRESS,
.reserved2 = IVT_RSVD,
};
#endif
/**
*
* @brief Initialize the system clock
*
* @return N/A
*
*/
static ALWAYS_INLINE void clock_init(void)
{
/* Boot ROM did initialize the XTAL, here we only sets external XTAL
* OSC freq
*/
CLOCK_SetXtalFreq(24000000U);
CLOCK_SetRtcXtalFreq(32768U);
/* Set PERIPH_CLK2 MUX to OSC */
CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 0x1);
/* Set PERIPH_CLK MUX to PERIPH_CLK2 */
CLOCK_SetMux(kCLOCK_PeriphMux, 0x1);
/* Setting the VDD_SOC to 1.5V. It is necessary to config AHB to 600Mhz
*/
DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(0x12);
/* Waiting for DCDC_STS_DC_OK bit is asserted */
while (DCDC_REG0_STS_DC_OK_MASK !=
(DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0)) {
;
}
#ifdef CONFIG_INIT_ARM_PLL
CLOCK_InitArmPll(&armPllConfig); /* Configure ARM PLL to 1200M */
#endif
#ifdef CONFIG_INIT_SYS_PLL
CLOCK_InitSysPll(&sysPllConfig); /* Configure SYS PLL to 528M */
#endif
#ifdef CONFIG_INIT_USB1_PLL
CLOCK_InitUsb1Pll(&usb1PllConfig); /* Configure USB1 PLL to 480M */
#endif
#ifdef CONFIG_INIT_ENET_PLL
CLOCK_InitEnetPll(&ethPllConfig);
#endif
#ifdef CONFIG_INIT_VIDEO_PLL
CLOCK_InitVideoPll(&videoPllConfig);
#endif
CLOCK_SetDiv(kCLOCK_ArmDiv, CONFIG_ARM_DIV); /* Set ARM PODF */
CLOCK_SetDiv(kCLOCK_AhbDiv, CONFIG_AHB_DIV); /* Set AHB PODF */
CLOCK_SetDiv(kCLOCK_IpgDiv, CONFIG_IPG_DIV); /* Set IPG PODF */
/* Set PRE_PERIPH_CLK to PLL1, 1200M */
CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x3);
/* Set PERIPH_CLK MUX to PRE_PERIPH_CLK */
CLOCK_SetMux(kCLOCK_PeriphMux, 0x0);
#ifdef CONFIG_UART_MCUX_LPUART
/* Configure UART divider to default */
CLOCK_SetMux(kCLOCK_UartMux, 0); /* Set UART source to PLL3 80M */
CLOCK_SetDiv(kCLOCK_UartDiv, 0); /* Set UART divider to 1 */
#endif
#ifdef CONFIG_I2C_MCUX_LPI2C
CLOCK_SetMux(kCLOCK_Lpi2cMux, 0); /* Set I2C source as USB1 PLL 480M */
CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 5); /* Set I2C divider to 6 */
#endif
#ifdef CONFIG_SPI_MCUX_LPSPI
CLOCK_SetMux(kCLOCK_LpspiMux, 1); /* Set SPI source to USB1 PFD0 720M */
CLOCK_SetDiv(kCLOCK_LpspiDiv, 7); /* Set SPI divider to 8 */
#endif
#ifdef CONFIG_DISPLAY_MCUX_ELCDIF
CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);
CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 4);
CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
#endif
#if CONFIG_USB_DC_NXP_EHCI
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M,
DT_INST_0_NXP_KINETIS_USBD_CLOCKS_CLOCK_FREQUENCY);
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M,
DT_INST_0_NXP_KINETIS_USBD_CLOCKS_CLOCK_FREQUENCY);
USB_EhciPhyInit(kUSB_ControllerEhci0, CPU_XTAL_CLK_HZ, &usbPhyConfig);
#endif
#if defined(CONFIG_DISK_ACCESS_USDHC1) || \
defined(CONFIG_DISK_ACCESS_USDHC2)
CLOCK_InitSysPfd(kCLOCK_Pfd0, 0x12U);
/* Configure USDHC clock source and divider */
#ifdef CONFIG_DISK_ACCESS_USDHC1
CLOCK_SetDiv(kCLOCK_Usdhc1Div, 0U);
CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U);
CLOCK_EnableClock(kCLOCK_Usdhc1);
#endif
#ifdef CONFIG_DISK_ACCESS_USDHC2
CLOCK_SetDiv(kCLOCK_Usdhc2Div, 0U);
CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1U);
CLOCK_EnableClock(kCLOCK_Usdhc2);
#endif
#endif
#ifdef CONFIG_VIDEO_MCUX_CSI
CLOCK_EnableClock(kCLOCK_Csi); /* Disable CSI clock gate */
CLOCK_SetDiv(kCLOCK_CsiDiv, 0); /* Set CSI divider to 1 */
CLOCK_SetMux(kCLOCK_CsiMux, 0); /* Set CSI source to OSC 24M */
#endif
/* Keep the system clock running so SYSTICK can wake up the system from
* wfi.
*/
CLOCK_SetMode(kCLOCK_ModeRun);
}
#if defined(CONFIG_DISK_ACCESS_USDHC1) || \
defined(CONFIG_DISK_ACCESS_USDHC2)
/* Usdhc driver needs to re-configure pinmux
* Pinmux depends on board design.
* From the perspective of Usdhc driver,
* it can't access board specific function.
* So SoC provides this for board to register
* its usdhc pinmux and for usdhc to access
* pinmux.
*/
static usdhc_pin_cfg_cb g_usdhc_pin_cfg_cb;
void imxrt_usdhc_pinmux_cb_register(usdhc_pin_cfg_cb cb)
{
g_usdhc_pin_cfg_cb = cb;
}
void imxrt_usdhc_pinmux(u16_t nusdhc, bool init,
u32_t speed, u32_t strength)
{
if (g_usdhc_pin_cfg_cb)
g_usdhc_pin_cfg_cb(nusdhc, init,
speed, strength);
}
#endif
/**
*
* @brief Perform basic hardware initialization
*
* Initialize the interrupt controller device drivers.
* Also initialize the timer device driver, if required.
*
* @return 0
*/
static int imxrt_init(struct device *arg)
{
ARG_UNUSED(arg);
unsigned int oldLevel; /* old interrupt lock level */
/* disable interrupts */
oldLevel = irq_lock();
/* Watchdog disable */
if ((WDOG1->WCR & WDOG_WCR_WDE_MASK) != 0) {
WDOG1->WCR &= ~WDOG_WCR_WDE_MASK;
}
if ((WDOG2->WCR & WDOG_WCR_WDE_MASK) != 0) {
WDOG2->WCR &= ~WDOG_WCR_WDE_MASK;
}
RTWDOG->CNT = 0xD928C520U; /* 0xD928C520U is the update key */
RTWDOG->TOVAL = 0xFFFF;
RTWDOG->CS = (uint32_t) ((RTWDOG->CS) & ~RTWDOG_CS_EN_MASK)
| RTWDOG_CS_UPDATE_MASK;
/* Disable Systick which might be enabled by bootrom */
if ((SysTick->CTRL & SysTick_CTRL_ENABLE_Msk) != 0) {
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
SCB_EnableICache();
if ((SCB->CCR & SCB_CCR_DC_Msk) == 0) {
SCB_EnableDCache();
}
/* Initialize system clock */
clock_init();
/*
* install default handler that simply resets the CPU
* if configured in the kernel, NOP otherwise
*/
NMI_INIT();
/* restore interrupt state */
irq_unlock(oldLevel);
return 0;
}
SYS_INIT(imxrt_init, PRE_KERNEL_1, 0);