183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2fea25720SGraeme Russ /*
3fea25720SGraeme Russ * (C) Copyright 2008-2011
4fea25720SGraeme Russ * Graeme Russ, <graeme.russ@gmail.com>
5fea25720SGraeme Russ *
6fea25720SGraeme Russ * (C) Copyright 2002
7fa82f871SAlbert ARIBAUD * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
8fea25720SGraeme Russ *
9fea25720SGraeme Russ * (C) Copyright 2002
10fea25720SGraeme Russ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
11fea25720SGraeme Russ * Marius Groeger <mgroeger@sysgo.de>
12fea25720SGraeme Russ *
13fea25720SGraeme Russ * (C) Copyright 2002
14fea25720SGraeme Russ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
15fea25720SGraeme Russ * Alex Zuepke <azu@sysgo.de>
16fea25720SGraeme Russ *
1752f952bfSBin Meng * Part of this file is adapted from coreboot
1852f952bfSBin Meng * src/arch/x86/lib/cpu.c
19fea25720SGraeme Russ */
20fea25720SGraeme Russ
21fea25720SGraeme Russ #include <common.h>
22fea25720SGraeme Russ #include <command.h>
236e6f4ce4SBin Meng #include <dm.h>
24200182a7SSimon Glass #include <errno.h>
25200182a7SSimon Glass #include <malloc.h>
26d8906c1fSBin Meng #include <syscon.h>
27a0609a8dSBin Meng #include <asm/acpi.h>
28b727961bSBin Meng #include <asm/acpi_s3.h>
293a34cae0SBin Meng #include <asm/acpi_table.h>
30095593c0SStefan Reinauer #include <asm/control_regs.h>
31d19c9074SBin Meng #include <asm/coreboot_tables.h>
32200182a7SSimon Glass #include <asm/cpu.h>
336e6f4ce4SBin Meng #include <asm/lapic.h>
34e77b62e2SSimon Glass #include <asm/microcode.h>
356e6f4ce4SBin Meng #include <asm/mp.h>
360c2b7eefSBin Meng #include <asm/mrccache.h>
3743dd22f5SBin Meng #include <asm/msr.h>
3843dd22f5SBin Meng #include <asm/mtrr.h>
39a49e3c7fSSimon Glass #include <asm/post.h>
40fea25720SGraeme Russ #include <asm/processor.h>
41fea25720SGraeme Russ #include <asm/processor-flags.h>
42fea25720SGraeme Russ #include <asm/interrupt.h>
435e2400e8SBin Meng #include <asm/tables.h>
4460a9b6bfSGabe Black #include <linux/compiler.h>
45fea25720SGraeme Russ
4652f952bfSBin Meng DECLARE_GLOBAL_DATA_PTR;
4752f952bfSBin Meng
4852f952bfSBin Meng static const char *const x86_vendor_name[] = {
4952f952bfSBin Meng [X86_VENDOR_INTEL] = "Intel",
5052f952bfSBin Meng [X86_VENDOR_CYRIX] = "Cyrix",
5152f952bfSBin Meng [X86_VENDOR_AMD] = "AMD",
5252f952bfSBin Meng [X86_VENDOR_UMC] = "UMC",
5352f952bfSBin Meng [X86_VENDOR_NEXGEN] = "NexGen",
5452f952bfSBin Meng [X86_VENDOR_CENTAUR] = "Centaur",
5552f952bfSBin Meng [X86_VENDOR_RISE] = "Rise",
5652f952bfSBin Meng [X86_VENDOR_TRANSMETA] = "Transmeta",
5752f952bfSBin Meng [X86_VENDOR_NSC] = "NSC",
5852f952bfSBin Meng [X86_VENDOR_SIS] = "SiS",
5952f952bfSBin Meng };
6052f952bfSBin Meng
x86_cleanup_before_linux(void)61f30fc4deSGabe Black int __weak x86_cleanup_before_linux(void)
62f30fc4deSGabe Black {
637949703aSSimon Glass #ifdef CONFIG_BOOTSTAGE_STASH
64ee2b2434SSimon Glass bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
657949703aSSimon Glass CONFIG_BOOTSTAGE_STASH_SIZE);
667949703aSSimon Glass #endif
677949703aSSimon Glass
68f30fc4deSGabe Black return 0;
69f30fc4deSGabe Black }
70f30fc4deSGabe Black
x86_init_cache(void)71d653244bSGraeme Russ int x86_init_cache(void)
72d653244bSGraeme Russ {
73d653244bSGraeme Russ enable_caches();
74d653244bSGraeme Russ
75fea25720SGraeme Russ return 0;
76fea25720SGraeme Russ }
77d653244bSGraeme Russ int init_cache(void) __attribute__((weak, alias("x86_init_cache")));
78fea25720SGraeme Russ
flush_cache(unsigned long dummy1,unsigned long dummy2)79fea25720SGraeme Russ void flush_cache(unsigned long dummy1, unsigned long dummy2)
80fea25720SGraeme Russ {
81fea25720SGraeme Russ asm("wbinvd\n");
82fea25720SGraeme Russ }
83fea25720SGraeme Russ
84095593c0SStefan Reinauer /* Define these functions to allow ehch-hcd to function */
flush_dcache_range(unsigned long start,unsigned long stop)85095593c0SStefan Reinauer void flush_dcache_range(unsigned long start, unsigned long stop)
86095593c0SStefan Reinauer {
87095593c0SStefan Reinauer }
88095593c0SStefan Reinauer
invalidate_dcache_range(unsigned long start,unsigned long stop)89095593c0SStefan Reinauer void invalidate_dcache_range(unsigned long start, unsigned long stop)
90095593c0SStefan Reinauer {
91095593c0SStefan Reinauer }
9289371409SSimon Glass
dcache_enable(void)9389371409SSimon Glass void dcache_enable(void)
9489371409SSimon Glass {
9589371409SSimon Glass enable_caches();
9689371409SSimon Glass }
9789371409SSimon Glass
dcache_disable(void)9889371409SSimon Glass void dcache_disable(void)
9989371409SSimon Glass {
10089371409SSimon Glass disable_caches();
10189371409SSimon Glass }
10289371409SSimon Glass
icache_enable(void)10389371409SSimon Glass void icache_enable(void)
10489371409SSimon Glass {
10589371409SSimon Glass }
10689371409SSimon Glass
icache_disable(void)10789371409SSimon Glass void icache_disable(void)
10889371409SSimon Glass {
10989371409SSimon Glass }
11089371409SSimon Glass
icache_status(void)11189371409SSimon Glass int icache_status(void)
11289371409SSimon Glass {
11389371409SSimon Glass return 1;
11489371409SSimon Glass }
1157bddac94SSimon Glass
cpu_vendor_name(int vendor)11652f952bfSBin Meng const char *cpu_vendor_name(int vendor)
11752f952bfSBin Meng {
11852f952bfSBin Meng const char *name;
11952f952bfSBin Meng name = "<invalid cpu vendor>";
12039670c34SHeinrich Schuchardt if (vendor < ARRAY_SIZE(x86_vendor_name) &&
12139670c34SHeinrich Schuchardt x86_vendor_name[vendor])
12252f952bfSBin Meng name = x86_vendor_name[vendor];
12352f952bfSBin Meng
12452f952bfSBin Meng return name;
12552f952bfSBin Meng }
12652f952bfSBin Meng
cpu_get_name(char * name)127727c1a98SSimon Glass char *cpu_get_name(char *name)
12852f952bfSBin Meng {
129727c1a98SSimon Glass unsigned int *name_as_ints = (unsigned int *)name;
13052f952bfSBin Meng struct cpuid_result regs;
131727c1a98SSimon Glass char *ptr;
13252f952bfSBin Meng int i;
13352f952bfSBin Meng
134727c1a98SSimon Glass /* This bit adds up to 48 bytes */
13552f952bfSBin Meng for (i = 0; i < 3; i++) {
13652f952bfSBin Meng regs = cpuid(0x80000002 + i);
13752f952bfSBin Meng name_as_ints[i * 4 + 0] = regs.eax;
13852f952bfSBin Meng name_as_ints[i * 4 + 1] = regs.ebx;
13952f952bfSBin Meng name_as_ints[i * 4 + 2] = regs.ecx;
14052f952bfSBin Meng name_as_ints[i * 4 + 3] = regs.edx;
14152f952bfSBin Meng }
142727c1a98SSimon Glass name[CPU_MAX_NAME_LEN - 1] = '\0';
14352f952bfSBin Meng
14452f952bfSBin Meng /* Skip leading spaces. */
145727c1a98SSimon Glass ptr = name;
146727c1a98SSimon Glass while (*ptr == ' ')
147727c1a98SSimon Glass ptr++;
14852f952bfSBin Meng
149727c1a98SSimon Glass return ptr;
15052f952bfSBin Meng }
15152f952bfSBin Meng
default_print_cpuinfo(void)152727c1a98SSimon Glass int default_print_cpuinfo(void)
15392cc94a1SSimon Glass {
15452f952bfSBin Meng printf("CPU: %s, vendor %s, device %xh\n",
15552f952bfSBin Meng cpu_has_64bit() ? "x86_64" : "x86",
15652f952bfSBin Meng cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
15792cc94a1SSimon Glass
158b727961bSBin Meng #ifdef CONFIG_HAVE_ACPI_RESUME
159b727961bSBin Meng debug("ACPI previous sleep state: %s\n",
160b727961bSBin Meng acpi_ss_string(gd->arch.prev_sleep_state));
161b727961bSBin Meng #endif
162b727961bSBin Meng
16392cc94a1SSimon Glass return 0;
16492cc94a1SSimon Glass }
165200182a7SSimon Glass
show_boot_progress(int val)166a49e3c7fSSimon Glass void show_boot_progress(int val)
167a49e3c7fSSimon Glass {
168a49e3c7fSSimon Glass outb(val, POST_PORT);
169a49e3c7fSSimon Glass }
1705e2400e8SBin Meng
1711ab2c010SBin Meng #if !defined(CONFIG_SYS_COREBOOT) && !defined(CONFIG_EFI_STUB)
1721e2f7b9eSBin Meng /*
1731e2f7b9eSBin Meng * Implement a weak default function for boards that optionally
1741e2f7b9eSBin Meng * need to clean up the system before jumping to the kernel.
1751e2f7b9eSBin Meng */
board_final_cleanup(void)1761e2f7b9eSBin Meng __weak void board_final_cleanup(void)
1771e2f7b9eSBin Meng {
1781e2f7b9eSBin Meng }
1791e2f7b9eSBin Meng
last_stage_init(void)1805e2400e8SBin Meng int last_stage_init(void)
1815e2400e8SBin Meng {
182*474a62bcSBin Meng struct acpi_fadt __maybe_unused *fadt;
183*474a62bcSBin Meng
184bffd7981SBin Meng board_final_cleanup();
185bffd7981SBin Meng
186*474a62bcSBin Meng #ifdef CONFIG_HAVE_ACPI_RESUME
187*474a62bcSBin Meng fadt = acpi_find_fadt();
1883a34cae0SBin Meng
189*474a62bcSBin Meng if (fadt && gd->arch.prev_sleep_state == ACPI_S3)
1900f4e2588SBin Meng acpi_resume(fadt);
1913a34cae0SBin Meng #endif
1923a34cae0SBin Meng
1935e2400e8SBin Meng write_tables();
1945e2400e8SBin Meng
195*474a62bcSBin Meng #ifdef CONFIG_GENERATE_ACPI_TABLE
196*474a62bcSBin Meng fadt = acpi_find_fadt();
197*474a62bcSBin Meng
198*474a62bcSBin Meng /* Don't touch ACPI hardware on HW reduced platforms */
199*474a62bcSBin Meng if (fadt && !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) {
200*474a62bcSBin Meng /*
201*474a62bcSBin Meng * Other than waiting for OSPM to request us to switch to ACPI
202*474a62bcSBin Meng * mode, do it by ourselves, since SMI will not be triggered.
203*474a62bcSBin Meng */
204*474a62bcSBin Meng enter_acpi_mode(fadt->pm1a_cnt_blk);
205*474a62bcSBin Meng }
206*474a62bcSBin Meng #endif
207*474a62bcSBin Meng
2085e2400e8SBin Meng return 0;
2095e2400e8SBin Meng }
2105e2400e8SBin Meng #endif
211bcb0c61eSSimon Glass
x86_init_cpus(void)212afd5d50cSSimon Glass static int x86_init_cpus(void)
213bcb0c61eSSimon Glass {
2146e6f4ce4SBin Meng #ifdef CONFIG_SMP
2156e6f4ce4SBin Meng debug("Init additional CPUs\n");
2166e6f4ce4SBin Meng x86_mp_init();
217c77b8912SBin Meng #else
218c77b8912SBin Meng struct udevice *dev;
219c77b8912SBin Meng
220c77b8912SBin Meng /*
221c77b8912SBin Meng * This causes the cpu-x86 driver to be probed.
222c77b8912SBin Meng * We don't check return value here as we want to allow boards
223c77b8912SBin Meng * which have not been converted to use cpu uclass driver to boot.
224c77b8912SBin Meng */
225c77b8912SBin Meng uclass_first_device(UCLASS_CPU, &dev);
2266e6f4ce4SBin Meng #endif
2276e6f4ce4SBin Meng
228bcb0c61eSSimon Glass return 0;
229bcb0c61eSSimon Glass }
230bcb0c61eSSimon Glass
cpu_init_r(void)231bcb0c61eSSimon Glass int cpu_init_r(void)
232bcb0c61eSSimon Glass {
233ac643e03SSimon Glass struct udevice *dev;
234ac643e03SSimon Glass int ret;
235ac643e03SSimon Glass
236ac643e03SSimon Glass if (!ll_boot_init())
237ac643e03SSimon Glass return 0;
238ac643e03SSimon Glass
239ac643e03SSimon Glass ret = x86_init_cpus();
240ac643e03SSimon Glass if (ret)
241ac643e03SSimon Glass return ret;
242ac643e03SSimon Glass
243ac643e03SSimon Glass /*
244ac643e03SSimon Glass * Set up the northbridge, PCH and LPC if available. Note that these
245ac643e03SSimon Glass * may have had some limited pre-relocation init if they were probed
246ac643e03SSimon Glass * before relocation, but this is post relocation.
247ac643e03SSimon Glass */
248ac643e03SSimon Glass uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
249ac643e03SSimon Glass uclass_first_device(UCLASS_PCH, &dev);
250ac643e03SSimon Glass uclass_first_device(UCLASS_LPC, &dev);
251e49cceacSSimon Glass
252d8906c1fSBin Meng /* Set up pin control if available */
253d8906c1fSBin Meng ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev);
254d8906c1fSBin Meng debug("%s, pinctrl=%p, ret=%d\n", __func__, dev, ret);
255d8906c1fSBin Meng
256e49cceacSSimon Glass return 0;
257bcb0c61eSSimon Glass }
2580c2b7eefSBin Meng
2590c2b7eefSBin Meng #ifndef CONFIG_EFI_STUB
reserve_arch(void)2600c2b7eefSBin Meng int reserve_arch(void)
2610c2b7eefSBin Meng {
2620c2b7eefSBin Meng #ifdef CONFIG_ENABLE_MRC_CACHE
263d19c9074SBin Meng mrccache_reserve();
2640c2b7eefSBin Meng #endif
265d19c9074SBin Meng
266d19c9074SBin Meng #ifdef CONFIG_SEABIOS
267d19c9074SBin Meng high_table_reserve();
268d19c9074SBin Meng #endif
269d19c9074SBin Meng
2705ae5aa93SBin Meng #ifdef CONFIG_HAVE_ACPI_RESUME
2715ae5aa93SBin Meng acpi_s3_reserve();
2725ae5aa93SBin Meng
2735ae5aa93SBin Meng #ifdef CONFIG_HAVE_FSP
274ba65808eSBin Meng /*
275ba65808eSBin Meng * Save stack address to CMOS so that at next S3 boot,
276ba65808eSBin Meng * we can use it as the stack address for fsp_contiue()
277ba65808eSBin Meng */
278ba65808eSBin Meng fsp_save_s3_stack();
2795ae5aa93SBin Meng #endif /* CONFIG_HAVE_FSP */
2805ae5aa93SBin Meng #endif /* CONFIG_HAVE_ACPI_RESUME */
281ba65808eSBin Meng
282d19c9074SBin Meng return 0;
2830c2b7eefSBin Meng }
2840c2b7eefSBin Meng #endif
285