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 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 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 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 92fea25720SGraeme Russ void flush_cache(unsigned long dummy1, unsigned long dummy2) 93fea25720SGraeme Russ { 94fea25720SGraeme Russ asm("wbinvd\n"); 95fea25720SGraeme Russ } 96fea25720SGraeme Russ 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 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 */ 111095593c0SStefan Reinauer void flush_dcache_range(unsigned long start, unsigned long stop) 112095593c0SStefan Reinauer { 113095593c0SStefan Reinauer } 114095593c0SStefan Reinauer 115095593c0SStefan Reinauer void invalidate_dcache_range(unsigned long start, unsigned long stop) 116095593c0SStefan Reinauer { 117095593c0SStefan Reinauer } 11889371409SSimon Glass 11989371409SSimon Glass void dcache_enable(void) 12089371409SSimon Glass { 12189371409SSimon Glass enable_caches(); 12289371409SSimon Glass } 12389371409SSimon Glass 12489371409SSimon Glass void dcache_disable(void) 12589371409SSimon Glass { 12689371409SSimon Glass disable_caches(); 12789371409SSimon Glass } 12889371409SSimon Glass 12989371409SSimon Glass void icache_enable(void) 13089371409SSimon Glass { 13189371409SSimon Glass } 13289371409SSimon Glass 13389371409SSimon Glass void icache_disable(void) 13489371409SSimon Glass { 13589371409SSimon Glass } 13689371409SSimon Glass 13789371409SSimon Glass int icache_status(void) 13889371409SSimon Glass { 13989371409SSimon Glass return 1; 14089371409SSimon Glass } 1417bddac94SSimon Glass 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 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 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 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 */ 2021e2f7b9eSBin Meng __weak void board_final_cleanup(void) 2031e2f7b9eSBin Meng { 2041e2f7b9eSBin Meng } 2051e2f7b9eSBin Meng 2065e2400e8SBin Meng int last_stage_init(void) 2075e2400e8SBin Meng { 208bffd7981SBin Meng board_final_cleanup(); 209bffd7981SBin Meng 2103a34cae0SBin Meng #if CONFIG_HAVE_ACPI_RESUME 211*0f4e2588SBin Meng struct acpi_fadt *fadt = acpi_find_fadt(); 2123a34cae0SBin Meng 213*0f4e2588SBin Meng if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3) 214*0f4e2588SBin 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 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 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 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 281ba65808eSBin Meng #if defined(CONFIG_HAVE_ACPI_RESUME) && defined(CONFIG_HAVE_FSP) 282ba65808eSBin Meng /* 283ba65808eSBin Meng * Save stack address to CMOS so that at next S3 boot, 284ba65808eSBin Meng * we can use it as the stack address for fsp_contiue() 285ba65808eSBin Meng */ 286ba65808eSBin Meng fsp_save_s3_stack(); 287ba65808eSBin Meng #endif 288ba65808eSBin Meng 289d19c9074SBin Meng return 0; 2900c2b7eefSBin Meng } 2910c2b7eefSBin Meng #endif 292