diff options
Diffstat (limited to 'board/samsung/common/exynos4-dt.c')
-rw-r--r-- | board/samsung/common/exynos4-dt.c | 1185 |
1 files changed, 1185 insertions, 0 deletions
diff --git a/board/samsung/common/exynos4-dt.c b/board/samsung/common/exynos4-dt.c new file mode 100644 index 0000000000..5b217b3d55 --- /dev/null +++ b/board/samsung/common/exynos4-dt.c @@ -0,0 +1,1185 @@ +/* + * Copyright (C) 2014 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/sections.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/power.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#include <asm/gpio.h> +#include <asm/arch/cpu.h> +#include <power/pmic.h> +#include <power/max77686_pmic.h> +#include <power/battery.h> +#include <power/max77693_pmic.h> +#include <power/max77693_muic.h> +#include <power/max77693_fg.h> +#include <errno.h> +#include <usb.h> +#include <usb/s3c_udc.h> +#include <usb_mass_storage.h> +#include <fdt.h> +#include <lcd.h> +#include <mmc.h> +#include <asm/arch/mipi_dsim.h> +#include <samsung/misc.h> +#include <libtizen.h> +#include "setup.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define HWREV_TRATS2_CFG_REG 0x11000280 +#define HWREV_TRATS2_CFG 0x0 +#define HWREV_TRATS2_PULL_REG 0x11000288 +#define HWREV_TRATS2_PULL 0x33000033 +#define HWREV_TRATS2_DAT_REG 0x11000284 +#define HWREV_TRATS2_DAT_MASK 0xf0 + +#define CPU_MAIN_REV_MASK 0xf0 +#define CPU_MAIN_REV_SHIFT 0x4 +#define CPU_MAIN_REV(x) ((x >> CPU_MAIN_REV_SHIFT) & CPU_MAIN_REV_MASK) + +#define DTB_PADDING 0x4 + +/* For global battery and charger functions */ +static struct power_battery *pbat; +static struct pmic *p_chrg, *p_muic, *p_fg, *p_bat; +static int power_init_done; + +#ifdef CONFIG_BOARD_TYPES +/* Supported Exynos4 boards */ +enum { + BOARD_TYPE_TRATS2, + BOARD_TYPE_ODROID_U3, + BOARD_TYPE_ODROID_X2, + BOARD_TYPES_NUM, +}; + +static const int board_arch_num[] = { + MACH_TYPE_TRATS2, + MACH_TYPE_ODROIDX, + MACH_TYPE_ODROIDX, +}; + +static const char *board_compat[] = { + "samsung,trats2", + "samsung,odroid", + "samsung,odroid", +}; + +static const char *plat_name[] = { + "trats", + "odroid", + "odroid", +}; + +static const char *board_model[] = { + "2", + "u3", + "x2", +}; + +static const char *board_name[] = { + "trats2", + "odroidu3", + "odroidx2", +}; + +extern void sdelay(unsigned long); + +void set_board_type(void) +{ + int hwrev = 0; + unsigned int addr; + + /* GPM1[5:2] as input */ + writel(HWREV_TRATS2_CFG, HWREV_TRATS2_CFG_REG); + writel(HWREV_TRATS2_PULL, HWREV_TRATS2_PULL_REG); + hwrev = readl(HWREV_TRATS2_DAT_REG) & HWREV_TRATS2_DAT_MASK; + + /* Any Trats2 revision is valid */ + if (hwrev) { + gd->board_type = BOARD_TYPE_TRATS2; + return; + } + + /* Set GPA1 pin 1 to HI - enable XCL205 output */ + /* GPA1CON 0x11400020 */ + addr = 0x11400020; + writel(0x10, addr); + + /* GPA1DAT 0x11400024 */ + addr = 0x11400024; + writel(0x2, addr); + + /* GPA1PUD 0x11400028 */ + addr = 0x11400028; + writel(0xc, addr); + + /* GPA1DRV 0x1140002c */ + addr = 0x1140002c; + writel(0xc, addr); + + /* Check GPC1 pin 2 input */ + /* GPC1CON 0x11400020 */ + addr = 0x11400080; + writel(0x0, addr); + + /* GPC1PUD 0x11400028 */ + addr = 0x11400088; + writel(0x0, addr); + + /* XCL205 - needs some latch time */ + sdelay(200000); + + /* GPC1DAT 0x11400024 */ + addr = 0x11400084; + + /* Check GPC1 pin2 - LED supplied by XCL205 - X2 only */ + if (readl(addr) & 0x4) + gd->board_type = BOARD_TYPE_ODROID_X2; + else + gd->board_type = BOARD_TYPE_ODROID_U3; +} + +int board_is_trats2(void) +{ + if (gd->board_type == BOARD_TYPE_TRATS2) + return 1; + + return 0; +} + +int board_is_odroid_x2(void) +{ + if (gd->board_type == BOARD_TYPE_ODROID_X2) + return 1; + + return 0; +} + +int board_is_odroid_u3(void) +{ + if (gd->board_type == BOARD_TYPE_ODROID_U3) + return 1; + + return 0; +} + +const char *get_plat_name(void) +{ + return plat_name[gd->board_type]; +} + +const char *get_board_name(void) +{ + return board_name[gd->board_type]; +} + +const char *get_board_model(void) +{ + return board_model[gd->board_type]; +} +#endif + +#ifdef CONFIG_OF_MULTI +unsigned long *get_board_fdt(void) +{ + unsigned long *fdt = (unsigned long *)&_end; + unsigned long size; + char *compat = NULL; + int i; + + set_board_type(); + + for (i = 0; i < BOARD_TYPES_NUM; i++) { + if (!fdt || fdt_magic(fdt) != FDT_MAGIC) + break; + + compat = (char *) fdt_getprop(fdt, 0, "compatible", NULL); + if (compat && !strcmp(board_compat[gd->board_type], compat)) + return fdt; + + /* Byte size */ + size = fdt_totalsize(fdt); + + fdt += (unsigned long)(roundup(size, DTB_PADDING) >> 2); + } + + return NULL; +} +#endif + +#ifdef CONFIG_SET_DFU_ALT_INFO +char *get_dfu_alt_system(char *interface, char *devstr) +{ + char *alt_system; + + if (board_is_trats2()) + alt_system = getenv("dfu_alt_system_trats"); + else + alt_system = getenv("dfu_alt_system_odroid"); + + return alt_system; +} + +char *get_dfu_alt_boot(char *interface, char *devstr) +{ + struct mmc *mmc; + char *alt_boot; + int dev_num; + + dev_num = simple_strtoul(devstr, NULL, 10); + + mmc = find_mmc_device(dev_num); + if (!mmc) + return NULL; + + if (mmc_init(mmc)) + return NULL; + + if (board_is_trats2()) + alt_boot = IS_SD(mmc) ? DFU_ALT_BOOT_SD_TRATS2 : + DFU_ALT_BOOT_EMMC_TRATS2; + else + alt_boot = IS_SD(mmc) ? DFU_ALT_BOOT_SD_ODROID : + DFU_ALT_BOOT_EMMC_ODROID; + + return alt_boot; +} +#endif + +static void board_clock_init(void) +{ + unsigned int set, clr, clr_src_cpu, clr_pll_con0, clr_src_dmc; + struct exynos4x12_clock *clk = (struct exynos4x12_clock *) + samsung_get_base_clock(); + + /* + * CMU_CPU clocks src to MPLL + * Bit values: 0 ; 1 + * MUX_APLL_SEL: FIN_PLL ; FOUT_APLL + * MUX_CORE_SEL: MOUT_APLL ; SCLK_MPLL + * MUX_HPM_SEL: MOUT_APLL ; SCLK_MPLL_USER_C + * MUX_MPLL_USER_SEL_C: FIN_PLL ; SCLK_MPLL + */ + clr_src_cpu = MUX_APLL_SEL(0x1) | MUX_CORE_SEL(0x1) | + MUX_HPM_SEL(0x1) | MUX_MPLL_USER_SEL_C(0x1); + set = MUX_APLL_SEL(0) | MUX_CORE_SEL(1) | MUX_HPM_SEL(1) | + MUX_MPLL_USER_SEL_C(1); + + clrsetbits_le32(&clk->src_cpu, clr_src_cpu, set); + + /* Wait for mux change */ + while (readl(&clk->mux_stat_cpu) & MUX_STAT_CPU_CHANGING) + continue; + + /* Set APLL to 1000MHz */ + clr_pll_con0 = SDIV(0x7) | PDIV(0x3f) | MDIV(0x3ff) | FSEL(0x1); + set = SDIV(0) | PDIV(3) | MDIV(125) | FSEL(1); + + clrsetbits_le32(&clk->apll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ + while (!(readl(&clk->apll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Set CMU_CPU clocks src to APLL */ + set = MUX_APLL_SEL(1) | MUX_CORE_SEL(0) | MUX_HPM_SEL(0) | + MUX_MPLL_USER_SEL_C(1); + clrsetbits_le32(&clk->src_cpu, clr_src_cpu, set); + + /* Wait for mux change */ + while (readl(&clk->mux_stat_cpu) & MUX_STAT_CPU_CHANGING) + continue; + + set = CORE_RATIO(0) | COREM0_RATIO(2) | COREM1_RATIO(5) | + PERIPH_RATIO(0) | ATB_RATIO(4) | PCLK_DBG_RATIO(1) | + APLL_RATIO(0) | CORE2_RATIO(0); + /* + * Set dividers for MOUTcore = 1000 MHz + * coreout = MOUT / (ratio + 1) = 1000 MHz (0) + * corem0 = armclk / (ratio + 1) = 333 MHz (2) + * corem1 = armclk / (ratio + 1) = 166 MHz (5) + * periph = armclk / (ratio + 1) = 1000 MHz (0) + * atbout = MOUT / (ratio + 1) = 200 MHz (4) + * pclkdbgout = atbout / (ratio + 1) = 100 MHz (1) + * sclkapll = MOUTapll / (ratio + 1) = 1000 MHz (0) + * core2out = core_out / (ratio + 1) = 1000 MHz (0) (armclk) + */ + clr = CORE_RATIO(0x7) | COREM0_RATIO(0x7) | COREM1_RATIO(0x7) | + PERIPH_RATIO(0x7) | ATB_RATIO(0x7) | PCLK_DBG_RATIO(0x7) | + APLL_RATIO(0x7) | CORE2_RATIO(0x7); + + clrsetbits_le32(&clk->div_cpu0, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_cpu0) & DIV_STAT_CPU0_CHANGING) + continue; + + /* + * For MOUThpm = 1000 MHz (MOUTapll) + * doutcopy = MOUThpm / (ratio + 1) = 200 (4) + * sclkhpm = doutcopy / (ratio + 1) = 200 (4) + * cores_out = armclk / (ratio + 1) = 200 (4) + */ + clr = COPY_RATIO(0x7) | HPM_RATIO(0x7) | CORES_RATIO(0x7); + set = COPY_RATIO(4) | HPM_RATIO(4) | CORES_RATIO(4); + + clrsetbits_le32(&clk->div_cpu1, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_cpu1) & DIV_STAT_CPU1_CHANGING) + continue; + + /* + * Set CMU_DMC clocks src to APLL + * Bit values: 0 ; 1 + * MUX_C2C_SEL: SCLKMPLL ; SCLKAPLL + * MUX_DMC_BUS_SEL: SCLKMPLL ; SCLKAPLL + * MUX_DPHY_SEL: SCLKMPLL ; SCLKAPLL + * MUX_MPLL_SEL: FINPLL ; MOUT_MPLL_FOUT + * MUX_PWI_SEL: 0110 (MPLL); 0111 (EPLL); 1000 (VPLL); 0(XXTI) + * MUX_G2D_ACP0_SEL: SCLKMPLL ; SCLKAPLL + * MUX_G2D_ACP1_SEL: SCLKEPLL ; SCLKVPLL + * MUX_G2D_ACP_SEL: OUT_ACP0 ; OUT_ACP1 + */ + clr_src_dmc = MUX_C2C_SEL(0x1) | MUX_DMC_BUS_SEL(0x1) | + MUX_DPHY_SEL(0x1) | MUX_MPLL_SEL(0x1) | + MUX_PWI_SEL(0xf) | MUX_G2D_ACP0_SEL(0x1) | + MUX_G2D_ACP1_SEL(0x1) | MUX_G2D_ACP_SEL(0x1); + set = MUX_C2C_SEL(1) | MUX_DMC_BUS_SEL(1) | MUX_DPHY_SEL(1) | + MUX_MPLL_SEL(0) | MUX_PWI_SEL(0) | MUX_G2D_ACP0_SEL(1) | + MUX_G2D_ACP1_SEL(1) | MUX_G2D_ACP_SEL(1); + + clrsetbits_le32(&clk->src_dmc, clr_src_dmc, set); + + /* Wait for mux change */ + while (readl(&clk->mux_stat_dmc) & MUX_STAT_DMC_CHANGING) + continue; + + /* Set MPLL to 800MHz */ + set = SDIV(0) | PDIV(3) | MDIV(100) | FSEL(0) | PLL_ENABLE(1); + + clrsetbits_le32(&clk->mpll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ + while (!(readl(&clk->mpll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Switch back CMU_DMC mux */ + set = MUX_C2C_SEL(0) | MUX_DMC_BUS_SEL(0) | MUX_DPHY_SEL(0) | + MUX_MPLL_SEL(1) | MUX_PWI_SEL(8) | MUX_G2D_ACP0_SEL(0) | + MUX_G2D_ACP1_SEL(0) | MUX_G2D_ACP_SEL(0); + + clrsetbits_le32(&clk->src_dmc, clr_src_dmc, set); + + /* Wait for mux change */ + while (readl(&clk->mux_stat_dmc) & MUX_STAT_DMC_CHANGING) + continue; + + /* CLK_DIV_DMC0 */ + clr = ACP_RATIO(0x7) | ACP_PCLK_RATIO(0x7) | DPHY_RATIO(0x7) | + DMC_RATIO(0x7) | DMCD_RATIO(0x7) | DMCP_RATIO(0x7); + /* + * For: + * MOUTdmc = 800 MHz + * MOUTdphy = 800 MHz + * + * aclk_acp = MOUTdmc / (ratio + 1) = 200 (3) + * pclk_acp = aclk_acp / (ratio + 1) = 100 (1) + * sclk_dphy = MOUTdphy / (ratio + 1) = 400 (1) + * sclk_dmc = MOUTdmc / (ratio + 1) = 400 (1) + * aclk_dmcd = sclk_dmc / (ratio + 1) = 200 (1) + * aclk_dmcp = aclk_dmcd / (ratio + 1) = 100 (1) + */ + set = ACP_RATIO(3) | ACP_PCLK_RATIO(1) | DPHY_RATIO(1) | + DMC_RATIO(1) | DMCD_RATIO(1) | DMCP_RATIO(1); + + clrsetbits_le32(&clk->div_dmc0, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_dmc0) & DIV_STAT_DMC0_CHANGING) + continue; + + /* CLK_DIV_DMC1 */ + clr = G2D_ACP_RATIO(0xf) | C2C_RATIO(0x7) | PWI_RATIO(0xf) | + C2C_ACLK_RATIO(0x7) | DVSEM_RATIO(0x7f) | DPM_RATIO(0x7f); + /* + * For: + * MOUTg2d = 800 MHz + * MOUTc2c = 800 Mhz + * MOUTpwi = 108 MHz + * + * sclk_g2d_acp = MOUTg2d / (ratio + 1) = 200 (3) + * sclk_c2c = MOUTc2c / (ratio + 1) = 400 (1) + * aclk_c2c = sclk_c2c / (ratio + 1) = 200 (1) + * sclk_pwi = MOUTpwi / (ratio + 1) = 18 (5) + */ + set = G2D_ACP_RATIO(3) | C2C_RATIO(1) | PWI_RATIO(5) | + C2C_ACLK_RATIO(1) | DVSEM_RATIO(1) | DPM_RATIO(1); + + clrsetbits_le32(&clk->div_dmc1, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_dmc1) & DIV_STAT_DMC1_CHANGING) + continue; + + /* CLK_SRC_PERIL0 */ + clr = UART0_SEL(0xf) | UART1_SEL(0xf) | UART2_SEL(0xf) | + UART3_SEL(0xf) | UART4_SEL(0xf); + /* + * Set CLK_SRC_PERIL0 clocks src to MPLL + * src values: 0(XXTI); 1(XusbXTI); 2(SCLK_HDMI24M); 3(SCLK_USBPHY0); + * 5(SCLK_HDMIPHY); 6(SCLK_MPLL_USER_T); 7(SCLK_EPLL); + * 8(SCLK_VPLL) + * + * Set all to SCLK_MPLL_USER_T + */ + set = UART0_SEL(6) | UART1_SEL(6) | UART2_SEL(6) | UART3_SEL(6) | + UART4_SEL(6); + + clrsetbits_le32(&clk->src_peril0, clr, set); + + /* CLK_DIV_PERIL0 */ + clr = UART0_RATIO(0xf) | UART1_RATIO(0xf) | UART2_RATIO(0xf) | + UART3_RATIO(0xf) | UART4_RATIO(0xf); + /* + * For MOUTuart0-4: 800MHz + * + * SCLK_UARTx = MOUTuartX / (ratio + 1) = 100 (7) + */ + set = UART0_RATIO(7) | UART1_RATIO(7) | UART2_RATIO(7) | + UART3_RATIO(7) | UART4_RATIO(7); + + clrsetbits_le32(&clk->div_peril0, clr, set); + + while (readl(&clk->div_stat_peril0) & DIV_STAT_PERIL0_CHANGING) + continue; + + /* CLK_DIV_FSYS1 */ + clr = MMC0_RATIO(0xf) | MMC0_PRE_RATIO(0xff) | MMC1_RATIO(0xf) | + MMC1_PRE_RATIO(0xff); + /* + * For MOUTmmc0-3 = 800 MHz (MPLL) + * + * DOUTmmc1 = MOUTmmc1 / (ratio + 1) = 100 (7) + * sclk_mmc1 = DOUTmmc1 / (ratio + 1) = 50 (1) + * DOUTmmc0 = MOUTmmc0 / (ratio + 1) = 100 (7) + * sclk_mmc0 = DOUTmmc0 / (ratio + 1) = 50 (1) + */ + set = MMC0_RATIO(7) | MMC0_PRE_RATIO(1) | MMC1_RATIO(7) | + MMC1_PRE_RATIO(1); + + clrsetbits_le32(&clk->div_fsys1, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_fsys1) & DIV_STAT_FSYS1_CHANGING) + continue; + + /* CLK_DIV_FSYS2 */ + clr = MMC2_RATIO(0xf) | MMC2_PRE_RATIO(0xff) | MMC3_RATIO(0xf) | + MMC3_PRE_RATIO(0xff); + /* + * For MOUTmmc0-3 = 800 MHz (MPLL) + * + * DOUTmmc3 = MOUTmmc3 / (ratio + 1) = 100 (7) + * sclk_mmc3 = DOUTmmc3 / (ratio + 1) = 50 (1) + * DOUTmmc2 = MOUTmmc2 / (ratio + 1) = 100 (7) + * sclk_mmc2 = DOUTmmc2 / (ratio + 1) = 50 (1) + */ + set = MMC2_RATIO(7) | MMC2_PRE_RATIO(1) | MMC3_RATIO(7) | + MMC3_PRE_RATIO(1); + + clrsetbits_le32(&clk->div_fsys2, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_fsys2) & DIV_STAT_FSYS2_CHANGING) + continue; + + /* CLK_DIV_FSYS3 */ + clr = MMC4_RATIO(0xf) | MMC4_PRE_RATIO(0xff); + /* + * For MOUTmmc4 = 800 MHz (MPLL) + * + * DOUTmmc4 = MOUTmmc4 / (ratio + 1) = 100 (7) + * sclk_mmc4 = DOUTmmc4 / (ratio + 1) = 100 (0) + */ + set = MMC4_RATIO(7) | MMC4_PRE_RATIO(0); + + clrsetbits_le32(&clk->div_fsys3, clr, set); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_fsys3) & DIV_STAT_FSYS3_CHANGING) + continue; + + return; +} + +static void board_gpio_init(void) +{ + if (board_is_trats2()) { + /* PS_ALS_INT */ + gpio_set_pull(EXYNOS4X12_GPIO_X02, S5P_GPIO_PULL_NONE); + /* TSP_nINT */ + gpio_set_pull(EXYNOS4X12_GPIO_X04, S5P_GPIO_PULL_NONE); + /* AP_PMIC_IRQ*/ + gpio_set_pull(EXYNOS4X12_GPIO_X07, S5P_GPIO_PULL_NONE); + /* IF_PMIC_IRQ*/ + gpio_set_pull(EXYNOS4X12_GPIO_X15, S5P_GPIO_PULL_NONE); + /* VOL_UP */ + gpio_set_pull(EXYNOS4X12_GPIO_X20, S5P_GPIO_PULL_NONE); + /* VOL_DOWN */ + gpio_set_pull(EXYNOS4X12_GPIO_X21, S5P_GPIO_PULL_NONE); + /* FUEL_ALERT */ + gpio_set_pull(EXYNOS4X12_GPIO_X23, S5P_GPIO_PULL_NONE); + /* ADC_INT */ + gpio_set_pull(EXYNOS4X12_GPIO_X24, S5P_GPIO_PULL_NONE); + /* nPOWER */ + gpio_set_pull(EXYNOS4X12_GPIO_X27, S5P_GPIO_PULL_NONE); + /* WPC_INT */ + gpio_set_pull(EXYNOS4X12_GPIO_X30, S5P_GPIO_PULL_NONE); + /* OK_KEY */ + gpio_set_pull(EXYNOS4X12_GPIO_X35, S5P_GPIO_PULL_NONE); + /* HDMI_HPD */ + gpio_set_pull(EXYNOS4X12_GPIO_X37, S5P_GPIO_PULL_NONE); + } else { + /* eMMC reset */ + gpio_request(EXYNOS4X12_GPIO_K12, "eMMC Reset"); + + gpio_cfg_pin(EXYNOS4X12_GPIO_K12, S5P_GPIO_FUNC(0x1)); + gpio_set_pull(EXYNOS4X12_GPIO_K12, S5P_GPIO_PULL_NONE); + gpio_set_drv(EXYNOS4X12_GPIO_K12, S5P_GPIO_DRV_4X); + + /* Enable FAN (Odroid U3) */ + gpio_request(EXYNOS4X12_GPIO_D00, "FAN Control"); + + gpio_set_pull(EXYNOS4X12_GPIO_D00, S5P_GPIO_PULL_UP); + gpio_set_drv(EXYNOS4X12_GPIO_D00, S5P_GPIO_DRV_4X); + gpio_direction_output(EXYNOS4X12_GPIO_D00, 1); + + /* OTG Vbus output (Odroid U3+) */ + gpio_request(EXYNOS4X12_GPIO_L20, "OTG Vbus"); + + gpio_set_pull(EXYNOS4X12_GPIO_L20, S5P_GPIO_PULL_NONE); + gpio_set_drv(EXYNOS4X12_GPIO_L20, S5P_GPIO_DRV_4X); + gpio_direction_output(EXYNOS4X12_GPIO_L20, 0); + + /* OTG INT (Odroid U3+) */ + gpio_request(EXYNOS4X12_GPIO_X31, "OTG INT"); + + gpio_set_pull(EXYNOS4X12_GPIO_X31, S5P_GPIO_PULL_UP); + gpio_set_drv(EXYNOS4X12_GPIO_X31, S5P_GPIO_DRV_4X); + gpio_direction_input(EXYNOS4X12_GPIO_X31); + + /* Blue LED (Odroid X2/U2/U3) */ + gpio_request(EXYNOS4X12_GPIO_C10, "Blue LED"); + + gpio_direction_output(EXYNOS4X12_GPIO_C10, 0); + +#ifdef CONFIG_CMD_USB + /* USB3503A Reference frequency */ + gpio_request(EXYNOS4X12_GPIO_X30, "USB3503A RefFreq"); + + /* USB3503A Connect */ + gpio_request(EXYNOS4X12_GPIO_X34, "USB3503A Connect"); + + /* USB3503A Reset */ + gpio_request(EXYNOS4X12_GPIO_X35, "USB3503A Reset"); +#endif + } +} + +static int pmic_init_max77686(void) +{ + struct pmic *p = pmic_get("MAX77686_PMIC"); + + if (!p) + return -ENODEV; + + if (pmic_probe(p)) + return -ENODEV; + + if (board_is_trats2()) { + /* BUCK/LDO Output Voltage */ + max77686_set_ldo_voltage(p, 21, 2800000); /* LDO21 VTF_2.8V */ + max77686_set_ldo_voltage(p, 23, 3300000); /* LDO23 TSP_AVDD_3.3V*/ + max77686_set_ldo_voltage(p, 24, 1800000); /* LDO24 TSP_VDD_1.8V */ + + /* BUCK/LDO Output Mode */ + max77686_set_buck_mode(p, 1, OPMODE_STANDBY); /* BUCK1 VMIF_1.1V_AP */ + max77686_set_buck_mode(p, 2, OPMODE_ON); /* BUCK2 VARM_1.0V_AP */ + max77686_set_buck_mode(p, 3, OPMODE_ON); /* BUCK3 VINT_1.0V_AP */ + max77686_set_buck_mode(p, 4, OPMODE_ON); /* BUCK4 VG3D_1.0V_AP */ + max77686_set_buck_mode(p, 5, OPMODE_ON); /* BUCK5 VMEM_1.2V_AP */ + max77686_set_buck_mode(p, 6, OPMODE_ON); /* BUCK6 VCC_SUB_1.35V*/ + max77686_set_buck_mode(p, 7, OPMODE_ON); /* BUCK7 VCC_SUB_2.0V */ + max77686_set_buck_mode(p, 8, OPMODE_OFF); /* VMEM_VDDF_2.85V */ + max77686_set_buck_mode(p, 9, OPMODE_OFF); /* CAM_ISP_CORE_1.2V*/ + + max77686_set_ldo_mode(p, 1, OPMODE_LPM); /* LDO1 VALIVE_1.0V_AP*/ + max77686_set_ldo_mode(p, 2, OPMODE_STANDBY); /* LDO2 VM1M2_1.2V_AP */ + max77686_set_ldo_mode(p, 3, OPMODE_LPM); /* LDO3 VCC_1.8V_AP */ + max77686_set_ldo_mode(p, 4, OPMODE_LPM); /* LDO4 VCC_2.8V_AP */ + max77686_set_ldo_mode(p, 5, OPMODE_OFF); /* LDO5_VCC_1.8V_IO */ + max77686_set_ldo_mode(p, 6, OPMODE_STANDBY); /* LDO6 VMPLL_1.0V_AP */ + max77686_set_ldo_mode(p, 7, OPMODE_STANDBY); /* LDO7 VPLL_1.0V_AP */ + max77686_set_ldo_mode(p, 8, OPMODE_LPM); /* LDO8 VMIPI_1.0V_AP */ + max77686_set_ldo_mode(p, 9, OPMODE_OFF); /* CAM_ISP_MIPI_1.2*/ + max77686_set_ldo_mode(p, 10, OPMODE_LPM); /* LDO10 VMIPI_1.8V_AP*/ + max77686_set_ldo_mode(p, 11, OPMODE_STANDBY); /* LDO11 VABB1_1.8V_AP*/ + max77686_set_ldo_mode(p, 12, OPMODE_LPM); /* LDO12 VUOTG_3.0V_AP*/ + max77686_set_ldo_mode(p, 13, OPMODE_OFF); /* LDO13 VC2C_1.8V_AP */ + max77686_set_ldo_mode(p, 14, OPMODE_STANDBY); /* VABB02_1.8V_AP */ + max77686_set_ldo_mode(p, 15, OPMODE_STANDBY); /* LDO15 VHSIC_1.0V_AP*/ + max77686_set_ldo_mode(p, 16, OPMODE_STANDBY); /* LDO16 VHSIC_1.8V_AP*/ + max77686_set_ldo_mode(p, 17, OPMODE_OFF); /* CAM_SENSOR_CORE_1.2*/ + max77686_set_ldo_mode(p, 18, OPMODE_OFF); /* CAM_ISP_SEN_IO_1.8V*/ + max77686_set_ldo_mode(p, 19, OPMODE_OFF); /* LDO19 VT_CAM_1.8V */ + max77686_set_ldo_mode(p, 20, OPMODE_ON); /* LDO20 VDDQ_PRE_1.8V*/ + max77686_set_ldo_mode(p, 21, OPMODE_OFF); /* LDO21 VTF_2.8V */ + max77686_set_ldo_mode(p, 22, OPMODE_OFF); /* LDO22 VMEM_VDD_2.8V*/ + max77686_set_ldo_mode(p, 23, OPMODE_OFF); /* LDO23 TSP_AVDD_3.3V*/ + max77686_set_ldo_mode(p, 24, OPMODE_OFF); /* LDO24 TSP_VDD_1.8V */ + max77686_set_ldo_mode(p, 25, OPMODE_OFF); /* LDO25 VCC_3.3V_LCD */ + max77686_set_ldo_mode(p, 26, OPMODE_OFF); /*LDO26 VCC_3.0V_MOTOR*/ + } else { + /* Set LDO Voltage */ + max77686_set_ldo_voltage(p, 20, 1800000); /* LDO20 eMMC */ + max77686_set_ldo_voltage(p, 21, 2800000); /* LDO21 SD */ + max77686_set_ldo_voltage(p, 22, 2800000); /* LDO22 eMMC */ + } + + return 0; +} + +#ifdef CONFIG_SYS_I2C_INIT_BOARD +static void board_init_i2c(void) +{ + int i2c_id; + + if (board_is_trats2()) { + i2c_id = PERIPH_ID_I2C7; + + /* I2C_8 */ + gpio_request(EXYNOS4X12_GPIO_F14, "i2c8_clk"); + gpio_request(EXYNOS4X12_GPIO_F15, "i2c8_data"); + gpio_direction_output(EXYNOS4X12_GPIO_F14, 1); + gpio_direction_output(EXYNOS4X12_GPIO_F15, 1); + + /* I2C_9 */ + gpio_request(EXYNOS4X12_GPIO_M21, "i2c9_clk"); + gpio_request(EXYNOS4X12_GPIO_M20, "i2c9_data"); + gpio_direction_output(EXYNOS4X12_GPIO_M21, 1); + gpio_direction_output(EXYNOS4X12_GPIO_M20, 1); + } else { + i2c_id = PERIPH_ID_I2C0; + } + + if (exynos_pinmux_config(i2c_id, PINMUX_FLAG_NONE)) + debug("I2C%d not configured\n", i2c_id - PERIPH_ID_I2C0); +} +#endif + +#ifdef CONFIG_SYS_I2C_SOFT +int get_soft_i2c_scl_pin(void) +{ + if (I2C_ADAP_HWNR) + return EXYNOS4X12_GPIO_M21; /* I2C9 */ + else + return EXYNOS4X12_GPIO_F14; /* I2C8 */ +} + +int get_soft_i2c_sda_pin(void) +{ + if (I2C_ADAP_HWNR) + return EXYNOS4X12_GPIO_M20; /* I2C9 */ + else + return EXYNOS4X12_GPIO_F15; /* I2C8 */ +} +#endif + +int exynos_early_init_f(void) +{ + board_clock_init(); + + return 0; +} + +int exynos_init(void) +{ + struct exynos4_power *pwr = + (struct exynos4_power *)samsung_get_base_power(); + + gd->bd->bi_arch_number = board_arch_num[gd->board_type]; + + board_gpio_init(); + + if (!board_is_trats2()) + return 0; + + writel(0, &pwr->inform4); + writel(0, &pwr->inform5); + + return 0; +} + +int exynos_power_init(void) +{ +#ifdef CONFIG_SYS_I2C_INIT_BOARD + board_init_i2c(); +#endif + /* bus number taken from FDT */ + pmic_init(0); + pmic_init_max77686(); + + if (!board_is_trats2()) + goto done; + + /* I2C adapter 10 - bus name soft1 */ + pmic_init_max77693(I2C_10); + /* I2C adapter 10 - bus name soft1 */ + power_muic_init(I2C_10); + /* I2C adapter 9 - bus name soft0 */ + power_fg_init(I2C_9); + power_bat_init(0); + + p_chrg = pmic_get("MAX77693_PMIC"); + if (!p_chrg) { + puts("MAX77693_PMIC: Not found\n"); + return -ENODEV; + } + + p_muic = pmic_get("MAX77693_MUIC"); + if (!p_muic) { + puts("MAX77693_MUIC: Not found\n"); + return -ENODEV; + } + + p_fg = pmic_get("MAX77693_FG"); + if (!p_fg) { + puts("MAX17042_FG: Not found\n"); + return -ENODEV; + } + + if (p_chrg->chrg->chrg_bat_present(p_chrg) == 0) + puts("No battery detected\n"); + + p_bat = pmic_get("BAT_TRATS2"); + if (!p_bat) { + puts("BAT_TRATS2: Not found\n"); + return -ENODEV; + } + + p_fg->parent = p_bat; + p_chrg->parent = p_bat; + p_muic->parent = p_bat; + +#ifdef CONFIG_INTERACTIVE_CHARGER + p_bat->low_power_mode = board_low_power_mode; +#endif + p_bat->pbat->battery_init(p_bat, p_fg, p_chrg, p_muic); + + pbat = p_bat->pbat; + +done: + power_init_done = 1; + + return 0; +} + +#ifdef CONFIG_USB_GADGET +static int s5pc210_phy_control(int on) +{ + struct pmic *p_pmic; + + p_pmic = pmic_get("MAX77686_PMIC"); + if (!p_pmic) + return -ENODEV; + + if (pmic_probe(p_pmic)) + return -1; + + if (on) + return max77686_set_ldo_mode(p_pmic, 12, OPMODE_ON); + else + return max77686_set_ldo_mode(p_pmic, 12, OPMODE_LPM); +} + +struct s3c_plat_otg_data s5pc210_otg_data = { + .phy_control = s5pc210_phy_control, + .regs_phy = EXYNOS4X12_USBPHY_BASE, + .regs_otg = EXYNOS4X12_USBOTG_BASE, + .usb_phy_ctrl = EXYNOS4X12_USBPHY_CONTROL, + .usb_flags = PHY0_SLEEP, +}; +#endif + +#if defined(CONFIG_USB_GADGET) || defined(CONFIG_CMD_USB) + +int board_usb_init(int index, enum usb_init_type init) +{ +#ifdef CONFIG_CMD_USB + struct pmic *p_pmic; + + /* Set Ref freq 0 => 24MHz, 1 => 26MHz*/ + /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */ + if (gd->board_type == ODROID_TYPE_U3) + gpio_direction_output(EXYNOS4X12_GPIO_X30, 0); + else + gpio_direction_output(EXYNOS4X12_GPIO_X30, 1); + + /* Disconnect, Reset, Connect */ + gpio_direction_output(EXYNOS4X12_GPIO_X34, 0); + gpio_direction_output(EXYNOS4X12_GPIO_X35, 0); + gpio_direction_output(EXYNOS4X12_GPIO_X35, 1); + gpio_direction_output(EXYNOS4X12_GPIO_X34, 1); + + /* Power off and on BUCK8 for LAN9730 */ + debug("LAN9730 - Turning power buck 8 OFF and ON.\n"); + + p_pmic = pmic_get("MAX77686_PMIC"); + if (p_pmic && !pmic_probe(p_pmic)) { + max77686_set_buck_voltage(p_pmic, 8, 750000); + max77686_set_buck_voltage(p_pmic, 8, 3300000); + } + +#endif + + debug("USB_udc_probe\n"); + return s3c_udc_probe(&s5pc210_otg_data); +} +#endif + +/* + * LCD + */ +#ifdef CONFIG_LCD +int mipi_power(void) +{ + struct pmic *p; + + if (!board_is_trats2()) + return 0; + + p = pmic_get("MAX77686_PMIC"); + if (!p) + return -ENODEV; + + /* LDO8 VMIPI_1.0V_AP */ + max77686_set_ldo_mode(p, 8, OPMODE_ON); + /* LDO10 VMIPI_1.8V_AP */ + max77686_set_ldo_mode(p, 10, OPMODE_ON); + + return 0; +} + +void exynos_lcd_power_on(void) +{ + struct pmic *p; + + if (!board_is_trats2()) + return; + + p = pmic_get("MAX77686_PMIC"); + if (!p) + return; + + /* LCD_2.2V_EN: GPC0[1] */ + gpio_request(EXYNOS4X12_GPIO_C01, "lcd_2v2_en"); + gpio_set_pull(EXYNOS4X12_GPIO_C01, S5P_GPIO_PULL_UP); + gpio_direction_output(EXYNOS4X12_GPIO_C01, 1); + + /* LDO25 VCC_3.1V_LCD */ + pmic_probe(p); + max77686_set_ldo_voltage(p, 25, 3100000); + max77686_set_ldo_mode(p, 25, OPMODE_LPM); +} + +void exynos_reset_lcd(void) +{ + if (!board_is_trats2()) + return; + + /* reset lcd */ + gpio_request(EXYNOS4X12_GPIO_F21, "lcd_reset"); + gpio_direction_output(EXYNOS4X12_GPIO_F21, 0); + udelay(10); + gpio_set_value(EXYNOS4X12_GPIO_F21, 1); +} + +void exynos_lcd_misc_init(vidinfo_t *vid) +{ + if (!board_is_trats2()) + return; +#ifdef CONFIG_TIZEN + get_tizen_logo_info(vid); +#endif +#ifdef CONFIG_S6E8AX0 + s6e8ax0_init(); +#endif +} +#endif /* LCD */ + +void low_clock_mode(void) +{ + struct exynos4x12_clock *clk = (struct exynos4x12_clock *) + samsung_get_base_clock(); + + unsigned int cfg_apll_con0; + unsigned int cfg_src_cpu; + unsigned int cfg_div_cpu0; + unsigned int cfg_div_cpu1; + unsigned int clk_gate_cfg; + + /* Turn off unnecessary clocks */ + clk_gate_cfg = 0x0; + writel(clk_gate_cfg, &clk->gate_ip_image); /* IMAGE */ + writel(clk_gate_cfg, &clk->gate_ip_cam); /* CAM */ + writel(clk_gate_cfg, &clk->gate_ip_tv); /* TV */ + writel(clk_gate_cfg, &clk->gate_ip_mfc); /* MFC */ + writel(clk_gate_cfg, &clk->gate_ip_g3d); /* G3D */ + writel(clk_gate_cfg, &clk->gate_ip_gps); /* GPS */ + writel(clk_gate_cfg, &clk->gate_ip_isp1); /* ISP1 */ + + /* + * Set CMU_CPU clocks src to MPLL + * Bit values: 0 ; 1 + * MUX_APLL_SEL: FIN_PLL; FOUT_APLL + * MUX_CORE_SEL: MOUT_APLL; SCLK_MPLL + * MUX_HPM_SEL: MOUT_APLL; SCLK_MPLL_USER_C + * MUX_MPLL_USER_SEL_C: FIN_PLL; SCLK_MPLL + */ + cfg_src_cpu = MUX_APLL_SEL(1) | MUX_CORE_SEL(1) | MUX_HPM_SEL(1) | + MUX_MPLL_USER_SEL_C(1); + writel(cfg_src_cpu, &clk->src_cpu); + + /* Disable APLL */ + cfg_apll_con0 = readl(&clk->apll_con0); + writel(cfg_apll_con0 & ~PLL_ENABLE(1), &clk->apll_con0); + + /* Set APLL to 200MHz */ + cfg_apll_con0 = SDIV(2) | PDIV(3) | MDIV(100) | FSEL(1) | PLL_ENABLE(1); + writel(cfg_apll_con0, &clk->apll_con0); + + /* Wait for PLL to be locked */ + while (!(readl(&clk->apll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Set CMU_CPU clock src to APLL */ + cfg_src_cpu = MUX_APLL_SEL(1) | MUX_CORE_SEL(0) | MUX_HPM_SEL(0) | + MUX_MPLL_USER_SEL_C(0); + writel(cfg_src_cpu, &clk->src_cpu); + + /* Wait for MUX ready status */ + while (readl(&clk->src_cpu) & MUX_STAT_CPU_CHANGING) + continue; + + /* + * Set dividers for MOUTcore = 200 MHz + * coreout = MOUT / (ratio + 1) = 200 MHz + * corem0 = armclk / (ratio + 1) = 200 MHz + * corem1 = armclk / (ratio + 1) = 200 MHz + * periph = armclk / (ratio + 1) = 200 MHz + * atbout = MOUT / (ratio + 1) = 200 MHz + * pclkdbgout = atbout / (ratio + 1) = 200 MHz + * sclkapll = MOUTapll / (ratio + 1) = 50 MHz + * armclk = core_out / (ratio + 1) = 200 MHz + */ + cfg_div_cpu0 = CORE_RATIO(0) | COREM0_RATIO(0) | COREM1_RATIO(0) | + PERIPH_RATIO(0) | ATB_RATIO(0) | PCLK_DBG_RATIO(1) | + APLL_RATIO(3) | CORE2_RATIO(0); + writel(cfg_div_cpu0, &clk->div_cpu0); + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_cpu0) & DIV_STAT_CPU0_CHANGING) + continue; + + /* + * For MOUThpm = 200 MHz (MOUTapll) + * doutcopy = MOUThpm / (ratio + 1) = 100 + * sclkhpm = doutcopy / (ratio + 1) = 100 + * cores_out = armclk / (ratio + 1) = 200 + */ + cfg_div_cpu1 = COPY_RATIO(1) | HPM_RATIO(0) | CORES_RATIO(0); + writel(cfg_div_cpu1, &clk->div_cpu1); /* DIV_CPU1 */ + + /* Wait for divider ready status */ + while (readl(&clk->div_stat_cpu1) & DIV_STAT_CPU1_CHANGING) + continue; +} + +#ifdef CONFIG_INTERACTIVE_CHARGER +static int low_power_mode_set; + +void board_low_power_mode(void) +{ + struct exynos4x12_power *pwr = (struct exynos4x12_power *) + samsung_get_base_power(); + + unsigned int pwr_core_cfg = 0x0; + unsigned int pwr_cfg = 0x0; + + /* Set low power mode only once */ + if (low_power_mode_set) + return; + + /* Power down CORES: 1, 2, 3 */ + /* LOCAL_PWR_CFG [1:0] 0x3 EN, 0x0 DIS */ + writel(pwr_core_cfg, &pwr->arm_core1_configuration); + writel(pwr_core_cfg, &pwr->arm_core2_configuration); + writel(pwr_core_cfg, &pwr->arm_core3_configuration); + + /* Turn off unnecessary power domains */ + writel(pwr_cfg, &pwr->xxti_configuration); /* XXTI */ + writel(pwr_cfg, &pwr->cam_configuration); /* CAM */ + writel(pwr_cfg, &pwr->tv_configuration); /* TV */ + writel(pwr_cfg, &pwr->mfc_configuration); /* MFC */ + writel(pwr_cfg, &pwr->g3d_configuration); /* G3D */ + writel(pwr_cfg, &pwr->gps_configuration); /* GPS */ + writel(pwr_cfg, &pwr->gps_alive_configuration); /* GPS_ALIVE */ + + /* Set CPU clock to 200MHz */ + low_clock_mode(); + + low_power_mode_set = 1; +} +#endif + +#ifdef CONFIG_CMD_POWEROFF +void board_poweroff(void) +{ + unsigned int val; + struct exynos4x12_power *power = + (struct exynos4x12_power *)samsung_get_base_power(); + + val = readl(&power->ps_hold_control); + val |= EXYNOS_PS_HOLD_CONTROL_EN_OUTPUT; /* set to output */ + val &= ~EXYNOS_PS_HOLD_CONTROL_DATA_HIGH; /* set state to low */ + writel(val, &power->ps_hold_control); + + while (1); + /* Should not reach here */ +} +#endif + +/* Functions for interactive charger in board/samsung/common/misc.c */ +#ifdef CONFIG_INTERACTIVE_CHARGER +int charger_enable(void) +{ + if (!power_init_done) { + if (exynos_power_init()) { + puts("Can't init board power subsystem"); + return -EIO; + } + } + + if (!pbat) { + puts("No such device!\n"); + return -ENODEV; + } + + if (!pbat->battery_charge) { + puts("Can't enable charger\n"); + return -ENODEV; + } + + /* Enable charger */ + if (pbat->battery_charge(p_bat)) { + puts("Charger enable error\n"); + return -EIO; + } + + return 0; +} + +int charger_type(void) +{ + if (!power_init_done) { + if (exynos_power_init()) { + puts("Can't init board power subsystem"); + return -EIO; + } + } + + if (!p_muic) { + puts("No such device!\n"); + return -ENODEV; + } + + if (!p_muic->chrg->chrg_type) { + puts("Can't get charger type\n"); + return -ENODEV; + } + + return p_muic->chrg->chrg_type(p_muic); +} + +int battery_present(void) +{ + if (!power_init_done) { + if (exynos_power_init()) { + puts("Can't init board power subsystem"); + return 0; + } + } + + if (!p_chrg) { + puts("No such device!\n"); + return 0; + } + + if (!p_chrg->chrg->chrg_bat_present) { + puts("Can't get battery state\n"); + return 0;; + } + + if (!p_chrg->chrg->chrg_bat_present(p_chrg)) { + puts("Battery not present.\n"); + return 0; + } + + return 1; +} + +int battery_state(unsigned int *soc) +{ + struct battery *bat = pbat->bat; + + if (!power_init_done) { + if (exynos_power_init()) { + printf("Can't init board power subsystem"); + return -EIO; + } + } + + if (!p_fg) { + puts("No such device!\n"); + return -ENODEV; + } + + if (!p_fg->fg->fg_battery_update) { + puts("Can't update battery state\n"); + return -EIO; + } + + /* Check battery state */ + if (p_fg->fg->fg_battery_update(p_fg, p_bat)) { + puts("Battery update error\n"); + return -EIO; + } + + debug("[BAT]:\n#state:%u\n#soc:%3.1u\n#vcell:%u\n", bat->state, + bat->state_of_chrg, + bat->voltage_uV); + + *soc = bat->state_of_chrg; + + return 0; +} +#endif |