[U-Boot] [PATCH 6/7] ARM: exynos: SPL support for exynos 4412

Simon Shields simon at lineageos.org
Wed Sep 12 08:28:32 UTC 2018


This patch adds support for using u-boot's SPL in place of a proprietary
BL2 on exynos 4412 boards. This has been verified to work on both
exynos4412 boards (i9300 and i9305), and exynos4412-prime boards (n7100
and n7105), with one or two gigabytes of RAM. Using u-boot as SPL
requires an appropriate FWBL1 that does not verify the signature of BL2.

The majority of the configuration logic comes from the vendor u-boot drop,
while some was reverse-engineered from a proprietary bootloader.

Note that this patch does not initialise the exynos4412-prime clocks as
they're initialised by the proprietary bootloader - instead, they're
initialised to the same state as normal exynos4412 clocks.

Signed-off-by: Simon Shields <simon at lineageos.org>
---
 arch/arm/mach-exynos/Kconfig                 |   6 +
 arch/arm/mach-exynos/Makefile                |   1 +
 arch/arm/mach-exynos/clock_init_exynos4412.c | 122 ++++++
 arch/arm/mach-exynos/dmc_init_exynos4412.c   | 185 ++++++++
 arch/arm/mach-exynos/exynos4412_setup.h      | 425 +++++++++++++++++++
 arch/arm/mach-exynos/power.c                 |  12 +
 6 files changed, 751 insertions(+)
 create mode 100644 arch/arm/mach-exynos/clock_init_exynos4412.c
 create mode 100644 arch/arm/mach-exynos/dmc_init_exynos4412.c
 create mode 100644 arch/arm/mach-exynos/exynos4412_setup.h

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index ed04369cfa..17eaf99724 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -42,6 +42,9 @@ endchoice
 
 if ARCH_EXYNOS4
 
+config EXYNOS4412
+	bool
+
 choice
 	prompt "EXYNOS4 board select"
 
@@ -59,12 +62,15 @@ config TARGET_S5PC210_UNIVERSAL
 config TARGET_ORIGEN
 	bool "Exynos4412 Origen board"
 	select SUPPORT_SPL
+	select EXYNOS4412
 
 config TARGET_TRATS2
 	bool "Exynos4412 Trat2 board"
+	select EXYNOS4412
 
 config TARGET_ODROID
 	bool "Exynos4412 Odroid board"
+	select EXYNOS4412
 
 endchoice
 endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index ce88921868..5dcad9643b 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -13,6 +13,7 @@ ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_EXYNOS5)	+= clock_init_exynos5.o
 obj-$(CONFIG_EXYNOS5)	+= dmc_common.o dmc_init_ddr3.o
 obj-$(CONFIG_EXYNOS4210)+= dmc_init_exynos4210.o clock_init_exynos4210.o
+obj-$(CONFIG_EXYNOS4412)+= dmc_init_exynos4412.o clock_init_exynos4412.o
 obj-y	+= spl_boot.o tzpc.o
 obj-y	+= lowlevel_init.o
 endif
diff --git a/arch/arm/mach-exynos/clock_init_exynos4412.c b/arch/arm/mach-exynos/clock_init_exynos4412.c
new file mode 100644
index 0000000000..140d8b3482
--- /dev/null
+++ b/arch/arm/mach-exynos/clock_init_exynos4412.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Clock initialisation for Exynos4412 based boards
+ *
+ * Copyright (C) 2018 Simon Shields <simon at lineageos.org>
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/power.h>
+#include "common_setup.h"
+#include "exynos4412_setup.h"
+
+static void reset_isp(void)
+{
+	struct exynos4412_power *pwr =
+		(struct exynos4412_power *)samsung_get_base_power();
+
+	/*
+	 * This is needed on some SoC revisions
+	 * to ensure that the ISP power domain is usable.
+	 * It doesn't hurt to have it on SoC revisions where it's
+	 * not needed, so we just do it on all.
+	 */
+	writel(0, &pwr->cmu_reset_isp_sys_pwr_reg);
+	writel(0, &pwr->cmu_sysclk_isp_sys_pwr_reg);
+}
+
+void system_clock_init(void)
+{
+	struct exynos4x12_clock *clk =
+		(struct exynos4x12_clock *)samsung_get_base_clock();
+
+	reset_isp();
+
+	/* Switch clocks away from PLLs while we configure them */
+	writel(CLK_SRC_CPU_INIT, &clk->src_cpu);
+	writel(CLK_SRC_TOP0_INIT, &clk->src_top0);
+	writel(CLK_SRC_TOP1_INIT, &clk->src_top1);
+	writel(CLK_SRC_LEFTBUS_VAL, &clk->src_leftbus);
+	writel(CLK_SRC_RIGHTBUS_VAL, &clk->src_rightbus);
+	writel(CLK_SRC_PERIL0_VAL, &clk->src_peril0);
+	writel(CLK_SRC_LCD0_VAL, &clk->src_lcd);
+
+	sdelay(0x10000);
+
+	writel(CLK_DIV_DMC0_VAL, &clk->div_dmc0);
+	writel(CLK_DIV_DMC1_VAL, &clk->div_dmc1);
+	writel(CLK_DIV_TOP_VAL, &clk->div_top);
+	writel(CLK_DIV_LEFTBUS_VAL, &clk->div_leftbus);
+	writel(CLK_DIV_RIGHTBUS_VAL, &clk->div_rightbus);
+	writel(CLK_DIV_PERIL0_VAL, &clk->div_peril0);
+
+	/* PLLs */
+	writel(APLL_LOCK_VAL, &clk->apll_lock);
+	writel(MPLL_LOCK_VAL, &clk->mpll_lock);
+	writel(EPLL_LOCK_VAL, &clk->epll_lock);
+	writel(VPLL_LOCK_VAL, &clk->vpll_lock);
+
+	writel(CLK_DIV_CPU0_VAL, &clk->div_cpu0);
+	writel(CLK_DIV_CPU1_VAL, &clk->div_cpu1);
+
+	/* APLL: 800MHz */
+	writel(APLL_CON1_VAL, &clk->apll_con1);
+	writel(APLL_CON0_VAL, &clk->apll_con0);
+
+	/*
+	 * The iROM sets MPLL at 400MHz.
+	 * Skip increasing MPLL if it's not at 400MHz
+	 */
+	if (readl(&clk->mpll_con0) == 0xa0640301) {
+		/* MPLL: 800MHz */
+		writel(MPLL_CON1_VAL, &clk->mpll_con1);
+		writel(MPLL_CON0_VAL, &clk->mpll_con0);
+	}
+
+	/* EPLL: 96MHz */
+	writel(EPLL_CON2_VAL, &clk->epll_con2);
+	writel(EPLL_CON1_VAL, &clk->epll_con1);
+	writel(EPLL_CON0_VAL, &clk->epll_con0);
+
+	/* VPLL: 108MHz */
+	writel(VPLL_CON2_VAL, &clk->vpll_con2);
+	writel(VPLL_CON1_VAL, &clk->vpll_con1);
+	writel(VPLL_CON0_VAL, &clk->vpll_con0);
+
+	/* Stabilise */
+	sdelay(0x40000);
+
+	/* Now that PLLs are set up, use them. */
+	writel(CLK_SRC_CPU_PLLS, &clk->src_cpu);
+	writel(CLK_SRC_DMC_PLLS, &clk->src_dmc);
+	writel(CLK_SRC_TOP0_PLLS, &clk->src_top0);
+	writel(CLK_SRC_TOP1_PLLS, &clk->src_top1);
+
+	sdelay(0x10000);
+
+	/*
+	 * In the SDMMC booting case, we need to reconfigure MMC clock
+	 * to make the iROM happy.
+	 */
+	u32 fsys2_div = readl(&clk->div_fsys2);
+	/* new MMC2 div is 16 */
+	fsys2_div |= 0xf;
+	writel(fsys2_div, &clk->div_fsys2);
+}
+
+void emmc_boot_clk_div_set(void)
+{
+	struct exynos4x12_clock *clk = (struct exynos4x12_clock *)
+		samsung_get_base_clock();
+	u32 div_fsys3 = readl(&clk->div_fsys3);
+
+	div_fsys3 &= ~(0xff0f);
+	div_fsys3 |= (1 << 8) | 0x7;
+
+	writel(div_fsys3, &clk->div_fsys3);
+}
diff --git a/arch/arm/mach-exynos/dmc_init_exynos4412.c b/arch/arm/mach-exynos/dmc_init_exynos4412.c
new file mode 100644
index 0000000000..a1efd09d02
--- /dev/null
+++ b/arch/arm/mach-exynos/dmc_init_exynos4412.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Simon Shields <simon at lineageos.org>
+ */
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/dmc.h>
+#include <asm/arch/power.h>
+#include <debug_uart.h>
+#include "common_setup.h"
+#include "exynos4412_setup.h"
+
+#define NR_TZASC_BANKS 4
+
+/* Allow non-secure and secure access to all memory */
+#define RA0_VAL 0xf0000000
+
+static void tzasc_init(void)
+{
+	unsigned int start = samsung_get_base_dmc_tzasc();
+	unsigned int end = start + (DMC_OFFSET * (NR_TZASC_BANKS - 1));
+
+	for (; start <= end; start += DMC_OFFSET) {
+		struct exynos4412_tzasc *asc = (struct exynos4412_tzasc *)start;
+
+		writel(RA0_VAL, &asc->region_attributes_0);
+	}
+}
+
+static int board_num_mem_chips(void)
+{
+	u32 pkgid = readl(EXYNOS4_PRO_ID + 4);
+
+	/* 2GB of RAM */
+	if ((pkgid & 0x30) == 0x10)
+		return 2;
+	return 1;
+}
+
+static void set_prime_stopctrl(void)
+{
+	struct exynos4x12_clock *clk = (struct exynos4x12_clock *)
+		samsung_get_base_clock();
+
+	/* PRE_WAIT_CNT, POST_WAIT_CNT = 0x1 */
+	writel(0x101, &clk->atclk_stopctrl);
+}
+
+static void do_directcmd(struct exynos4_dmc *dmc, u32 cmd, int chip, u32 delay)
+{
+	if (delay)
+		sdelay(delay);
+	if (chip)
+		cmd |= CMD_CHIP(1);
+
+	writel(cmd, &dmc->directcmd);
+}
+
+void mem_ctrl_init(int reset)
+{
+	struct exynos4_dmc *dmcs[2];
+	int chips = board_num_mem_chips();
+	int rev = exynos4412_get_rev();
+	u32 memcontrol = DMC_MEMCONTROL;
+	u32 prechconfig = 0x64000000;
+	u32 zqcontrol = DMC_PHYZQCONTROL;
+
+	dmcs[0] = (struct exynos4_dmc *)samsung_get_base_dmc_ctrl();
+	dmcs[1] = (struct exynos4_dmc *)(samsung_get_base_dmc_ctrl()
+			+ DMC_OFFSET);
+
+	if (rev == EXYNOS4412_REV_ZERO)
+		prechconfig |= 0xffff;
+	else if (rev == EXYNOS4412_REV_PRIME)
+		set_prime_stopctrl();
+
+	if (chips == 2) {
+		memcontrol |= MEM_2CHIPS;
+		zqcontrol |= CTRL_ZQ_MODE_DDS_2GB;
+	} else {
+		zqcontrol |= CTRL_ZQ_MODE_DDS_1GB;
+	}
+
+	for (int idx = 0; idx < ARRAY_SIZE(dmcs); idx++) {
+		struct exynos4_dmc *dmc = dmcs[idx];
+
+		writel(zqcontrol, &dmc->phyzqcontrol);
+		writel(PHYCONTROL0_VAL_INIT, &dmc->phycontrol0);
+		writel(PHYCONTROL0_VAL_INIT | CTRL_DLL_ON, &dmc->phycontrol0);
+
+		writel(PHYCONTROL1_VAL, &dmc->phycontrol1);
+		writel(PHYCONTROL0_VAL, &dmc->phycontrol0);
+		writel(PHYCONTROL1_VAL | FP_RESYNC, &dmc->phycontrol1);
+		writel(PHYCONTROL1_VAL, &dmc->phycontrol1);
+		writel(PHYCONTROL1_VAL | FP_RESYNC, &dmc->phycontrol1);
+		writel(PHYCONTROL1_VAL, &dmc->phycontrol1);
+
+		writel(DMC_CONCONTROL_INIT, &dmc->concontrol);
+		writel(memcontrol, &dmc->memcontrol);
+		/* map first gigabyte of RAM at 0x40000000 - 0x7fffffff */
+		writel(CHIP_BASE(0x40) | DMC_MEMCONFIG0, &dmc->memconfig0);
+
+		/* map second gigabyte at 0x80000000 - 0xbfffffff */
+		if (chips == 2)
+			writel(CHIP_BASE(0x80) | DMC_MEMCONFIG0,
+					&dmc->memconfig1);
+		writel(DMC_IVCONTROL, &dmc->ivcontrol);
+		writel(prechconfig, &dmc->prechconfig);
+		writel(PHYCONTROL0_VAL_STAGE2, &dmc->phycontrol0);
+
+		writel(T_REFI(0x5d), &dmc->timingref);
+
+		if (rev == EXYNOS4412_REV_PRIME) {
+			writel(T_RFC(0x3a) | T_RRD(0x5) | T_RP(0xa) | T_RCD(0x8)
+					| T_RC(0x1c) | T_RAS(0x13),
+					&dmc->timingrow);
+			writel(T_WTR(0x4) | T_WR(0x7) | T_RTP(0x4) | CL(0x0)
+					| WL(0x3) | RL(0x6), &dmc->timingdata);
+			writel(T_FAW(0x16) | T_XSR(0x3e) | T_XP(0x4)
+					| T_CKE(0x7) | T_MRD(0x5),
+					&dmc->timingpower);
+		} else {
+			u32 timingrow = T_RFC(0x34) | T_RP(0x9) | T_RCD(0x8)
+				| T_RC(0x1a) | T_RAS(0x11);
+			if (rev == EXYNOS4412_REV_ZERO)
+				timingrow |= T_RRD(0xa);
+			else
+				timingrow |= T_RRD(0x4);
+			writel(timingrow, &dmc->timingrow);
+			writel(T_WTR(0x3) | T_WR(0x6) | T_RTP(0x3) | CL(0x3)
+					| WL(0x3) | RL(0x6), &dmc->timingdata);
+			writel(T_FAW(0x14) | T_XSR(0x38) | T_XP(0x3)
+					| T_CKE(0x6) | T_MRD(0x5),
+					&dmc->timingpower);
+		}
+
+		for (int i = 0; i < chips; i++) {
+			do_directcmd(dmc, CMD_TYPE(0x7), i, 0x100000);
+			do_directcmd(dmc, CMD_TYPE(0x0) | CMD_BANK(0x7)
+					| CMD_ADDR(0x1c00), i, 0x100000);
+			do_directcmd(dmc, CMD_TYPE(0x0) | CMD_BANK(0x1)
+					| CMD_ADDR(0xbfc), i, 0x100000);
+			do_directcmd(dmc, CMD_TYPE(0x0) | CMD_BANK(0x0)
+					| CMD_ADDR(0x608), i, 0x100000);
+			do_directcmd(dmc, CMD_TYPE(0x0) | CMD_BANK(0x0)
+					| CMD_ADDR(0x810), i, 0);
+			do_directcmd(dmc, CMD_TYPE(0x0) | CMD_BANK(0x0)
+					| CMD_ADDR(0xc08), i, 0);
+		}
+	}
+
+	writel(PHYCONTROL0_VAL, &dmcs[0]->phycontrol0);
+	writel(MEM_TERM_EN | PHY_READ_EN | CTRL_SHGATE | CTRL_REF(8)
+			| CTRL_SHIFTC(4), &dmcs[0]->phycontrol1);
+	writel(PHYCONTROL0_VAL | CTRL_DLL_START, &dmcs[0]->phycontrol0);
+	sdelay(0x20000);
+
+	writel(CTRL_REF(8) | FP_RESYNC | CTRL_SHIFTC(4), &dmcs[0]->phycontrol1);
+	writel(CTRL_REF(8) | CTRL_SHIFTC(4), &dmcs[0]->phycontrol1);
+
+	sdelay(0x20000);
+
+	writel(PHYCONTROL0_VAL, &dmcs[1]->phycontrol0);
+	writel(MEM_TERM_EN | PHY_READ_EN | CTRL_SHGATE | CTRL_REF(8)
+			| CTRL_SHIFTC(4), &dmcs[1]->phycontrol1);
+	writel(PHYCONTROL0_VAL | CTRL_DLL_START, &dmcs[1]->phycontrol0);
+	sdelay(0x20000);
+
+	writel(CTRL_REF(8) | FP_RESYNC | CTRL_SHIFTC(4), &dmcs[1]->phycontrol1);
+	writel(CTRL_REF(8) | CTRL_SHIFTC(4), &dmcs[1]->phycontrol1);
+
+	sdelay(0x20000);
+
+	writel(DMC_CONCONTROL, &dmcs[0]->concontrol);
+	writel(DMC_CONCONTROL, &dmcs[1]->concontrol);
+
+	memcontrol |= DSREF_EN | TP_EN | DPWRDN_EN | CLK_STOP_EN;
+	writel(memcontrol, &dmcs[0]->memcontrol);
+	writel(memcontrol, &dmcs[1]->memcontrol);
+
+	tzasc_init();
+}
diff --git a/arch/arm/mach-exynos/exynos4412_setup.h b/arch/arm/mach-exynos/exynos4412_setup.h
new file mode 100644
index 0000000000..73ab75af7f
--- /dev/null
+++ b/arch/arm/mach-exynos/exynos4412_setup.h
@@ -0,0 +1,425 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2011 Samsung Electronics Co. Ltd
+ * Copyright (C) 2018 Simon Shields <simon at lineageos.org>
+ */
+
+#ifndef _EXYNOS4412_SETUP_H
+#define _EXYNOS4412_SETUP_H
+
+#include <config.h>
+#include <version.h>
+
+#include <asm/arch/cpu.h>
+
+#define EXYNOS4412_REV_ZERO 0x00
+#define EXYNOS4412_REV_MAIN 0x10
+#define EXYNOS4412_REV_PRIME 0x20
+#define EXYNOS4412_REV_MASK 0xf0
+
+static inline int exynos4412_get_rev(void)
+{
+	return readl(EXYNOS4_PRO_ID) & EXYNOS4412_REV_MASK;
+}
+
+/* CLK_DIV_CPU0 */
+#define CORE2_RATIO	0x0
+#define APLL_RATIO	0x1
+#define PCLK_DBG_RATIO	0x1
+#define ATB_RATIO	0x3
+#define PERIPH_RATIO	0x7
+#define COREM1_RATIO	0x5
+#define COREM0_RATIO	0x2
+#define CORE_RATIO	0x0
+
+/* CLK_DIV_CPU1 */
+#define CORES_RATIO	0x3
+#define HPM_RATIO	0x0
+#define COPY_RATIO	0x3
+
+#define CLK_DIV_CPU0_VAL	((CORE2_RATIO << 28)    \
+				| (APLL_RATIO << 24)    \
+				| (PCLK_DBG_RATIO << 20)\
+				| (ATB_RATIO << 16)     \
+				| (PERIPH_RATIO << 12)   \
+				| (COREM1_RATIO << 8)   \
+				| (COREM0_RATIO << 4)   \
+				| (CORE_RATIO))
+
+#define CLK_DIV_CPU1_VAL	((CORES_RATIO << 8) \
+				|  (HPM_RATIO << 4) \
+				| (COPY_RATIO))
+/* APLL_CON1 / MPLL_CON1 */
+#define RESV1	(1 << 24)
+#define RESV0	(1 << 23)
+#define BYPASS	(1 << 22)
+#define DCC_ENB	(1 << 21) /* Active low */
+#define AFC_ENB	(1 << 20) /* Active low */
+#define FEED_EN	(1 << 16)
+#define LOCK_CON_OUT(x)	((x) << 14)
+#define LOCK_CON_IN(x)	((x) << 12)
+#define LOCK_CON_DLY(x)	((x) << 8)
+#define AFC(x)		((x) << 0)
+
+/* MPLL */
+/* 800MHz = (0x64) * 24000000 / (3 * (1 << 0)) */
+#define MPLL_MDIV	0x64
+#define MPLL_PDIV	0x3
+#define MPLL_SDIV	0x0
+#define MPLL_CON1_VAL (RESV0 | LOCK_CON_IN(3) | LOCK_CON_DLY(8))
+
+/* ARM_CLOCK/APLL */
+/* 800MHz = (0x64) * 24000000 / (3 * (1 << 0)) */
+#define APLL_MDIV	0x64
+#define APLL_PDIV	0x3
+#define APLL_SDIV	0x0
+#define APLL_CON1_VAL (RESV0 | LOCK_CON_IN(3) | LOCK_CON_DLY(8))
+
+/* EPLL_CON1 / VPLL_CON1 */
+#define SELF_PF(x)	((x) << 29)
+#define MRR(x)		((x) << 24)
+#define MFR(x)		((x) << 16)
+#define K(x)		((x) << 0)
+
+/* EPLL_CON2 / VPLL_CON2 */
+#define EXTAFC(x)	((x) << 8)
+#define DCC_ENB_EV	(1 << 7) /* Active low */
+#define AFC_ENB_EV	(1 << 6) /* Active low */
+#define SSCG_EN		(1 << 5)
+#define BYPASS_EV	(1 << 4)
+#define FVCO_EN		(1 << 3)
+#define FSEL		(1 << 2)
+#define ICP_BOOST(x)	((x) << 0)
+
+/* EPLL */
+/* Fout = (M + K/65536) * Fin / (P * (1 << S)) */
+/* 96MHz = (0x40) * 24000000 / (2 * (1 << 3)) */
+#define EPLL_MDIV	0x40
+#define EPLL_PDIV	0x2
+#define EPLL_SDIV	0x3
+
+#define EPLL_CON1_VAL	SELF_PF(3) | MRR(6) | MFR(1)
+#define EPLL_CON2_VAL	DCC_ENB_EV
+
+/* VPLL */
+#define VPLL_MDIV	0x48
+#define VPLL_PDIV	0x2
+#define VPLL_SDIV	0x3
+
+#define VPLL_CON1_VAL	SELF_PF(3) | MRR(6) | MFR(1)
+#define VPLL_CON2_VAL	DCC_ENB_EV
+
+/* Set PLL */
+#define set_pll(mdiv, pdiv, sdiv)	((1 << 31) | (mdiv << 16) \
+					| (pdiv << 8) | (sdiv))
+
+#define APLL_CON0_VAL	set_pll(APLL_MDIV, APLL_PDIV, APLL_SDIV)
+#define MPLL_CON0_VAL	set_pll(MPLL_MDIV, MPLL_PDIV, MPLL_SDIV)
+#define EPLL_CON0_VAL	set_pll(EPLL_MDIV, EPLL_PDIV, EPLL_SDIV)
+#define VPLL_CON0_VAL	set_pll(VPLL_MDIV, VPLL_PDIV, VPLL_SDIV)
+
+/* CLK_SRC_CPU */
+#define MUX_MPLL_USER_SEL_C(x)	((x) << 24) /* 0: FINPLL, 1: FOUTMPLL */
+#define MUX_HPM_SEL(x)		((x) << 20) /* 0: MOUTAPLL, 1: SCLKMPLL */
+#define MUX_CORE_SEL(x)		((x) << 16) /* 0: MOUTAPLL, 1: SCLKMPLL */
+#define MUX_APLL_SEL(x)		((x) << 0)  /* 0: FINPLL, 1: MOUTAPLLFOUT */
+
+/* All clocks from XusbXTI */
+#define CLK_SRC_CPU_INIT	(MUX_MPLL_USER_SEL_C(0) | MUX_HPM_SEL(0) \
+				| MUX_CORE_SEL(0) | MUX_APLL_SEL(0))
+
+#define CLK_SRC_CPU_PLLS	(MUX_MPLL_USER_SEL_C(1) | MUX_APLL_SEL(1))
+
+/* CLK_SRC_DMC */
+#define MUX_PWI_SEL(x)		((x) << 16)	/* 0: XXTI, 1: XusbXTI, ... */
+#define MUX_MPLL_SEL(x)		((x) << 12)	/* 0: FINPLL, 1: MOUTMPLLFOUT */
+#define MUX_DPHY_SEL(x)		((x) << 8)	/* 0: SCLKMPLL, 1: SCLKAPLL */
+#define MUX_DMC_BUS_SEL		((x) << 4)	/* 0: SCLKMPLL, 1: SCLKAPLL */
+
+#define CLK_SRC_DMC_PLLS	(MUX_PWI_SEL(1) | MUX_MPLL_SEL(1))
+
+/* CLK_DIV_DMC0 */
+#define CORE_TIMERS_RATIO	0x0
+#define COPY2_RATIO		0x0
+#define DMCP_RATIO		0x1
+#define DMCD_RATIO		0x1
+#define DMC_RATIO		0x7
+#define DPHY_RATIO		0x1
+#define ACP_PCLK_RATIO		0x1
+#define ACP_RATIO		0x7
+
+#define CLK_DIV_DMC0_VAL	((CORE_TIMERS_RATIO << 28) \
+				| (COPY2_RATIO << 24) \
+				| (DMCP_RATIO << 20)	\
+				| (DMCD_RATIO << 16)	\
+				| (DMC_RATIO << 12)	\
+				| (DPHY_RATIO << 8)	\
+				| (ACP_PCLK_RATIO << 4)	\
+				| (ACP_RATIO))
+
+/* CLK_DIV_DMC1 */
+#define DPM_RATIO		0x7
+#define DVSEM_RATIO		0x7
+#define C2C_ACLK_RATIO		0x1
+#define PWI_RATIO		0x7
+#define C2C_RATIO		0x7
+#define G2D_ACP_RATIO		0x3
+
+#define CLK_DIV_DMC1_VAL	((DPM_RATIO << 24) \
+				| (DVSEM_RATIO << 16) \
+				| (C2C_ACLK_RATIO << 12) \
+				| (PWI_RATIO << 8) \
+				| (C2C_RATIO << 4) \
+				| (G2D_ACP_RATIO))
+
+/* CLK_SRC_TOP0	*/
+#define MUX_ONENAND_SEL(x)	((x) << 28) /* 0 = DOUT133, 1 = DOUT166 */
+#define MUX_ACLK_133_SEL(x)	((x) << 24) /* 0 = SCLKMPLL, 1 = SCLKAPLL */
+#define MUX_ACLK_160_SEL(x)	((x) << 20) /* ditto */
+#define MUX_ACLK_100_SEL(x)	((x) << 16) /* ditto */
+#define MUX_ACLK_200_SEL(x)	((x) << 12) /* ditto */
+#define MUX_VPLL_SEL(x)		((x) << 8) /* 0: FINPLL, 1: FOUTVPLL */
+#define MUX_EPLL_SEL(x)		((x) << 4) /* 0: FINPLL, 1: FOUTEPLL */
+#define CLK_SRC_TOP0_INIT	(MUX_ONENAND_SEL(0)	\
+				| MUX_ACLK_133_SEL(0)	\
+				| MUX_ACLK_160_SEL(0)	\
+				| MUX_ACLK_100_SEL(0)	\
+				| MUX_ACLK_200_SEL(0)	\
+				| MUX_VPLL_SEL(0)	\
+				| MUX_EPLL_SEL(0))
+
+#define CLK_SRC_TOP0_PLLS	(MUX_VPLL_SEL(1) | MUX_EPLL_SEL(1))
+
+/* CLK_SRC_TOP1	*/
+/* 0: FINPLL, 1: DIVOUT_ACLK_400_MCUISP */
+#define MUX_ACLK_400_MCUISP_SUB_SEL(x)	((x) << 24)
+/* 0: FINPLL, 1: DIVOUT_ACLK_200 */
+#define MUX_ACLK_200_SUB_SEL(x)		((x) << 20)
+/* 0: FINPLL, 1: DIVOUT_ACLK_266_GPS */
+#define MUX_ACLK_266_GPS_SUB_SEL(x)	((x) << 16)
+/* 0: FINPLL, 1: SCLKMPLL */
+#define MUX_MPLL_USER_T_SEL(x)		((x) << 12)
+/* 0: SCLKMPLL_USER_T, 1: SCLKAPLL */
+#define MUX_ACLK_400_MCUISP_SEL(x)	((x) << 8)
+/* 0: SCLKMPLL_USER_T, 1: SCLKAPLL */
+#define MUX_ACLK_266_GPS_SEL(x)		((x) << 4)
+
+#define CLK_SRC_TOP1_INIT	(MUX_ACLK_400_MCUISP_SUB_SEL(0)  \
+				| MUX_ACLK_200_SUB_SEL(0)  \
+				| MUX_ACLK_266_GPS_SUB_SEL(0)  \
+				| MUX_MPLL_USER_T_SEL(0))
+
+#define CLK_SRC_TOP1_PLLS (MUX_ACLK_266_GPS_SUB_SEL(1) | MUX_MPLL_USER_T_SEL(1))
+
+/* CLK_DIV_TOP */
+#define ACLK_400_MCUISP_RATIO	0x1
+#define ACLK_266_GPS_RATIO	0x2
+#define ONENAND_RATIO	0x1
+#define ACLK_133_RATIO	0x7
+#define ACLK_160_RATIO	0x4
+#define ACLK_100_RATIO	0xf
+#define ACLK_200_RATIO	0x4
+
+#define CLK_DIV_TOP_VAL	((ACLK_400_MCUISP_RATIO << 24) \
+			| (ACLK_266_GPS_RATIO << 20) \
+			| (ONENAND_RATIO << 16) \
+			| (ACLK_133_RATIO << 12) \
+			| (ACLK_160_RATIO << 8)	\
+			| (ACLK_100_RATIO << 4)	\
+			| (ACLK_200_RATIO))
+
+/* CLK_SRC_LEFTBUS */
+#define MUX_MPLL_USER_SEL_L(x)	((x) << 4) /* 0: FINPLL, 1: FOUTMPLL */
+#define MUX_GDL_SEL(x)		((x) << 0) /* 0: SCLKMPLL, 1: SCLKAPLL */
+#define CLK_SRC_LEFTBUS_VAL	(MUX_MPLL_USER_SEL_L(1) | MUX_GDL_SEL(0))
+
+/* CLK_DIV_LEFTBUS */
+#define GPL_RATIO	0x1
+#define GDL_RATIO	0x7
+#define CLK_DIV_LEFTBUS_VAL	((GPL_RATIO << 4) \
+				| (GDL_RATIO))
+
+/* CLK_SRC_RIGHTBUS */
+#define MUX_MPLL_USER_SEL_R(x)	((x) << 4) /* 0: FINPLL, 1: FOUTMPLL */
+#define MUX_GDR_SEL(x)		((x) << 0) /* 0: SCLKMPLL, 1: SCLKAPLL */
+#define CLK_SRC_RIGHTBUS_VAL	(MUX_MPLL_USER_SEL_R(1) | MUX_GDR_SEL(0))
+
+/* CLK_DIV_RIGHTBUS */
+#define GPR_RATIO	0x1
+#define GDR_RATIO	0x7
+#define CLK_DIV_RIGHTBUS_VAL	((GPR_RATIO << 4) \
+				| (GDR_RATIO))
+
+/* APLL_LOCK */
+#define APLL_LOCK_VAL	(0x3E8)
+/* MPLL_LOCK */
+#define MPLL_LOCK_VAL	(0x2F1)
+/* EPLL_LOCK */
+#define EPLL_LOCK_VAL	(0x2321)
+/* VPLL_LOCK */
+#define VPLL_LOCK_VAL	(0x2321)
+
+/* CLK_SRC_PERIL0 */
+#define UART4_SEL(x)	((x) << 16) /* 6: SCLK_MPLL_USER_T */
+#define UART3_SEL(x)	((x) << 12)
+#define UART2_SEL(x)	((x) << 8)
+#define UART1_SEL(x)	((x) << 4)
+#define UART0_SEL(x)	((x) << 0)
+#define CLK_SRC_PERIL0_VAL	(UART4_SEL(6) \
+				| UART3_SEL(6) \
+				| UART2_SEL(6)	\
+				| UART1_SEL(6)	\
+				| UART0_SEL(6))
+
+/* CLK_DIV_PERIL0 */
+#define UART5_RATIO	8
+#define UART4_RATIO	8
+#define UART3_RATIO	8
+#define UART2_RATIO	8
+#define UART1_RATIO	8
+#define UART0_RATIO	8
+
+#define CLK_DIV_PERIL0_VAL	((UART5_RATIO << 20) \
+				| (UART4_RATIO << 16) \
+				| (UART3_RATIO << 12)	\
+				| (UART2_RATIO << 8)	\
+				| (UART1_RATIO << 4)	\
+				| (UART0_RATIO))
+
+/* CLK_SRC_LCD0 */
+#define MIPI0_SEL(x)		((x) << 12) /* 1: XusbXTI */
+#define MDNIE_PWM0_SEL(x)	((x) << 8)  /* 1: XusbXTI */
+#define MDNIE0_SEL(x)		((x) << 4)  /* 6: SCLK_MPLL_USER_T */
+#define FIMD0_SEL(x)		((x) << 0)  /* 6: SCLK_MPLL_USER_T */
+
+#define CLK_SRC_LCD0_VAL	(MIPI0_SEL(0x1) \
+				| MDNIE_PWM0_SEL(0x1) \
+				| MDNIE0_SEL(0x6) \
+				| FIMD0_SEL(0x6))
+
+/* DMC PHYCONTROL0 */
+#define CTRL_FORCE(x)	((x) << 24)
+#define CTRL_INC(x)	((x) << 16)
+#define CTRL_START_POINT(x) ((x) << 8)
+#define DQS_DELAY(x)	((x) << 4)
+#define CTRL_DFDQS	(0x1 << 3)
+#define CTRL_HALF	(0x1 << 2)
+#define CTRL_DLL_ON	(0x1 << 1)
+#define CTRL_DLL_START (0x1 << 0)
+
+/* CTRL_DLL_START will be ORd in when appropriate */
+#define PHYCONTROL0_VAL_INIT (CTRL_FORCE(0x71) | CTRL_INC(0x10) \
+			| CTRL_START_POINT(0x10) \
+			| CTRL_DFDQS)
+#define PHYCONTROL0_VAL_STAGE2 (CTRL_FORCE(0x9c) | CTRL_INC(0x40) \
+			| DQS_DELAY(0xf) | CTRL_DFDQS | CTRL_HALF \
+			| CTRL_DLL_ON | CTRL_DLL_START)
+#define PHYCONTROL0_VAL (CTRL_FORCE(0x7f) | CTRL_INC(0x10) \
+			| CTRL_START_POINT(0x10) \
+			| CTRL_DFDQS | CTRL_DLL_ON)
+
+/* DMC PHYCONTROL1 */
+#define MEM_TERM_EN (0x1 << 31)
+#define PHY_READ_EN (0x1 << 30)
+#define CTRL_SHGATE (0x1 << 29)
+#define CTRL_REF(x)	(x << 4)
+#define FP_RESYNC	(0x1 << 3)
+#define CTRL_SHIFTC(x) (x << 0)
+
+#define PHYCONTROL1_VAL (CTRL_REF(8) | CTRL_SHIFTC(4))
+
+/* DMC TIMINGREF */
+#define T_REFI(x)	((x) << 0)
+
+/* DMC TIMINGROW */
+#define T_RFC(x)	((x) << 24)
+#define T_RRD(x)	((x) << 20)
+#define T_RP(x)		((x) << 16)
+#define T_RCD(x)	((x) << 12)
+#define T_RC(x)		((x) << 6)
+#define T_RAS(x)	((x) << 0)
+
+/* DMC TIMINGDATA */
+#define T_WTR(x)	((x) << 28)
+#define T_WR(x)		((x) << 24)
+#define T_RTP(x)	((x) << 20)
+#define CL(x)		((x) << 16)
+#define WL(x)		((x) << 8)
+#define RL(x)		((x) << 0)
+
+/* DMC TIMINGPOWER */
+#define T_FAW(x)	((x) << 26)
+#define T_XSR(x)	((x) << 16)
+#define T_XP(x)		((x) << 8)
+#define T_CKE(x)	((x) << 4)
+#define T_MRD(x)	((x) << 0)
+
+/* DMC CONCONTROL */
+#define TIMEOUT_LEVEL0	(0xfff << 16)
+#define RD_FETCH		(0x3 << 12)
+#define DRV_TYPE		(0x3 << 6)
+#define AREF_EN			(0x1 << 5)
+#define PDN_DQ_DISABLE	(0x1 << 4)
+#define IO_PDN_CON		(0x1 << 3)
+#define CLK_RATIO		(0x1 << 1)
+
+#define DMC_CONCONTROL_INIT	(TIMEOUT_LEVEL0 | RD_FETCH \
+				| DRV_TYPE | IO_PDN_CON | CLK_RATIO)
+
+#define DMC_CONCONTROL	(TIMEOUT_LEVEL0 | RD_FETCH \
+			| DRV_TYPE | AREF_EN \
+			| PDN_DQ_DISABLE | IO_PDN_CON \
+			| CLK_RATIO)
+
+/* DMC MEMCONTROL */
+#define BURSTLEN	(0x2 << 20)
+#define MEM_WIDTH	(0x2 << 12)
+#define MEM_2CHIPS	(0x1 << 16)
+#define MEM_TYPE	(0x5 << 8) /* LPDDR2-S4 */
+#define DSREF_EN	(0x1 << 5)
+#define TP_EN		(0x1 << 4)
+#define DPWRDN_EN	(0x1 << 1)
+#define CLK_STOP_EN (0x1 << 0)
+
+#define DMC_MEMCONTROL (BURSTLEN | MEM_WIDTH | MEM_TYPE)
+
+/* DMC MEMCONFIG0 */
+#define CHIP_BASE(x)	((x) << 24)
+#define CHIP_MASK	(0xc0 << 16)
+#define CHIP_MAP	(0x1 << 12)
+#define CHIP_COL	(0x3 << 8)
+#define CHIP_ROW	(0x2 << 4)
+#define CHIP_BANK	(0x3 << 0)
+
+#define DMC_MEMCONFIG0 (CHIP_MASK | CHIP_MAP | CHIP_COL | CHIP_ROW | CHIP_BANK)
+
+/* DMC DIRECTCMD */
+#define CMD_TYPE(x)	((x) << 24)
+#define CMD_CHIP(x)	((x) << 20)
+#define CMD_BANK(x)	((x) << 16)
+#define CMD_ADDR(x)	((x) << 0)
+
+/* DMC_PHYZQCONTROL */
+#define CTRL_DCC	(0xe38 << 20)
+#define CTRL_ZQ_FORCE_IMPP (0x2 << 17)
+#define CTRL_ZQ_FORCE_IMPN (0x5 << 14)
+#define CTRL_ZQ_MODE_TERM (0x2 << 11)
+#define CTRL_ZQ_MODE_DDS_1GB (0x4 << 8)
+#define CTRL_ZQ_MODE_DDS_2GB (0x5 << 8)
+#define CTRL_ZQ_DIV (0 << 4)
+#define CTRL_ZQ_FORCE (0 << 2)
+#define CTRL_ZQ_START (1 << 1)
+#define CTRL_ZQ_MODE_NOTTERM (1 << 0)
+
+#define DMC_PHYZQCONTROL	(CTRL_DCC | CTRL_ZQ_FORCE_IMPP \
+				| CTRL_ZQ_FORCE_IMPN | CTRL_ZQ_MODE_TERM \
+				| CTRL_ZQ_DIV | CTRL_ZQ_FORCE | CTRL_ZQ_START \
+				| CTRL_ZQ_MODE_NOTTERM)
+
+/* DMC IVCONTROL */
+#define IV_ON	(0x1 << 31)
+#define IV_SIZE_128B	(0x7 << 0)
+
+#define DMC_IVCONTROL	(IV_ON | IV_SIZE_128B)
+#endif
+
diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c
index 63c410acef..a513b89551 100644
--- a/arch/arm/mach-exynos/power.c
+++ b/arch/arm/mach-exynos/power.c
@@ -162,6 +162,16 @@ static void exynos5_set_ps_hold_ctrl(void)
 			EXYNOS_PS_HOLD_CONTROL_DATA_HIGH);
 }
 
+static void exynos4412_set_ps_hold_ctrl(void)
+{
+	struct exynos4412_power *power =
+		(struct exynos4412_power *)samsung_get_base_power();
+
+	/* Set PS-Hold high */
+	setbits_le32(&power->ps_hold_control,
+			EXYNOS_PS_HOLD_CONTROL_DATA_HIGH);
+}
+
 /*
  * Set ps_hold data driving value high
  * This enables the machine to stay powered on
@@ -172,6 +182,8 @@ void set_ps_hold_ctrl(void)
 {
 	if (cpu_is_exynos5())
 		exynos5_set_ps_hold_ctrl();
+	else if (proid_is_exynos4412())
+		exynos4412_set_ps_hold_ctrl();
 }
 
 
-- 
2.18.0



More information about the U-Boot mailing list