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