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 <[email protected]>
---
 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+#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 <[email protected]>
+ */
+
+#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

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to