blob: b655d8a0ed5ace4a07a164a2f554d933a15f918f [file] [log] [blame]
David Hendricks8cbd5692017-12-01 20:49:48 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2018-present Facebook, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <types.h>
Patrick Rudolph88f81af2018-04-11 11:40:55 +020017#include <soc/addressmap.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080018#include <arch/io.h>
19#include <soc/cpu.h>
20#include <bdk-coreboot.h>
Patrick Rudolph88f81af2018-04-11 11:40:55 +020021#include <console/console.h>
22#include <timer.h>
23#include <delay.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080024
Patrick Rudolph88f81af2018-04-11 11:40:55 +020025uint64_t cpu_get_available_core_mask(void)
David Hendricks8cbd5692017-12-01 20:49:48 -080026{
Patrick Rudolph88f81af2018-04-11 11:40:55 +020027 return read64((void *)RST_PP_AVAILABLE);
28}
29
30size_t cpu_get_num_available_cores(void)
31{
32 return bdk_dpop(cpu_get_available_core_mask());
33}
34
35static void (*secondary_c_entry)(size_t core_id);
36static size_t secondary_booted;
37
38void secondary_cpu_init(size_t core_id)
39{
40 write64(&secondary_booted, 1);
41 dmb();
42
43 if (secondary_c_entry)
44 secondary_c_entry(core_id);
45 else
46 asm("wfi");
47}
48
49size_t cpu_self_get_core_id(void)
50{
51 u32 mpidr_el1;
52 asm("mrs %0, MPIDR_EL1\n\t" : "=r" (mpidr_el1) :: "memory");
53
54 /* Core is 4 bits from AFF0 and rest from AFF1 */
55 size_t core_num;
56 core_num = mpidr_el1 & 0xf;
57 core_num |= (mpidr_el1 & 0xff00) >> 4;
58
59 return core_num;
60}
61
62uint64_t cpu_self_get_core_mask(void)
63{
64 return 1ULL << cpu_self_get_core_id();
65}
66
67size_t start_cpu(size_t cpu, void (*entry_64)(size_t core_id))
68{
69 const uint64_t coremask = 1ULL << cpu;
70 struct stopwatch sw;
71 uint64_t pending;
72
73 printk(BIOS_DEBUG, "CPU: Starting CPU%zu @ %p.\n", cpu, entry_64);
74
75 /* Core not available */
76 if (!(coremask & cpu_get_available_core_mask()))
77 return 1;
78
79 /* Only secondary CPUs are supported */
80 if (cpu == cpu_self_get_core_id())
81 return 1;
82
83 /* Check stack here, instead of in cpu_secondary.S */
Julius Werner7e0dea62019-02-20 18:39:22 -080084 if ((CONFIG_STACK_SIZE * cpu) > REGION_SIZE(stack_sec))
Patrick Rudolph88f81af2018-04-11 11:40:55 +020085 return 1;
86
87 /* Write the address of the main entry point */
88 write64((void *)MIO_BOOT_AP_JUMP, (uintptr_t)secondary_init);
89
90 /* Get coremask of cores in reset */
91 const uint64_t reset = read64((void *)RST_PP_RESET);
92 printk(BIOS_INFO, "CPU: Cores currently in reset: 0x%llx\n", reset);
93
94 /* Setup entry for secondary core */
95 write64(&secondary_c_entry, (uintptr_t)entry_64);
96 write64(&secondary_booted, 0);
97 dmb();
98
99 printk(BIOS_DEBUG, "CPU: Taking core %zu out of reset.\n", cpu);
100
101 /* Release core from reset */
102 write64((void *)RST_PP_RESET, reset & ~coremask);
103
104 /* Wait for cores to finish coming out of reset */
105 udelay(1);
106
107 stopwatch_init_usecs_expire(&sw, 1000000);
108 do {
109 pending = read64((void *)RST_PP_PENDING);
110 } while (!stopwatch_expired(&sw) && (pending & coremask));
111
112 if (stopwatch_expired(&sw)) {
113 printk(BIOS_ERR, "ERROR: Timeout waiting for reset "
114 "pending to clear.");
115 return 1;
116 }
117
118 stopwatch_init_usecs_expire(&sw, 1000000);
119
120 printk(BIOS_DEBUG, "CPU: Wait up to 1s for the core to boot...\n");
121 while (!stopwatch_expired(&sw) && !read64(&secondary_booted))
122 ;
123
124 /* Cleanup */
125 write64(&secondary_c_entry, 0);
126 dmb();
127
128 if (!read64(&secondary_booted)) {
129 printk(BIOS_ERR, "ERROR: Core %zu failed to start.\n", cpu);
130 return 1;
131 }
132
133 printk(BIOS_INFO, "CPU: Core %zu booted\n", cpu);
134 return 0;
David Hendricks8cbd5692017-12-01 20:49:48 -0800135}