xref: /OK3568_Linux_fs/u-boot/arch/x86/cpu/cpu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2008-2011
3*4882a593Smuzhiyun  * Graeme Russ, <graeme.russ@gmail.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * (C) Copyright 2002
6*4882a593Smuzhiyun  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * (C) Copyright 2002
9*4882a593Smuzhiyun  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
10*4882a593Smuzhiyun  * Marius Groeger <mgroeger@sysgo.de>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * (C) Copyright 2002
13*4882a593Smuzhiyun  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
14*4882a593Smuzhiyun  * Alex Zuepke <azu@sysgo.de>
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * Part of this file is adapted from coreboot
17*4882a593Smuzhiyun  * src/arch/x86/lib/cpu.c
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <common.h>
23*4882a593Smuzhiyun #include <command.h>
24*4882a593Smuzhiyun #include <dm.h>
25*4882a593Smuzhiyun #include <errno.h>
26*4882a593Smuzhiyun #include <malloc.h>
27*4882a593Smuzhiyun #include <syscon.h>
28*4882a593Smuzhiyun #include <asm/acpi_s3.h>
29*4882a593Smuzhiyun #include <asm/acpi_table.h>
30*4882a593Smuzhiyun #include <asm/control_regs.h>
31*4882a593Smuzhiyun #include <asm/coreboot_tables.h>
32*4882a593Smuzhiyun #include <asm/cpu.h>
33*4882a593Smuzhiyun #include <asm/lapic.h>
34*4882a593Smuzhiyun #include <asm/microcode.h>
35*4882a593Smuzhiyun #include <asm/mp.h>
36*4882a593Smuzhiyun #include <asm/mrccache.h>
37*4882a593Smuzhiyun #include <asm/msr.h>
38*4882a593Smuzhiyun #include <asm/mtrr.h>
39*4882a593Smuzhiyun #include <asm/post.h>
40*4882a593Smuzhiyun #include <asm/processor.h>
41*4882a593Smuzhiyun #include <asm/processor-flags.h>
42*4882a593Smuzhiyun #include <asm/interrupt.h>
43*4882a593Smuzhiyun #include <asm/tables.h>
44*4882a593Smuzhiyun #include <linux/compiler.h>
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static const char *const x86_vendor_name[] = {
49*4882a593Smuzhiyun 	[X86_VENDOR_INTEL]     = "Intel",
50*4882a593Smuzhiyun 	[X86_VENDOR_CYRIX]     = "Cyrix",
51*4882a593Smuzhiyun 	[X86_VENDOR_AMD]       = "AMD",
52*4882a593Smuzhiyun 	[X86_VENDOR_UMC]       = "UMC",
53*4882a593Smuzhiyun 	[X86_VENDOR_NEXGEN]    = "NexGen",
54*4882a593Smuzhiyun 	[X86_VENDOR_CENTAUR]   = "Centaur",
55*4882a593Smuzhiyun 	[X86_VENDOR_RISE]      = "Rise",
56*4882a593Smuzhiyun 	[X86_VENDOR_TRANSMETA] = "Transmeta",
57*4882a593Smuzhiyun 	[X86_VENDOR_NSC]       = "NSC",
58*4882a593Smuzhiyun 	[X86_VENDOR_SIS]       = "SiS",
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
x86_cleanup_before_linux(void)61*4882a593Smuzhiyun int __weak x86_cleanup_before_linux(void)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun #ifdef CONFIG_BOOTSTAGE_STASH
64*4882a593Smuzhiyun 	bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
65*4882a593Smuzhiyun 			CONFIG_BOOTSTAGE_STASH_SIZE);
66*4882a593Smuzhiyun #endif
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
x86_init_cache(void)71*4882a593Smuzhiyun int x86_init_cache(void)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	enable_caches();
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return 0;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun int init_cache(void) __attribute__((weak, alias("x86_init_cache")));
78*4882a593Smuzhiyun 
do_reset(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])79*4882a593Smuzhiyun int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	printf("resetting ...\n");
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* wait 50 ms */
84*4882a593Smuzhiyun 	udelay(50000);
85*4882a593Smuzhiyun 	disable_interrupts();
86*4882a593Smuzhiyun 	reset_cpu(0);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	/*NOTREACHED*/
89*4882a593Smuzhiyun 	return 0;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
flush_cache(unsigned long dummy1,unsigned long dummy2)92*4882a593Smuzhiyun void  flush_cache(unsigned long dummy1, unsigned long dummy2)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	asm("wbinvd\n");
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
reset_cpu(ulong addr)97*4882a593Smuzhiyun __weak void reset_cpu(ulong addr)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	/* Do a hard reset through the chipset's reset control register */
100*4882a593Smuzhiyun 	outb(SYS_RST | RST_CPU, IO_PORT_RESET);
101*4882a593Smuzhiyun 	for (;;)
102*4882a593Smuzhiyun 		cpu_hlt();
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
x86_full_reset(void)105*4882a593Smuzhiyun void x86_full_reset(void)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	outb(FULL_RST | SYS_RST | RST_CPU, IO_PORT_RESET);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun /* Define these functions to allow ehch-hcd to function */
flush_dcache_range(unsigned long start,unsigned long stop)111*4882a593Smuzhiyun void flush_dcache_range(unsigned long start, unsigned long stop)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
invalidate_dcache_range(unsigned long start,unsigned long stop)115*4882a593Smuzhiyun void invalidate_dcache_range(unsigned long start, unsigned long stop)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
dcache_enable(void)119*4882a593Smuzhiyun void dcache_enable(void)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	enable_caches();
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
dcache_disable(void)124*4882a593Smuzhiyun void dcache_disable(void)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	disable_caches();
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
icache_enable(void)129*4882a593Smuzhiyun void icache_enable(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
icache_disable(void)133*4882a593Smuzhiyun void icache_disable(void)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
icache_status(void)137*4882a593Smuzhiyun int icache_status(void)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	return 1;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
cpu_vendor_name(int vendor)142*4882a593Smuzhiyun const char *cpu_vendor_name(int vendor)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	const char *name;
145*4882a593Smuzhiyun 	name = "<invalid cpu vendor>";
146*4882a593Smuzhiyun 	if ((vendor < (ARRAY_SIZE(x86_vendor_name))) &&
147*4882a593Smuzhiyun 	    (x86_vendor_name[vendor] != 0))
148*4882a593Smuzhiyun 		name = x86_vendor_name[vendor];
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return name;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
cpu_get_name(char * name)153*4882a593Smuzhiyun char *cpu_get_name(char *name)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	unsigned int *name_as_ints = (unsigned int *)name;
156*4882a593Smuzhiyun 	struct cpuid_result regs;
157*4882a593Smuzhiyun 	char *ptr;
158*4882a593Smuzhiyun 	int i;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* This bit adds up to 48 bytes */
161*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
162*4882a593Smuzhiyun 		regs = cpuid(0x80000002 + i);
163*4882a593Smuzhiyun 		name_as_ints[i * 4 + 0] = regs.eax;
164*4882a593Smuzhiyun 		name_as_ints[i * 4 + 1] = regs.ebx;
165*4882a593Smuzhiyun 		name_as_ints[i * 4 + 2] = regs.ecx;
166*4882a593Smuzhiyun 		name_as_ints[i * 4 + 3] = regs.edx;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 	name[CPU_MAX_NAME_LEN - 1] = '\0';
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/* Skip leading spaces. */
171*4882a593Smuzhiyun 	ptr = name;
172*4882a593Smuzhiyun 	while (*ptr == ' ')
173*4882a593Smuzhiyun 		ptr++;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	return ptr;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
default_print_cpuinfo(void)178*4882a593Smuzhiyun int default_print_cpuinfo(void)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	printf("CPU: %s, vendor %s, device %xh\n",
181*4882a593Smuzhiyun 	       cpu_has_64bit() ? "x86_64" : "x86",
182*4882a593Smuzhiyun 	       cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun #ifdef CONFIG_HAVE_ACPI_RESUME
185*4882a593Smuzhiyun 	debug("ACPI previous sleep state: %s\n",
186*4882a593Smuzhiyun 	      acpi_ss_string(gd->arch.prev_sleep_state));
187*4882a593Smuzhiyun #endif
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
show_boot_progress(int val)192*4882a593Smuzhiyun void show_boot_progress(int val)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	outb(val, POST_PORT);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun #ifndef CONFIG_SYS_COREBOOT
198*4882a593Smuzhiyun /*
199*4882a593Smuzhiyun  * Implement a weak default function for boards that optionally
200*4882a593Smuzhiyun  * need to clean up the system before jumping to the kernel.
201*4882a593Smuzhiyun  */
board_final_cleanup(void)202*4882a593Smuzhiyun __weak void board_final_cleanup(void)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
last_stage_init(void)206*4882a593Smuzhiyun int last_stage_init(void)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	board_final_cleanup();
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun #if CONFIG_HAVE_ACPI_RESUME
211*4882a593Smuzhiyun 	struct acpi_fadt *fadt = acpi_find_fadt();
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3)
214*4882a593Smuzhiyun 		acpi_resume(fadt);
215*4882a593Smuzhiyun #endif
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	write_tables();
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun #endif
222*4882a593Smuzhiyun 
x86_init_cpus(void)223*4882a593Smuzhiyun static int x86_init_cpus(void)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun #ifdef CONFIG_SMP
226*4882a593Smuzhiyun 	debug("Init additional CPUs\n");
227*4882a593Smuzhiyun 	x86_mp_init();
228*4882a593Smuzhiyun #else
229*4882a593Smuzhiyun 	struct udevice *dev;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/*
232*4882a593Smuzhiyun 	 * This causes the cpu-x86 driver to be probed.
233*4882a593Smuzhiyun 	 * We don't check return value here as we want to allow boards
234*4882a593Smuzhiyun 	 * which have not been converted to use cpu uclass driver to boot.
235*4882a593Smuzhiyun 	 */
236*4882a593Smuzhiyun 	uclass_first_device(UCLASS_CPU, &dev);
237*4882a593Smuzhiyun #endif
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
cpu_init_r(void)242*4882a593Smuzhiyun int cpu_init_r(void)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct udevice *dev;
245*4882a593Smuzhiyun 	int ret;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	if (!ll_boot_init())
248*4882a593Smuzhiyun 		return 0;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	ret = x86_init_cpus();
251*4882a593Smuzhiyun 	if (ret)
252*4882a593Smuzhiyun 		return ret;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/*
255*4882a593Smuzhiyun 	 * Set up the northbridge, PCH and LPC if available. Note that these
256*4882a593Smuzhiyun 	 * may have had some limited pre-relocation init if they were probed
257*4882a593Smuzhiyun 	 * before relocation, but this is post relocation.
258*4882a593Smuzhiyun 	 */
259*4882a593Smuzhiyun 	uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
260*4882a593Smuzhiyun 	uclass_first_device(UCLASS_PCH, &dev);
261*4882a593Smuzhiyun 	uclass_first_device(UCLASS_LPC, &dev);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/* Set up pin control if available */
264*4882a593Smuzhiyun 	ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev);
265*4882a593Smuzhiyun 	debug("%s, pinctrl=%p, ret=%d\n", __func__, dev, ret);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun #ifndef CONFIG_EFI_STUB
reserve_arch(void)271*4882a593Smuzhiyun int reserve_arch(void)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun #ifdef CONFIG_ENABLE_MRC_CACHE
274*4882a593Smuzhiyun 	mrccache_reserve();
275*4882a593Smuzhiyun #endif
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #ifdef CONFIG_SEABIOS
278*4882a593Smuzhiyun 	high_table_reserve();
279*4882a593Smuzhiyun #endif
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun #ifdef CONFIG_HAVE_ACPI_RESUME
282*4882a593Smuzhiyun 	acpi_s3_reserve();
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun #ifdef CONFIG_HAVE_FSP
285*4882a593Smuzhiyun 	/*
286*4882a593Smuzhiyun 	 * Save stack address to CMOS so that at next S3 boot,
287*4882a593Smuzhiyun 	 * we can use it as the stack address for fsp_contiue()
288*4882a593Smuzhiyun 	 */
289*4882a593Smuzhiyun 	fsp_save_s3_stack();
290*4882a593Smuzhiyun #endif /* CONFIG_HAVE_FSP */
291*4882a593Smuzhiyun #endif /* CONFIG_HAVE_ACPI_RESUME */
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return 0;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun #endif
296