zephyr/soc/arm/nxp_imx/rt5xx/soc.c

351 lines
10 KiB
C

/*
* Copyright (c) 2022, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief System/hardware module for NXP RT5XX platform
*
* This module provides routines to initialize and support board-level
* hardware for the RT5XX platforms.
*/
#include <zephyr/init.h>
#include <soc.h>
#include "flash_clock_setup.h"
#include "fsl_power.h"
#include "fsl_clock.h"
#if CONFIG_USB_DC_NXP_LPCIP3511
#include "usb_phy.h"
#include "usb.h"
#endif
/* Board System oscillator settling time in us */
#define BOARD_SYSOSC_SETTLING_US 100U
/* Board xtal frequency in Hz */
#define BOARD_XTAL_SYS_CLK_HZ 24000000U
/* Core clock frequency: 198000000Hz */
#define CLOCK_INIT_CORE_CLOCK 198000000U
#define CTIMER_CLOCK_SOURCE(node_id) \
TO_CTIMER_CLOCK_SOURCE(DT_CLOCKS_CELL(node_id, name), DT_PROP(node_id, clk_source))
#define TO_CTIMER_CLOCK_SOURCE(inst, val) TO_CLOCK_ATTACH_ID(inst, val)
#define TO_CLOCK_ATTACH_ID(inst, val) CLKCTL1_TUPLE_MUXA(CT32BIT##inst##FCLKSEL_OFFSET, val)
#define CTIMER_CLOCK_SETUP(node_id) CLOCK_AttachClk(CTIMER_CLOCK_SOURCE(node_id));
const clock_sys_pll_config_t g_sysPllConfig_clock_init = {
/* OSC clock */
.sys_pll_src = kCLOCK_SysPllXtalIn,
/* Numerator of the SYSPLL0 fractional loop divider is 0 */
.numerator = 0,
/* Denominator of the SYSPLL0 fractional loop divider is 1 */
.denominator = 1,
/* Divide by 22 */
.sys_pll_mult = kCLOCK_SysPllMult22
};
const clock_audio_pll_config_t g_audioPllConfig_clock_init = {
/* OSC clock */
.audio_pll_src = kCLOCK_AudioPllXtalIn,
/* Numerator of the Audio PLL fractional loop divider is 0 */
.numerator = 5040,
/* Denominator of the Audio PLL fractional loop divider is 1 */
.denominator = 27000,
/* Divide by 22 */
.audio_pll_mult = kCLOCK_AudioPllMult22
};
const clock_frg_clk_config_t g_frg0Config_clock_init = {
.num = 0,
.sfg_clock_src = kCLOCK_FrgPllDiv,
.divider = 255U,
.mult = 0
};
const clock_frg_clk_config_t g_frg12Config_clock_init = {
.num = 12,
.sfg_clock_src = kCLOCK_FrgMainClk,
.divider = 255U,
.mult = 167
};
#if CONFIG_USB_DC_NXP_LPCIP3511
/* USB PHY condfiguration */
#define BOARD_USB_PHY_D_CAL (0x0CU)
#define BOARD_USB_PHY_TXCAL45DP (0x06U)
#define BOARD_USB_PHY_TXCAL45DM (0x06U)
#endif
/* System clock frequency. */
extern uint32_t SystemCoreClock;
#ifdef CONFIG_NXP_IMX_RT5XX_BOOT_HEADER
extern char z_main_stack[];
extern char _flash_used[];
extern void z_arm_reset(void);
extern void z_arm_nmi(void);
extern void z_arm_hard_fault(void);
extern void z_arm_mpu_fault(void);
extern void z_arm_bus_fault(void);
extern void z_arm_usage_fault(void);
extern void z_arm_secure_fault(void);
extern void z_arm_svc(void);
extern void z_arm_debug_monitor(void);
extern void z_arm_pendsv(void);
extern void sys_clock_isr(void);
extern void z_arm_exc_spurious(void);
__imx_boot_ivt_section void (* const image_vector_table[])(void) = {
(void (*)())(z_main_stack + CONFIG_MAIN_STACK_SIZE), /* 0x00 */
z_arm_reset, /* 0x04 */
z_arm_nmi, /* 0x08 */
z_arm_hard_fault, /* 0x0C */
z_arm_mpu_fault, /* 0x10 */
z_arm_bus_fault, /* 0x14 */
z_arm_usage_fault, /* 0x18 */
#if defined(CONFIG_ARM_SECURE_FIRMWARE)
z_arm_secure_fault, /* 0x1C */
#else
z_arm_exc_spurious,
#endif /* CONFIG_ARM_SECURE_FIRMWARE */
(void (*)())_flash_used, /* 0x20, imageLength. */
0, /* 0x24, imageType (Plain Image) */
0, /* 0x28, authBlockOffset/crcChecksum */
z_arm_svc, /* 0x2C */
z_arm_debug_monitor, /* 0x30 */
(void (*)())image_vector_table, /* 0x34, imageLoadAddress. */
z_arm_pendsv, /* 0x38 */
#if defined(CONFIG_SYS_CLOCK_EXISTS) && \
defined(CONFIG_CORTEX_M_SYSTICK_INSTALL_ISR)
sys_clock_isr, /* 0x3C */
#else
z_arm_exc_spurious,
#endif
};
#endif /* CONFIG_NXP_IMX_RT5XX_BOOT_HEADER */
#if CONFIG_USB_DC_NXP_LPCIP3511
static void usb_device_clock_init(void)
{
uint8_t usbClockDiv = 1;
uint32_t usbClockFreq;
usb_phy_config_struct_t phyConfig = {
BOARD_USB_PHY_D_CAL,
BOARD_USB_PHY_TXCAL45DP,
BOARD_USB_PHY_TXCAL45DM,
};
/* Make sure USDHC ram buffer and usb1 phy has power up */
POWER_DisablePD(kPDRUNCFG_APD_USBHS_SRAM);
POWER_DisablePD(kPDRUNCFG_PPD_USBHS_SRAM);
POWER_DisablePD(kPDRUNCFG_LP_HSPAD_FSPI0_VDET);
POWER_ApplyPD();
RESET_PeripheralReset(kUSBHS_PHY_RST_SHIFT_RSTn);
RESET_PeripheralReset(kUSBHS_DEVICE_RST_SHIFT_RSTn);
RESET_PeripheralReset(kUSBHS_HOST_RST_SHIFT_RSTn);
RESET_PeripheralReset(kUSBHS_SRAM_RST_SHIFT_RSTn);
/* enable usb ip clock */
CLOCK_EnableUsbHs0DeviceClock(kOSC_CLK_to_USB_CLK, usbClockDiv);
/* save usb ip clock freq*/
usbClockFreq = g_xtalFreq / usbClockDiv;
CLOCK_SetClkDiv(kCLOCK_DivPfc1Clk, 4);
/* enable usb ram clock */
CLOCK_EnableClock(kCLOCK_UsbhsSram);
/* enable USB PHY PLL clock, the phy bus clock (480MHz) source is same with USB IP */
CLOCK_EnableUsbHs0PhyPllClock(kOSC_CLK_to_USB_CLK, usbClockFreq);
/* USB PHY initialization */
USB_EhciPhyInit(kUSB_ControllerLpcIp3511Hs0, BOARD_XTAL_SYS_CLK_HZ, &phyConfig);
#if defined(FSL_FEATURE_USBHSD_USB_RAM) && (FSL_FEATURE_USBHSD_USB_RAM)
for (int i = 0; i < FSL_FEATURE_USBHSD_USB_RAM; i++) {
((uint8_t *)FSL_FEATURE_USBHSD_USB_RAM_BASE_ADDRESS)[i] = 0x00U;
}
#endif
/* The following code should run after phy initialization and should wait
* some microseconds to make sure utmi clock valid
*/
/* enable usb1 host clock */
CLOCK_EnableClock(kCLOCK_UsbhsHost);
/* Wait until host_needclk de-asserts */
while (SYSCTL0->USB0CLKSTAT & SYSCTL0_USB0CLKSTAT_HOST_NEED_CLKST_MASK) {
__ASM("nop");
}
/* According to reference mannual, device mode setting has to be set by access
* usb host register
*/
USBHSH->PORTMODE |= USBHSH_PORTMODE_DEV_ENABLE_MASK;
/* disable usb1 host clock */
CLOCK_DisableClock(kCLOCK_UsbhsHost);
}
#endif
void z_arm_platform_init(void)
{
/* This is provided by the SDK */
SystemInit();
}
void clock_init(void)
{
/* Configure LPOSC 1M */
/* Power on LPOSC (1MHz) */
POWER_DisablePD(kPDRUNCFG_PD_LPOSC);
/* Wait until LPOSC stable */
CLOCK_EnableLpOscClk();
/* Configure FRO clock source */
/* Power on FRO (192MHz or 96MHz) */
POWER_DisablePD(kPDRUNCFG_PD_FFRO);
/* FRO_DIV1 is always enabled and used as Main clock during PLL update. */
/* Enable all FRO outputs */
CLOCK_EnableFroClk(kCLOCK_FroAllOutEn);
/*
* Call function flexspi_clock_safe_config() to move FlexSPI clock to a stable
* clock source to avoid instruction/data fetch issue when updating PLL and Main
* clock if XIP(execute code on FLEXSPI memory).
*/
flexspi_clock_safe_config();
/* Let CPU run on FRO with divider 2 for safe switching. */
CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 2);
CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK);
/* Configure SYSOSC clock source. */
/* Power on SYSXTAL */
POWER_DisablePD(kPDRUNCFG_PD_SYSXTAL);
/* Updated XTAL oscillator settling time */
POWER_UpdateOscSettlingTime(BOARD_SYSOSC_SETTLING_US);
/* Enable system OSC */
CLOCK_EnableSysOscClk(true, true, BOARD_SYSOSC_SETTLING_US);
/* Sets external XTAL OSC freq */
CLOCK_SetXtalFreq(BOARD_XTAL_SYS_CLK_HZ);
/* Configure SysPLL0 clock source. */
CLOCK_InitSysPll(&g_sysPllConfig_clock_init);
/* Enable MAIN PLL clock */
CLOCK_InitSysPfd(kCLOCK_Pfd0, 24);
/* Enable AUX0 PLL clock */
CLOCK_InitSysPfd(kCLOCK_Pfd2, 24);
/* Configure Audio PLL clock source. */
CLOCK_InitAudioPll(&g_audioPllConfig_clock_init);
/* Enable Audio PLL clock */
CLOCK_InitAudioPfd(kCLOCK_Pfd0, 26);
/* Set MAINPLLCLKDIV divider to value 5 */
CLOCK_SetClkDiv(kCLOCK_DivMainPllClk, 5U);
/* Set SYSCPUAHBCLKDIV divider to value 2 */
CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 2U);
/* Setup FRG0 clock */
CLOCK_SetFRGClock(&g_frg0Config_clock_init);
/* Setup FRG12 clock */
CLOCK_SetFRGClock(&g_frg12Config_clock_init);
/* Set up clock selectors - Attach clocks to the peripheries. */
/* Switch MAIN_CLK to MAIN_PLL */
CLOCK_AttachClk(kMAIN_PLL_to_MAIN_CLK);
/* Switch SYSTICK_CLK to MAIN_CLK_DIV */
CLOCK_AttachClk(kMAIN_CLK_DIV_to_SYSTICK_CLK);
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm0), nxp_lpc_usart, okay)
/* Switch FLEXCOMM0 to FRG */
CLOCK_AttachClk(kFRG_to_FLEXCOMM0);
#endif
#if CONFIG_USB_DC_NXP_LPCIP3511
usb_device_clock_init();
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm4), nxp_lpc_i2c, okay)
/* Switch FLEXCOMM4 to FRO_DIV4 */
CLOCK_AttachClk(kFRO_DIV4_to_FLEXCOMM4);
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(hs_spi1), nxp_lpc_spi, okay)
CLOCK_AttachClk(kFRO_DIV4_to_FLEXCOMM16);
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm12), nxp_lpc_usart, okay)
/* Switch FLEXCOMM12 to FRG */
CLOCK_AttachClk(kFRG_to_FLEXCOMM12);
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pmic_i2c), nxp_lpc_i2c, okay)
CLOCK_AttachClk(kFRO_DIV4_to_FLEXCOMM15);
#endif
/* Switch CLKOUT to FRO_DIV2 */
CLOCK_AttachClk(kFRO_DIV2_to_CLKOUT);
DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP)
/* Set up dividers. */
/* Set AUDIOPLLCLKDIV divider to value 15 */
CLOCK_SetClkDiv(kCLOCK_DivAudioPllClk, 15U);
/* Set FRGPLLCLKDIV divider to value 11 */
CLOCK_SetClkDiv(kCLOCK_DivPLLFRGClk, 11U);
/* Set SYSTICKFCLKDIV divider to value 2 */
CLOCK_SetClkDiv(kCLOCK_DivSystickClk, 2U);
/* Set PFC0DIV divider to value 2 */
CLOCK_SetClkDiv(kCLOCK_DivPfc0Clk, 2U);
/* Set PFC1DIV divider to value 4 */
CLOCK_SetClkDiv(kCLOCK_DivPfc1Clk, 4U);
/* Set CLKOUTFCLKDIV divider to value 100 */
CLOCK_SetClkDiv(kCLOCK_DivClockOut, 100U);
/*
* Call function flexspi_setup_clock() to set user configured clock source/divider
* for FlexSPI.
*/
flexspi_setup_clock(FLEXSPI0, 0U, 2U);
/* Set SystemCoreClock variable. */
SystemCoreClock = CLOCK_INIT_CORE_CLOCK;
/* Set main clock to FRO as deep sleep clock by default. */
POWER_SetDeepSleepClock(kDeepSleepClk_Fro);
}
/**
*
* @brief Perform basic hardware initialization
*
* Initialize the interrupt controller device drivers.
* Also initialize the timer device driver, if required.
*
* @return 0
*/
static int nxp_rt500_init(const struct device *arg)
{
ARG_UNUSED(arg);
/* old interrupt lock level */
unsigned int oldLevel;
/* disable interrupts */
oldLevel = irq_lock();
/* Initialize clocks with tool generated code */
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(nxp_rt500_init, PRE_KERNEL_1, 0);