xref: /rk3399_rockchip-uboot/arch/x86/cpu/cpu.c (revision ae1b939930b0fffc062bb99196ec22e19afcc7e8)
1fea25720SGraeme Russ /*
2fea25720SGraeme Russ  * (C) Copyright 2008-2011
3fea25720SGraeme Russ  * Graeme Russ, <graeme.russ@gmail.com>
4fea25720SGraeme Russ  *
5fea25720SGraeme Russ  * (C) Copyright 2002
6fa82f871SAlbert ARIBAUD  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
7fea25720SGraeme Russ  *
8fea25720SGraeme Russ  * (C) Copyright 2002
9fea25720SGraeme Russ  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
10fea25720SGraeme Russ  * Marius Groeger <mgroeger@sysgo.de>
11fea25720SGraeme Russ  *
12fea25720SGraeme Russ  * (C) Copyright 2002
13fea25720SGraeme Russ  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
14fea25720SGraeme Russ  * Alex Zuepke <azu@sysgo.de>
15fea25720SGraeme Russ  *
1652f952bfSBin Meng  * Part of this file is adapted from coreboot
1752f952bfSBin Meng  * src/arch/x86/lib/cpu.c
1852f952bfSBin Meng  *
191a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
20fea25720SGraeme Russ  */
21fea25720SGraeme Russ 
22fea25720SGraeme Russ #include <common.h>
23fea25720SGraeme Russ #include <command.h>
246e6f4ce4SBin Meng #include <dm.h>
25200182a7SSimon Glass #include <errno.h>
26200182a7SSimon Glass #include <malloc.h>
27d8906c1fSBin Meng #include <syscon.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 
do_reset(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])79fea25720SGraeme Russ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
80fea25720SGraeme Russ {
81fea25720SGraeme Russ 	printf("resetting ...\n");
82fea25720SGraeme Russ 
83fea25720SGraeme Russ 	/* wait 50 ms */
84fea25720SGraeme Russ 	udelay(50000);
85fea25720SGraeme Russ 	disable_interrupts();
86fea25720SGraeme Russ 	reset_cpu(0);
87fea25720SGraeme Russ 
88fea25720SGraeme Russ 	/*NOTREACHED*/
89fea25720SGraeme Russ 	return 0;
90fea25720SGraeme Russ }
91fea25720SGraeme Russ 
flush_cache(unsigned long dummy1,unsigned long dummy2)92fea25720SGraeme Russ void  flush_cache(unsigned long dummy1, unsigned long dummy2)
93fea25720SGraeme Russ {
94fea25720SGraeme Russ 	asm("wbinvd\n");
95fea25720SGraeme Russ }
96fea25720SGraeme Russ 
reset_cpu(ulong addr)97e1ffd817SSimon Glass __weak void reset_cpu(ulong addr)
98fea25720SGraeme Russ {
99ff6a8f3cSSimon Glass 	/* Do a hard reset through the chipset's reset control register */
1002a605d4dSSimon Glass 	outb(SYS_RST | RST_CPU, IO_PORT_RESET);
101ff6a8f3cSSimon Glass 	for (;;)
102ff6a8f3cSSimon Glass 		cpu_hlt();
103ff6a8f3cSSimon Glass }
104ff6a8f3cSSimon Glass 
x86_full_reset(void)105ff6a8f3cSSimon Glass void x86_full_reset(void)
106ff6a8f3cSSimon Glass {
1072a605d4dSSimon Glass 	outb(FULL_RST | SYS_RST | RST_CPU, IO_PORT_RESET);
108fea25720SGraeme Russ }
109095593c0SStefan Reinauer 
110095593c0SStefan Reinauer /* Define these functions to allow ehch-hcd to function */
flush_dcache_range(unsigned long start,unsigned long stop)111095593c0SStefan Reinauer void flush_dcache_range(unsigned long start, unsigned long stop)
112095593c0SStefan Reinauer {
113095593c0SStefan Reinauer }
114095593c0SStefan Reinauer 
invalidate_dcache_range(unsigned long start,unsigned long stop)115095593c0SStefan Reinauer void invalidate_dcache_range(unsigned long start, unsigned long stop)
116095593c0SStefan Reinauer {
117095593c0SStefan Reinauer }
11889371409SSimon Glass 
dcache_enable(void)11989371409SSimon Glass void dcache_enable(void)
12089371409SSimon Glass {
12189371409SSimon Glass 	enable_caches();
12289371409SSimon Glass }
12389371409SSimon Glass 
dcache_disable(void)12489371409SSimon Glass void dcache_disable(void)
12589371409SSimon Glass {
12689371409SSimon Glass 	disable_caches();
12789371409SSimon Glass }
12889371409SSimon Glass 
icache_enable(void)12989371409SSimon Glass void icache_enable(void)
13089371409SSimon Glass {
13189371409SSimon Glass }
13289371409SSimon Glass 
icache_disable(void)13389371409SSimon Glass void icache_disable(void)
13489371409SSimon Glass {
13589371409SSimon Glass }
13689371409SSimon Glass 
icache_status(void)13789371409SSimon Glass int icache_status(void)
13889371409SSimon Glass {
13989371409SSimon Glass 	return 1;
14089371409SSimon Glass }
1417bddac94SSimon Glass 
cpu_vendor_name(int vendor)14252f952bfSBin Meng const char *cpu_vendor_name(int vendor)
14352f952bfSBin Meng {
14452f952bfSBin Meng 	const char *name;
14552f952bfSBin Meng 	name = "<invalid cpu vendor>";
14652f952bfSBin Meng 	if ((vendor < (ARRAY_SIZE(x86_vendor_name))) &&
14752f952bfSBin Meng 	    (x86_vendor_name[vendor] != 0))
14852f952bfSBin Meng 		name = x86_vendor_name[vendor];
14952f952bfSBin Meng 
15052f952bfSBin Meng 	return name;
15152f952bfSBin Meng }
15252f952bfSBin Meng 
cpu_get_name(char * name)153727c1a98SSimon Glass char *cpu_get_name(char *name)
15452f952bfSBin Meng {
155727c1a98SSimon Glass 	unsigned int *name_as_ints = (unsigned int *)name;
15652f952bfSBin Meng 	struct cpuid_result regs;
157727c1a98SSimon Glass 	char *ptr;
15852f952bfSBin Meng 	int i;
15952f952bfSBin Meng 
160727c1a98SSimon Glass 	/* This bit adds up to 48 bytes */
16152f952bfSBin Meng 	for (i = 0; i < 3; i++) {
16252f952bfSBin Meng 		regs = cpuid(0x80000002 + i);
16352f952bfSBin Meng 		name_as_ints[i * 4 + 0] = regs.eax;
16452f952bfSBin Meng 		name_as_ints[i * 4 + 1] = regs.ebx;
16552f952bfSBin Meng 		name_as_ints[i * 4 + 2] = regs.ecx;
16652f952bfSBin Meng 		name_as_ints[i * 4 + 3] = regs.edx;
16752f952bfSBin Meng 	}
168727c1a98SSimon Glass 	name[CPU_MAX_NAME_LEN - 1] = '\0';
16952f952bfSBin Meng 
17052f952bfSBin Meng 	/* Skip leading spaces. */
171727c1a98SSimon Glass 	ptr = name;
172727c1a98SSimon Glass 	while (*ptr == ' ')
173727c1a98SSimon Glass 		ptr++;
17452f952bfSBin Meng 
175727c1a98SSimon Glass 	return ptr;
17652f952bfSBin Meng }
17752f952bfSBin Meng 
default_print_cpuinfo(void)178727c1a98SSimon Glass int default_print_cpuinfo(void)
17992cc94a1SSimon Glass {
18052f952bfSBin Meng 	printf("CPU: %s, vendor %s, device %xh\n",
18152f952bfSBin Meng 	       cpu_has_64bit() ? "x86_64" : "x86",
18252f952bfSBin Meng 	       cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
18392cc94a1SSimon Glass 
184b727961bSBin Meng #ifdef CONFIG_HAVE_ACPI_RESUME
185b727961bSBin Meng 	debug("ACPI previous sleep state: %s\n",
186b727961bSBin Meng 	      acpi_ss_string(gd->arch.prev_sleep_state));
187b727961bSBin Meng #endif
188b727961bSBin Meng 
18992cc94a1SSimon Glass 	return 0;
19092cc94a1SSimon Glass }
191200182a7SSimon Glass 
show_boot_progress(int val)192a49e3c7fSSimon Glass void show_boot_progress(int val)
193a49e3c7fSSimon Glass {
194a49e3c7fSSimon Glass 	outb(val, POST_PORT);
195a49e3c7fSSimon Glass }
1965e2400e8SBin Meng 
1975e2400e8SBin Meng #ifndef CONFIG_SYS_COREBOOT
1981e2f7b9eSBin Meng /*
1991e2f7b9eSBin Meng  * Implement a weak default function for boards that optionally
2001e2f7b9eSBin Meng  * need to clean up the system before jumping to the kernel.
2011e2f7b9eSBin Meng  */
board_final_cleanup(void)2021e2f7b9eSBin Meng __weak void board_final_cleanup(void)
2031e2f7b9eSBin Meng {
2041e2f7b9eSBin Meng }
2051e2f7b9eSBin Meng 
last_stage_init(void)2065e2400e8SBin Meng int last_stage_init(void)
2075e2400e8SBin Meng {
208bffd7981SBin Meng 	board_final_cleanup();
209bffd7981SBin Meng 
2103a34cae0SBin Meng #if CONFIG_HAVE_ACPI_RESUME
2110f4e2588SBin Meng 	struct acpi_fadt *fadt = acpi_find_fadt();
2123a34cae0SBin Meng 
2130f4e2588SBin Meng 	if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3)
2140f4e2588SBin Meng 		acpi_resume(fadt);
2153a34cae0SBin Meng #endif
2163a34cae0SBin Meng 
2175e2400e8SBin Meng 	write_tables();
2185e2400e8SBin Meng 
2195e2400e8SBin Meng 	return 0;
2205e2400e8SBin Meng }
2215e2400e8SBin Meng #endif
222bcb0c61eSSimon Glass 
x86_init_cpus(void)223afd5d50cSSimon Glass static int x86_init_cpus(void)
224bcb0c61eSSimon Glass {
2256e6f4ce4SBin Meng #ifdef CONFIG_SMP
2266e6f4ce4SBin Meng 	debug("Init additional CPUs\n");
2276e6f4ce4SBin Meng 	x86_mp_init();
228c77b8912SBin Meng #else
229c77b8912SBin Meng 	struct udevice *dev;
230c77b8912SBin Meng 
231c77b8912SBin Meng 	/*
232c77b8912SBin Meng 	 * This causes the cpu-x86 driver to be probed.
233c77b8912SBin Meng 	 * We don't check return value here as we want to allow boards
234c77b8912SBin Meng 	 * which have not been converted to use cpu uclass driver to boot.
235c77b8912SBin Meng 	 */
236c77b8912SBin Meng 	uclass_first_device(UCLASS_CPU, &dev);
2376e6f4ce4SBin Meng #endif
2386e6f4ce4SBin Meng 
239bcb0c61eSSimon Glass 	return 0;
240bcb0c61eSSimon Glass }
241bcb0c61eSSimon Glass 
cpu_init_r(void)242bcb0c61eSSimon Glass int cpu_init_r(void)
243bcb0c61eSSimon Glass {
244ac643e03SSimon Glass 	struct udevice *dev;
245ac643e03SSimon Glass 	int ret;
246ac643e03SSimon Glass 
247ac643e03SSimon Glass 	if (!ll_boot_init())
248ac643e03SSimon Glass 		return 0;
249ac643e03SSimon Glass 
250ac643e03SSimon Glass 	ret = x86_init_cpus();
251ac643e03SSimon Glass 	if (ret)
252ac643e03SSimon Glass 		return ret;
253ac643e03SSimon Glass 
254ac643e03SSimon Glass 	/*
255ac643e03SSimon Glass 	 * Set up the northbridge, PCH and LPC if available. Note that these
256ac643e03SSimon Glass 	 * may have had some limited pre-relocation init if they were probed
257ac643e03SSimon Glass 	 * before relocation, but this is post relocation.
258ac643e03SSimon Glass 	 */
259ac643e03SSimon Glass 	uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
260ac643e03SSimon Glass 	uclass_first_device(UCLASS_PCH, &dev);
261ac643e03SSimon Glass 	uclass_first_device(UCLASS_LPC, &dev);
262e49cceacSSimon Glass 
263d8906c1fSBin Meng 	/* Set up pin control if available */
264d8906c1fSBin Meng 	ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev);
265d8906c1fSBin Meng 	debug("%s, pinctrl=%p, ret=%d\n", __func__, dev, ret);
266d8906c1fSBin Meng 
267e49cceacSSimon Glass 	return 0;
268bcb0c61eSSimon Glass }
2690c2b7eefSBin Meng 
2700c2b7eefSBin Meng #ifndef CONFIG_EFI_STUB
reserve_arch(void)2710c2b7eefSBin Meng int reserve_arch(void)
2720c2b7eefSBin Meng {
2730c2b7eefSBin Meng #ifdef CONFIG_ENABLE_MRC_CACHE
274d19c9074SBin Meng 	mrccache_reserve();
2750c2b7eefSBin Meng #endif
276d19c9074SBin Meng 
277d19c9074SBin Meng #ifdef CONFIG_SEABIOS
278d19c9074SBin Meng 	high_table_reserve();
279d19c9074SBin Meng #endif
280d19c9074SBin Meng 
281*5ae5aa93SBin Meng #ifdef CONFIG_HAVE_ACPI_RESUME
282*5ae5aa93SBin Meng 	acpi_s3_reserve();
283*5ae5aa93SBin Meng 
284*5ae5aa93SBin Meng #ifdef CONFIG_HAVE_FSP
285ba65808eSBin Meng 	/*
286ba65808eSBin Meng 	 * Save stack address to CMOS so that at next S3 boot,
287ba65808eSBin Meng 	 * we can use it as the stack address for fsp_contiue()
288ba65808eSBin Meng 	 */
289ba65808eSBin Meng 	fsp_save_s3_stack();
290*5ae5aa93SBin Meng #endif /* CONFIG_HAVE_FSP */
291*5ae5aa93SBin Meng #endif /* CONFIG_HAVE_ACPI_RESUME */
292ba65808eSBin Meng 
293d19c9074SBin Meng 	return 0;
2940c2b7eefSBin Meng }
2950c2b7eefSBin Meng #endif
296