/* * Lowlevel setup for EXYNOS5 based board * * Copyright (C) 2013 Samsung Electronics * Rajeshwari Shinde * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include "common_setup.h" #include "exynos5_setup.h" /* These are the things we can do during low-level init */ enum { DO_WAKEUP = 1 << 0, DO_CLOCKS = 1 << 1, DO_MEM_RESET = 1 << 2, DO_UART = 1 << 3, DO_POWER = 1 << 4, }; #ifdef CONFIG_EXYNOS5420 /* * Pointer to this function is stored in iRam which is used * for jump and power down of a specific core. */ static void power_down_core(void) { uint32_t tmp, core_id, core_config; /* Get the unique core id */ /* * Multiprocessor Affinity Register * [11:8] Cluster ID * [1:0] CPU ID */ mrc_mpafr(core_id); tmp = core_id & 0x3; core_id = (core_id >> 6) & ~3; core_id |= tmp; core_id &= 0x3f; /* Set the status of the core to low */ core_config = (core_id * CPU_CONFIG_STATUS_OFFSET); core_config += EXYNOS5420_CPU_CONFIG_BASE; writel(0x0, core_config); /* Core enter WFI */ wfi(); } /* * Configurations for secondary cores are inapt at this stage. * Reconfigure secondary cores. Shutdown and change the status * of all cores except the primary core. */ static void secondary_cores_configure(void) { uint32_t core_id; /* Store jump address for power down of secondary cores */ writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4); /* Need all core power down check */ dsb(); sev(); /* * Power down all cores(secondary) while primary core must * wait for all cores to go down. */ for (core_id = 1; core_id != CONFIG_CORE_COUNT; core_id++) { while ((readl(EXYNOS5420_CPU_STATUS_BASE + (core_id * CPU_CONFIG_STATUS_OFFSET)) & 0xff) != 0x0) { isb(); sev(); } isb(); } } #endif int do_lowlevel_init(void) { uint32_t reset_status; int actions = 0; arch_cpu_init(); #ifdef CONFIG_EXYNOS5420 /* Reconfigure secondary cores */ secondary_cores_configure(); #endif reset_status = get_reset_status(); switch (reset_status) { case S5P_CHECK_SLEEP: actions = DO_CLOCKS | DO_WAKEUP; break; case S5P_CHECK_DIDLE: case S5P_CHECK_LPA: actions = DO_WAKEUP; break; default: /* This is a normal boot (not a wake from sleep) */ actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER; } if (actions & DO_POWER) set_ps_hold_ctrl(); if (actions & DO_CLOCKS) { system_clock_init(); mem_ctrl_init(actions & DO_MEM_RESET); tzpc_init(); } return actions & DO_WAKEUP; }