Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2018, NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <init.h>
#include <soc.h>
#include <dt-bindings/rdc/imx_rdc.h>
#include <arch/arm/cortex_m/cmsis.h>
#include "wdog_imx.h"

/* Initialize Resource Domain Controller. */
static void SOC_RdcInit(void)
{
	/* Move M4 core to the configured RDC domain */
	RDC_SetDomainID(RDC, rdcMdaM4, M4_DOMAIN_ID, false);

	/* Set access to WDOG3 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapWdog3,
			RDC_DOMAIN_PERM(M4_DOMAIN_ID, RDC_DOMAIN_PERM_RW),
			false, false);

#ifdef CONFIG_UART_IMX_UART_1
	/* Set access to UART_1 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart1, DT_NXP_IMX_UART_UART_1_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_1 */
#ifdef CONFIG_UART_IMX_UART_2
	/* Set access to UART_2 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart2, DT_NXP_IMX_UART_UART_2_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_2 */
#ifdef CONFIG_UART_IMX_UART_3
	/* Set access to UART_3 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart3, DT_NXP_IMX_UART_UART_3_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_3 */
#ifdef CONFIG_UART_IMX_UART_4
	/* Set access to UART_4 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart4, DT_NXP_IMX_UART_UART_4_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_4 */
#ifdef CONFIG_UART_IMX_UART_5
	/* Set access to UART_5 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart5, DT_NXP_IMX_UART_UART_5_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_5 */
#ifdef CONFIG_UART_IMX_UART_6
	/* Set access to UART_6 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapUart6, DT_NXP_IMX_UART_UART_6_RDC, false, false);
#endif /* CONFIG_UART_IMX_UART_6 */
#ifdef CONFIG_GPIO_IMX_PORT_1
	/* Set access to GPIO_1 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio1, DT_NXP_IMX_GPIO_GPIO_1_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_1 */
#ifdef CONFIG_GPIO_IMX_PORT_2
	/* Set access to GPIO_2 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio2, DT_NXP_IMX_GPIO_GPIO_2_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_2 */
#ifdef CONFIG_GPIO_IMX_PORT_3
	/* Set access to GPIO_3 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio3, DT_NXP_IMX_GPIO_GPIO_3_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_3 */
#ifdef CONFIG_GPIO_IMX_PORT_4
	/* Set access to GPIO_4 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio4, DT_NXP_IMX_GPIO_GPIO_4_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_4 */
#ifdef CONFIG_GPIO_IMX_PORT_5
	/* Set access to GPIO_5 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio5, DT_NXP_IMX_GPIO_GPIO_5_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_5 */
#ifdef CONFIG_GPIO_IMX_PORT_6
	/* Set access to GPIO_6 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio6, DT_NXP_IMX_GPIO_GPIO_6_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_6 */
#ifdef CONFIG_GPIO_IMX_PORT_7
	/* Set access to GPIO_7 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapGpio7, DT_NXP_IMX_GPIO_GPIO_7_RDC, false, false);
#endif /* CONFIG_GPIO_IMX_PORT_7 */

#ifdef CONFIG_IPM_IMX
	/* Set access to MU B for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapMuB, DT_NXP_IMX_MU_MU_B_RDC, false, false);
#endif /* CONFIG_IPM_IMX */

#ifdef CONFIG_COUNTER_IMX_EPIT_1
	/* Set access to EPIT_1 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapEpit1, DT_NXP_IMX_EPIT_EPIT_1_RDC, false, false);
#endif /* CONFIG_COUNTER_IMX_EPIT_1 */
#ifdef CONFIG_COUNTER_IMX_EPIT_2
	/* Set access to EPIT_2 for M4 core */
	RDC_SetPdapAccess(RDC, rdcPdapEpit2, DT_NXP_IMX_EPIT_EPIT_2_RDC, false, false);
#endif /* CONFIG_COUNTER_IMX_EPIT_2 */
}

/* Initialize cache. */
static void SOC_CacheInit(void)
{
	/* Enable System Bus Cache */
	/* set command to invalidate all ways and write GO bit
	 * to initiate command
	 */
	LMEM_PSCCR = LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_INVW0_MASK;
	LMEM_PSCCR |= LMEM_PSCCR_GO_MASK;
	/* Wait until the command completes */
	while (LMEM_PSCCR & LMEM_PSCCR_GO_MASK)
		;
	/* Enable system bus cache, enable write buffer */
	LMEM_PSCCR = (LMEM_PSCCR_ENWRBUF_MASK | LMEM_PSCCR_ENCACHE_MASK);
	__ISB();

	/* Enable Code Bus Cache */
	/* set command to invalidate all ways and write GO bit
	 * to initiate command
	 */
	LMEM_PCCCR = LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK;
	LMEM_PCCCR |= LMEM_PCCCR_GO_MASK;
	/* Wait until the command completes */
	while (LMEM_PCCCR & LMEM_PCCCR_GO_MASK)
		;
	/* Enable code bus cache, enable write buffer */
	LMEM_PCCCR = (LMEM_PCCCR_ENWRBUF_MASK | LMEM_PCCCR_ENCACHE_MASK);
	__ISB();
	__DSB();
}

/* Initialize clock. */
static void SOC_ClockInit(void)
{
	/* OSC/PLL is already initialized by Cortex-A9 core */

	/* Enable IP bridge and IO mux clock */
	CCM_ControlGate(CCM, ccmCcgrGateIomuxIptClkIo, ccmClockNeededAll);
	CCM_ControlGate(CCM, ccmCcgrGateIpmux1Clk, ccmClockNeededAll);
	CCM_ControlGate(CCM, ccmCcgrGateIpmux2Clk, ccmClockNeededAll);
	CCM_ControlGate(CCM, ccmCcgrGateIpmux3Clk, ccmClockNeededAll);

#ifdef CONFIG_UART_IMX
	/* Set UART clock is derived from OSC clock (24M) */
	CCM_SetRootMux(CCM, ccmRootUartClkSel, ccmRootmuxUartClkOsc24m);

	/* Configure UART divider */
	CCM_SetRootDivider(CCM, ccmRootUartClkPodf, 0);

	/* Enable UART clock */
	CCM_ControlGate(CCM, ccmCcgrGateUartClk, ccmClockNeededAll);
	CCM_ControlGate(CCM, ccmCcgrGateUartSerialClk, ccmClockNeededAll);
#endif /* CONFIG_UART_IMX */

#ifdef CONFIG_COUNTER_IMX_EPIT
	/* Select EPIT clock is derived from OSC (24M) */
	CCM_SetRootMux(CCM, ccmRootPerclkClkSel, ccmRootmuxPerclkClkOsc24m);

	/* Configure EPIT divider */
	CCM_SetRootDivider(CCM, ccmRootPerclkPodf, 0);

	/* Enable EPIT clocks */
#ifdef CONFIG_COUNTER_IMX_EPIT_1
	CCM_ControlGate(CCM, ccmCcgrGateEpit1Clk, ccmClockNeededAll);
#endif /* CONFIG_COUNTER_IMX_EPIT_1 */
#ifdef CONFIG_COUNTER_IMX_EPIT_2
	CCM_ControlGate(CCM, ccmCcgrGateEpit2Clk, ccmClockNeededAll);
#endif /* CONFIG_COUNTER_IMX_EPIT_2 */
#endif /* CONFIG_COUNTER_IMX_EPIT */
}

/**
 *
 * @brief Perform basic hardware initialization
 *
 * Initialize the interrupt controller device drivers.
 * Also initialize the counter device driver, if required.
 *
 * @return 0
 */
static int mcimx6x_m4_init(struct device *arg)
{
	ARG_UNUSED(arg);

	unsigned int oldLevel; /* Old interrupt lock level */

	/* Disable interrupts */
	oldLevel = irq_lock();

	/* Configure RDC */
	SOC_RdcInit();

	/* Disable WDOG3 powerdown */
	WDOG_DisablePowerdown(WDOG3);

	/* Initialize Cache */
	SOC_CacheInit();

	/* Initialize clock */
	SOC_ClockInit();

	/*
	 * 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(mcimx6x_m4_init, PRE_KERNEL_1, 0);