
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@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@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@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@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(); }