aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/samsung/exynos5420/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/samsung/exynos5420/smp.c')
-rw-r--r--src/cpu/samsung/exynos5420/smp.c307
1 files changed, 0 insertions, 307 deletions
diff --git a/src/cpu/samsung/exynos5420/smp.c b/src/cpu/samsung/exynos5420/smp.c
deleted file mode 100644
index 6fc2fb01ea..0000000000
--- a/src/cpu/samsung/exynos5420/smp.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 Google Inc.
- * Copyright (C) 2012 Samsung Electronics
- *
- * 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; version 2 of the License.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <types.h>
-#include <arch/cpu.h>
-#include <arch/io.h>
-
-#include "cpu.h"
-#include "power.h"
-
-/* ACTLR, L2CTLR L2ACTLR constants used in SMP core power up. */
-
-#define ACTLR_SMP (1 << 6)
-
-#define L2CTLR_ECC_PARITY (1 << 21)
-#define L2CTLR_DATA_RAM_LATENCY_MASK (7 << 0)
-#define L2CTLR_TAG_RAM_LATENCY_MASK (7 << 6)
-#define L2CTLR_DATA_RAM_LATENCY_CYCLES_3 (2 << 0)
-#define L2CTLR_TAG_RAM_LATENCY_CYCLES_3 (2 << 6)
-
-#define L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL (1 << 3)
-#define L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT (1 << 7)
-#define L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE (1 << 27)
-
-/* Part number in CPU ID (MPIDR). */
-#define PART_NUMBER_CORTEX_A15 (0xc0f)
-
-/* State of CPU cores in Exynos 5420. */
-#define CORE_STATE_RESET (1 << 0)
-#define CORE_STATE_SECONDARY_RESET (1 << 1)
-#define CORE_STATE_SWITCH_CLUSTER (1 << 4)
-
-/* The default address to re-power on a code. */
-#define CORE_RESET_INIT_ADDRESS ((void*)0x00000000)
-
-/* Vectors in BL1 (0x02020000 = base of iRAM). */
-#define VECTOR_CORE_SEV_HANDLER ((void*)(intptr_t)0x02020004)
-#define VECTOR_LOW_POWER_FLAG ((void*)(intptr_t)0x02020028)
-#define VECTOR_LOW_POWER_ADDRESS ((void*)(intptr_t)0x0202002C)
-
-/* The data structure for the "CPU state" memory page (shared with kernel)
- * controlling cores in active cluster. Kernel will put starting address for one
- * core in "hotplug_address" before power on. Note the address is hard-coded in
- * kernel (EXYNOS5420_PA_SYSRAM_NS = 0x02073000). */
-volatile struct exynos5420_cpu_states
-{
- uint32_t _reserved[2]; /* RESV, +0x00 */
- uint32_t resume_address; /* REG0, +0x08 */
- uint32_t resume_flag; /* REG1, +0x0C */
- uint32_t _reg2; /* REG2, +0x10 */
- uint32_t _reg3; /* REG3, +0x14 */
- uint32_t switch_address; /* REG4, +0x18, cluster switching */
- uint32_t hotplug_address; /* REG5, +0x1C, core hotplug */
- uint32_t _reg6; /* REG6, +0x20 */
- uint32_t c2_address; /* REG7, +0x24, C2 state change */
-
- /* Managed per core status for active cluster, offset: +0x28~0x38 */
- uint32_t cpu_states[4];
-
- /* Managed per core GIC status for active cluster, offset: 0x38~0x48 */
- uint32_t cpu_gic_states[4];
-} *exynos_cpu_states = (volatile struct exynos5420_cpu_states*)0x02073000;
-
-/* When leaving core handlers and jump to hot-plug address (or cluster
- * switching), we are not sure if the destination is Thumb or ARM mode.
- * So a BX command is required.
- */
-inline static void jump_bx(void *address)
-{
- asm volatile ("bx %0" : : "r"(address));
- /* never returns. */
-}
-
-/* Extracts arbitrary bits from a 32-bit unsigned int. */
-inline static uint32_t get_bits(uint32_t value, uint32_t start, uint32_t len)
-{
- return ((value << (sizeof(value) * 8 - len - start)) >>
- (sizeof(value) * 8 - len));
-}
-
-/* Waits the referenced address to be ready (non-zero) and then jump into it. */
-static void wait_and_jump(volatile uint32_t* reference)
-{
- while (!*reference) {
- wfe();
- }
- jump_bx((void*)*reference);
-}
-
-/* Configures L2 Control Register to use 3 cycles for DATA/TAG RAM latency. */
-static void configure_l2ctlr(void)
-{
- uint32_t val;
-
- val = read_l2ctlr();
- val &= ~(L2CTLR_DATA_RAM_LATENCY_MASK | L2CTLR_TAG_RAM_LATENCY_MASK);
- val |= (L2CTLR_DATA_RAM_LATENCY_CYCLES_3 | L2CTLR_TAG_RAM_LATENCY_CYCLES_3 |
- L2CTLR_ECC_PARITY);
- write_l2ctlr(val);
-}
-
-/* Configures L2 Auxiliary Control Register for Cortex A15. */
-static void configure_l2actlr(void)
-{
- uint32_t val;
-
- val = read_l2actlr();
- val |= (L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL |
- L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT |
- L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE);
- write_l2actlr(val);
-}
-
-/* Initializes the CPU states to reset state. */
-static void init_exynos_cpu_states(void) {
- memset((void*)exynos_cpu_states, 0, sizeof(*exynos_cpu_states));
- exynos_cpu_states->cpu_states[0] = CORE_STATE_RESET;
- exynos_cpu_states->cpu_states[1] = CORE_STATE_SECONDARY_RESET;
- exynos_cpu_states->cpu_states[2] = CORE_STATE_SECONDARY_RESET;
- exynos_cpu_states->cpu_states[3] = CORE_STATE_SECONDARY_RESET;
-}
-
-/*
- * Ensures that the L2 logic has been used within the previous 256 cycles
- * before modifying the ACTLR.SMP bit. This is required during boot before
- * MMU has been enabled, or during a specified reset or power down sequence.
- */
-static void enable_smp(void)
-{
- uint32_t actlr, val;
-
- /* Enable SMP mode */
- actlr = read_actlr();
- actlr |= ACTLR_SMP;
-
- /* Dummy read to assure L2 access */
- val = readl(&exynos_power->inform0);
- val &= 0;
- actlr |= val;
-
- write_actlr(actlr);
- dsb();
- isb();
-}
-
-/* Starts the core and jumps to correct location by its state. */
-static void core_start_execution(void)
-{
- u32 cpu_id, cpu_state;
-
- enable_smp();
- set_system_mode();
-
- cpu_id = read_mpidr() & 0x3; /* up to 4 processors for one cluster. */
- cpu_state = exynos_cpu_states->cpu_states[cpu_id];
-
- if (cpu_state & CORE_STATE_SWITCH_CLUSTER) {
- wait_and_jump(&exynos_cpu_states->switch_address);
- /* never returns. */
- }
-
- /* Standard Exynos suspend/resume. */
- if (exynos_power->inform1) {
- exynos_power->inform1 = 0;
- jump_bx((void*)exynos_power->inform0);
- /* never returns. */
- }
-
- if (cpu_state & CORE_STATE_RESET) {
- /* For Reset, U-Boot jumps to its starting address;
- * on Coreboot, seems ok to ignore for now. */
- }
- wait_and_jump(&exynos_cpu_states->hotplug_address);
- /* never returns. */
-}
-
-/* The entry point for hotplug-in and cluster switching. */
-static void low_power_start(void)
-{
- uint32_t sctlr, reg_val;
-
- /* On warm reset, because iRAM is not cleared, all cores will enter
- * low_power_start, not the initial address. So we need to check reset
- * status again, and jump to 0x0 in that case. */
- reg_val = readl(&exynos_power->spare0);
- if (reg_val != RST_FLAG_VAL) {
- writel(0x0, VECTOR_LOW_POWER_FLAG);
- jump_bx(CORE_RESET_INIT_ADDRESS);
- /* restart cpu execution and never returns. */
- }
-
- /* Workaround for iROM EVT1. A7 core execution may flow into incorrect
- * path, bypassing first jump address and makes final jump address 0x0,
- * so we try to make any core set again low_power_start address, if that
- * becomes zero. */
- reg_val = readl(VECTOR_CORE_SEV_HANDLER);
- if (reg_val != (intptr_t)low_power_start) {
- writel((intptr_t)low_power_start, VECTOR_CORE_SEV_HANDLER);
- dsb();
- /* ask all cores to power on again. */
- sev();
- }
-
- set_system_mode();
-
- /* Whenever a Cortex A-15 core powers on, iROM resets its L2 cache
- * so we need to configure again. */
- if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15) {
- configure_l2ctlr();
- configure_l2actlr();
- }
-
- /* Invalidate L1 & TLB */
- tlbiall();
- iciallu();
-
- /* Disable MMU stuff and caches */
- sctlr = read_sctlr();
- sctlr &= ~(SCTLR_V | SCTLR_M | SCTLR_C);
- sctlr |= (SCTLR_I | SCTLR_Z | SCTLR_A);
- write_sctlr(sctlr);
-
- core_start_execution();
- /* The core should not return. But in order to prevent unexpected
- * errors, a WFI command will help to put CPU back to idle state. */
- wfi();
-}
-
-/* Callback to shutdown a core, safe to be set as hot-plug address. */
-static void power_down_core(void)
-{
- uint32_t mpidr, core_id;
-
- /* MPIDR: 0~2=ID, 8~11=cluster. On Exynos 5420, cluster will be only 0
- * or 1. */
- mpidr = read_mpidr();
- core_id = get_bits(mpidr, 0, 2) | (get_bits(mpidr, 8, 4) << 2);
-
- /* Set the status of the core to low.
- * S5E5420A User Manual, 8.8.1.202, ARM_CORE0_CONFIGURATION, two bits to
- * control power state in each power down level.
- */
- writel(0x0, &exynos_power->arm_core[core_id].config);
-
- /* S5E5420A User Manual, 8.4.2.5, after ARM_CORE*_CONFIGURATION has been
- * set to zero, PMU will detect and wait for WFI then run power-down
- * sequence. */
- wfi();
-}
-
-/* Configures the CPU states shard memory page and then shutdown all cores. */
-static void configure_secondary_cores(void)
-{
- if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15) {
- configure_l2ctlr();
- configure_l2actlr();
- }
-
- /* Currently we use power_down_core as callback for each core to
- * shutdown itself, but it is also ok to directly set ARM_CORE*_CONFIG
- * to zero by CPU0 because every secondary cores should be already in
- * WFI state (in bootblock). The power_down_core will be more helpful
- * when we want to use SMP inside firmware. */
-
- /* Clear boot reg (hotplug address) in cpu states */
- writel(0, (void*)&exynos_cpu_states->hotplug_address);
-
- /* set low_power flag and address */
- writel((intptr_t)low_power_start, VECTOR_LOW_POWER_ADDRESS);
- writel(RST_FLAG_VAL, VECTOR_LOW_POWER_FLAG);
- writel(RST_FLAG_VAL, &exynos_power->spare0);
-
- /* On next SEV, shutdown all cores. */
- writel((intptr_t)power_down_core, VECTOR_CORE_SEV_HANDLER);
-
- /* Ask all cores in WFE mode to shutdown. */
- dsb();
- sev();
-}
-
-/* Configures the SMP cores on Exynos 5420 SOC (and shutdown all secondary
- * cores) */
-void exynos5420_config_smp(void)
-{
- init_exynos_cpu_states();
- configure_secondary_cores();
-}
-