+// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* (C) Copyright 2009 Freescale Semiconductor, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <init.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
+#include <asm/bootm.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/dma.h>
#include <asm/mach-imx/hab.h>
#include <imx_thermal.h>
#include <mmc.h>
-enum ldo_reg {
- LDO_ARM,
- LDO_SOC,
- LDO_PU,
-};
-
struct scu_regs {
u32 ctrl;
u32 config;
};
#endif
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
.bank = 0,
.word = 6,
type = MXC_CPU_MX6D;
}
+ if (type == MXC_CPU_MX6ULL) {
+ if (readl(SRC_BASE_ADDR + 0x1c) & (1 << 6))
+ type = MXC_CPU_MX6ULZ;
+ }
}
major = ((reg >> 8) & 0xff);
if ((major >= 1) &&
type = MXC_CPU_MX6DP;
}
reg &= 0xff; /* mx6 silicon revision */
+
+ /* For 6DQ, the value 0x00630005 is Silicon revision 1.3*/
+ if (((type == MXC_CPU_MX6Q) || (type == MXC_CPU_MX6D)) && (reg == 0x5))
+ reg = 0x3;
+
return (type << 12) | (reg + (0x10 * (major + 1)));
}
#define OCOTP_CFG3_SPEED_528MHZ 1
#define OCOTP_CFG3_SPEED_696MHZ 2
+/*
+ * For i.MX6ULL
+ */
+#define OCOTP_CFG3_SPEED_792MHZ 2
+#define OCOTP_CFG3_SPEED_900MHZ 3
+
u32 get_cpu_speed_grade_hz(void)
{
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
- if (is_mx6ul() || is_mx6ull()) {
+ if (is_mx6ul()) {
if (val == OCOTP_CFG3_SPEED_528MHZ)
return 528000000;
else if (val == OCOTP_CFG3_SPEED_696MHZ)
return 0;
}
+ if (is_mx6ull()) {
+ if (val == OCOTP_CFG3_SPEED_528MHZ)
+ return 528000000;
+ else if (val == OCOTP_CFG3_SPEED_792MHZ)
+ return 792000000;
+ else if (val == OCOTP_CFG3_SPEED_900MHZ)
+ return 900000000;
+ else
+ return 0;
+ }
+
switch (val) {
/* Valid for IMX6DQ */
case OCOTP_CFG3_SPEED_1P2GHZ:
* Possible values are from 0.725V to 1.450V in steps of
* 0.025V (25mV).
*/
-static int set_ldo_voltage(enum ldo_reg ldo, u32 mv)
+int set_ldo_voltage(enum ldo_reg ldo, u32 mv)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
u32 val, step, old, reg = readl(&anatop->reg_core);
u8 shift;
+ /* No LDO_SOC/PU/ARM */
+ if (is_mx6sll())
+ return 0;
+
if (mv < 725)
val = 0x00; /* Power gated off */
else if (mv > 1450)
reg = readl(&mxc_ccm->ccdr);
/* Clear MMDC channel mask */
- if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sl())
+ if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sl() || is_mx6sll())
reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK);
else
reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK | MXC_CCM_CCDR_MMDC_CH0_HS_MASK);
}
}
-#ifdef CONFIG_MX6SL
-static void set_preclk_from_osc(void)
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6QDL)
+static void noc_setup(void)
{
- struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- u32 reg;
-
- reg = readl(&mxc_ccm->cscmr1);
- reg |= MXC_CCM_CSCMR1_PER_CLK_SEL_MASK;
- writel(reg, &mxc_ccm->cscmr1);
+ enable_ipu_clock();
+
+ writel(0x80000201, 0xbb0608);
+ /* Bypass IPU1 QoS generator */
+ writel(0x00000002, 0x00bb048c);
+ /* Bypass IPU2 QoS generator */
+ writel(0x00000002, 0x00bb050c);
+ /* Bandwidth THR for of PRE0 */
+ writel(0x00000200, 0x00bb0690);
+ /* Bandwidth THR for of PRE1 */
+ writel(0x00000200, 0x00bb0710);
+ /* Bandwidth THR for of PRE2 */
+ writel(0x00000200, 0x00bb0790);
+ /* Bandwidth THR for of PRE3 */
+ writel(0x00000200, 0x00bb0810);
+ /* Saturation THR for of PRE0 */
+ writel(0x00000010, 0x00bb0694);
+ /* Saturation THR for of PRE1 */
+ writel(0x00000010, 0x00bb0714);
+ /* Saturation THR for of PRE2 */
+ writel(0x00000010, 0x00bb0794);
+ /* Saturation THR for of PRE */
+ writel(0x00000010, 0x00bb0814);
+
+ disable_ipu_clock();
}
#endif
int arch_cpu_init(void)
{
+ struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
init_aips();
/* Need to clear MMDC_CHx_MASK to make warm reset work. */
}
/* Set perclk to source from OSC 24MHz */
-#if defined(CONFIG_MX6SL)
- set_preclk_from_osc();
-#endif
+ if (is_mx6sl())
+ setbits_le32(&ccm->cscmr1, MXC_CCM_CSCMR1_PER_CLK_SEL_MASK);
+
+ imx_wdog_disable_powerdown(); /* Disable PDE bit of WMCR register */
- imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */
+ if (is_mx6sx())
+ setbits_le32(&ccm->cscdr1, MXC_CCM_CSCDR1_UART_CLK_SEL);
init_src();
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6QDL)
+ if (is_mx6dqp())
+ noc_setup();
+#endif
return 0;
}
int board_postclk_init(void)
{
+ /* NO LDO SOC on i.MX6SLL */
+ if (is_mx6sll())
+ return 0;
+
set_ldo_voltage(LDO_SOC, 1175); /* Set VDDSOC to 1.175V */
return 0;
}
-#if defined(CONFIG_FEC_MXC)
-void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
-{
- struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
- struct fuse_bank *bank = &ocotp->bank[4];
- struct fuse_bank4_regs *fuse =
- (struct fuse_bank4_regs *)bank->fuse_regs;
-
- if ((is_mx6sx() || is_mx6ul() || is_mx6ull()) && dev_id == 1) {
- u32 value = readl(&fuse->mac_addr2);
- mac[0] = value >> 24 ;
- mac[1] = value >> 16 ;
- mac[2] = value >> 8 ;
- mac[3] = value ;
-
- value = readl(&fuse->mac_addr1);
- mac[4] = value >> 24 ;
- mac[5] = value >> 16 ;
-
- } else {
- u32 value = readl(&fuse->mac_addr1);
- mac[0] = (value >> 8);
- mac[1] = value ;
-
- value = readl(&fuse->mac_addr0);
- mac[2] = value >> 24 ;
- mac[3] = value >> 16 ;
- mac[4] = value >> 8 ;
- mac[5] = value ;
- }
-
-}
-#endif
-
+#ifndef CONFIG_SPL_BUILD
/*
* cfg_val will be used for
* Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
{"esdhc4", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
{NULL, 0},
};
+#endif
void reset_misc(void)
{
-#ifdef CONFIG_VIDEO_MXS
+#ifndef CONFIG_SPL_BUILD
+#if defined(CONFIG_VIDEO_MXS) && !defined(CONFIG_DM_VIDEO)
lcdif_power_down();
#endif
+#endif
}
void s_init(void)
u32 mask528;
u32 reg, periph1, periph2;
- if (is_mx6sx() || is_mx6ul() || is_mx6ull())
+ if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sll())
return;
/* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs
}
#endif
-#ifdef CONFIG_IMX_BOOTAUX
-int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data)
-{
- struct src *src_reg;
- u32 stack, pc;
-
- if (!boot_private_data)
- return -EINVAL;
-
- stack = *(u32 *)boot_private_data;
- pc = *(u32 *)(boot_private_data + 4);
- /* Set the stack and pc to M4 bootROM */
- writel(stack, M4_BOOTROM_BASE_ADDR);
- writel(pc, M4_BOOTROM_BASE_ADDR + 4);
-
- /* Enable M4 */
- src_reg = (struct src *)SRC_BASE_ADDR;
- clrsetbits_le32(&src_reg->scr, SRC_SCR_M4C_NON_SCLR_RST_MASK,
- SRC_SCR_M4_ENABLE_MASK);
-
- return 0;
-}
-
-int arch_auxiliary_core_check_up(u32 core_id)
+/*
+ * gpr_init() function is common for boards using MX6S, MX6DL, MX6D,
+ * MX6Q and MX6QP processors
+ */
+void gpr_init(void)
{
- struct src *src_reg = (struct src *)SRC_BASE_ADDR;
- unsigned val;
+ struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
- val = readl(&src_reg->scr);
-
- if (val & SRC_SCR_M4C_NON_SCLR_RST_MASK)
- return 0; /* assert in reset */
+ /*
+ * If this function is used in a common MX6 spl implementation
+ * we have to ensure that it is only called for suitable cpu types,
+ * otherwise it breaks hardware parts like enet1, can1, can2, etc.
+ */
+ if (!is_mx6dqp() && !is_mx6dq() && !is_mx6sdl())
+ return;
- return 1;
+ /* enable AXI cache for VDOA/VPU/IPU */
+ writel(0xF00000CF, &iomux->gpr[4]);
+ if (is_mx6dqp()) {
+ /* set IPU AXI-id1 Qos=0x1 AXI-id0/2/3 Qos=0x7 */
+ writel(0x77177717, &iomux->gpr[6]);
+ writel(0x77177717, &iomux->gpr[7]);
+ } else {
+ /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
+ writel(0x007F007F, &iomux->gpr[6]);
+ writel(0x007F007F, &iomux->gpr[7]);
+ }
}
-#endif