xref: /openbmc/u-boot/arch/x86/cpu/cpu.c (revision e0ed8332fa2fe684b4c8ba1caab991663730cbf0)
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