Home | History | Annotate | Download | only in mach-exynos
      1 /*
      2  * Lowlevel setup for EXYNOS5 based board
      3  *
      4  * Copyright (C) 2013 Samsung Electronics
      5  * Rajeshwari Shinde <rajeshwari.s (at) samsung.com>
      6  *
      7  * See file CREDITS for list of people who contributed to this
      8  * project.
      9  *
     10  * This program is free software; you can redistribute it and/or
     11  * modify it under the terms of the GNU General Public License as
     12  * published by the Free Software Foundation; either version 2 of
     13  * the License, or (at your option) any later version.
     14  *
     15  * This program is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  * GNU General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License
     21  * along with this program; if not, write to the Free Software
     22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     23  * MA 02111-1307 USA
     24  */
     25 
     26 #include <common.h>
     27 #include <config.h>
     28 #include <debug_uart.h>
     29 #include <asm/arch/cpu.h>
     30 #include <asm/arch/dmc.h>
     31 #include <asm/arch/power.h>
     32 #include <asm/arch/tzpc.h>
     33 #include <asm/arch/periph.h>
     34 #include <asm/arch/pinmux.h>
     35 #include <asm/arch/system.h>
     36 #include <asm/armv7.h>
     37 #include "common_setup.h"
     38 #include "exynos5_setup.h"
     39 
     40 /* These are the things we can do during low-level init */
     41 enum {
     42 	DO_WAKEUP	= 1 << 0,
     43 	DO_CLOCKS	= 1 << 1,
     44 	DO_MEM_RESET	= 1 << 2,
     45 	DO_UART		= 1 << 3,
     46 	DO_POWER	= 1 << 4,
     47 };
     48 
     49 #ifdef CONFIG_EXYNOS5420
     50 /*
     51  * Power up secondary CPUs.
     52  */
     53 static void secondary_cpu_start(void)
     54 {
     55 	v7_enable_smp(EXYNOS5420_INFORM_BASE);
     56 	svc32_mode_en();
     57 	branch_bx(CONFIG_EXYNOS_RELOCATE_CODE_BASE);
     58 }
     59 
     60 /*
     61  * This is the entry point of hotplug-in and
     62  * cluster switching.
     63  */
     64 static void low_power_start(void)
     65 {
     66 	uint32_t val, reg_val;
     67 
     68 	reg_val = readl(EXYNOS5420_SPARE_BASE);
     69 	if (reg_val != CPU_RST_FLAG_VAL) {
     70 		writel(0x0, CONFIG_LOWPOWER_FLAG);
     71 		branch_bx(0x0);
     72 	}
     73 
     74 	reg_val = readl(CONFIG_PHY_IRAM_BASE + 0x4);
     75 	if (reg_val != (uint32_t)&low_power_start) {
     76 		/* Store jump address as low_power_start if not present */
     77 		writel((uint32_t)&low_power_start, CONFIG_PHY_IRAM_BASE + 0x4);
     78 		dsb();
     79 		sev();
     80 	}
     81 
     82 	/* Set the CPU to SVC32 mode */
     83 	svc32_mode_en();
     84 
     85 #ifndef CONFIG_SYS_L2CACHE_OFF
     86 	/* Read MIDR for Primary Part Number */
     87 	mrc_midr(val);
     88 	val = (val >> 4);
     89 	val &= 0xf;
     90 
     91 	if (val == 0xf) {
     92 		configure_l2_ctlr();
     93 		configure_l2_actlr();
     94 		v7_enable_l2_hazard_detect();
     95 	}
     96 #endif
     97 
     98 	/* Invalidate L1 & TLB */
     99 	val = 0x0;
    100 	mcr_tlb(val);
    101 	mcr_icache(val);
    102 
    103 	/* Disable MMU stuff and caches */
    104 	mrc_sctlr(val);
    105 
    106 	val &= ~((0x2 << 12) | 0x7);
    107 	val |= ((0x1 << 12) | (0x8 << 8) | 0x2);
    108 	mcr_sctlr(val);
    109 
    110 	/* CPU state is hotplug or reset */
    111 	secondary_cpu_start();
    112 
    113 	/* Core should not enter into WFI here */
    114 	wfi();
    115 }
    116 
    117 /*
    118  * Pointer to this function is stored in iRam which is used
    119  * for jump and power down of a specific core.
    120  */
    121 static void power_down_core(void)
    122 {
    123 	uint32_t tmp, core_id, core_config;
    124 
    125 	/* Get the unique core id */
    126 	/*
    127 	 * Multiprocessor Affinity Register
    128 	 * [11:8]	Cluster ID
    129 	 * [1:0]	CPU ID
    130 	 */
    131 	mrc_mpafr(core_id);
    132 	tmp = core_id & 0x3;
    133 	core_id = (core_id >> 6) & ~3;
    134 	core_id |= tmp;
    135 	core_id &= 0x3f;
    136 
    137 	/* Set the status of the core to low */
    138 	core_config = (core_id * CPU_CONFIG_STATUS_OFFSET);
    139 	core_config += EXYNOS5420_CPU_CONFIG_BASE;
    140 	writel(0x0, core_config);
    141 
    142 	/* Core enter WFI */
    143 	wfi();
    144 }
    145 
    146 /*
    147  * Configurations for secondary cores are inapt at this stage.
    148  * Reconfigure secondary cores. Shutdown and change the status
    149  * of all cores except the primary core.
    150  */
    151 static void secondary_cores_configure(void)
    152 {
    153 	/* Clear secondary boot iRAM base */
    154 	writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C));
    155 
    156 	/* set lowpower flag and address */
    157 	writel(CPU_RST_FLAG_VAL, CONFIG_LOWPOWER_FLAG);
    158 	writel((uint32_t)&low_power_start, CONFIG_LOWPOWER_ADDR);
    159 	writel(CPU_RST_FLAG_VAL, EXYNOS5420_SPARE_BASE);
    160 	/* Store jump address for power down */
    161 	writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4);
    162 
    163 	/* Need all core power down check */
    164 	dsb();
    165 	sev();
    166 }
    167 
    168 extern void relocate_wait_code(void);
    169 #endif
    170 
    171 int do_lowlevel_init(void)
    172 {
    173 	uint32_t reset_status;
    174 	int actions = 0;
    175 
    176 	arch_cpu_init();
    177 
    178 #if !defined(CONFIG_SYS_L2CACHE_OFF) && defined(CONFIG_EXYNOS5420)
    179 	/*
    180 	 * Init L2 cache parameters here for use by boot and resume
    181 	 *
    182 	 * These are here instead of in v7_outer_cache_enable() so that the
    183 	 * L2 cache settings get properly set even at resume time or if we're
    184 	 * running U-Boot with the cache off.  The kernel still needs us to
    185 	 * set these for it.
    186 	 */
    187 	configure_l2_ctlr();
    188 	configure_l2_actlr();
    189 	dsb();
    190 	isb();
    191 
    192 	relocate_wait_code();
    193 
    194 	/* Reconfigure secondary cores */
    195 	secondary_cores_configure();
    196 #endif
    197 
    198 	reset_status = get_reset_status();
    199 
    200 	switch (reset_status) {
    201 	case S5P_CHECK_SLEEP:
    202 		actions = DO_CLOCKS | DO_WAKEUP;
    203 		break;
    204 	case S5P_CHECK_DIDLE:
    205 	case S5P_CHECK_LPA:
    206 		actions = DO_WAKEUP;
    207 		break;
    208 	default:
    209 		/* This is a normal boot (not a wake from sleep) */
    210 		actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER;
    211 	}
    212 
    213 	if (actions & DO_POWER)
    214 		set_ps_hold_ctrl();
    215 
    216 	if (actions & DO_CLOCKS) {
    217 		system_clock_init();
    218 #ifdef CONFIG_DEBUG_UART
    219 #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL_SUPPORT)) || \
    220     !defined(CONFIG_SPL_BUILD)
    221 		exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
    222 		debug_uart_init();
    223 #endif
    224 #endif
    225 		mem_ctrl_init(actions & DO_MEM_RESET);
    226 		tzpc_init();
    227 	}
    228 
    229 	return actions & DO_WAKEUP;
    230 }
    231