17bddac94SSimon Glass /* 27bddac94SSimon Glass * Copyright (c) 2014 The Chromium OS Authors. 37bddac94SSimon Glass * 452f952bfSBin Meng * Part of this file is adapted from coreboot 552f952bfSBin Meng * src/arch/x86/include/arch/cpu.h and 652f952bfSBin Meng * src/arch/x86/lib/cpu.c 752f952bfSBin Meng * 87bddac94SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 97bddac94SSimon Glass */ 107bddac94SSimon Glass 1152f952bfSBin Meng #ifndef _ASM_CPU_H 1252f952bfSBin Meng #define _ASM_CPU_H 1352f952bfSBin Meng 1452f952bfSBin Meng enum { 1552f952bfSBin Meng X86_VENDOR_INVALID = 0, 1652f952bfSBin Meng X86_VENDOR_INTEL, 1752f952bfSBin Meng X86_VENDOR_CYRIX, 1852f952bfSBin Meng X86_VENDOR_AMD, 1952f952bfSBin Meng X86_VENDOR_UMC, 2052f952bfSBin Meng X86_VENDOR_NEXGEN, 2152f952bfSBin Meng X86_VENDOR_CENTAUR, 2252f952bfSBin Meng X86_VENDOR_RISE, 2352f952bfSBin Meng X86_VENDOR_TRANSMETA, 2452f952bfSBin Meng X86_VENDOR_NSC, 2552f952bfSBin Meng X86_VENDOR_SIS, 2652f952bfSBin Meng X86_VENDOR_ANY = 0xfe, 2752f952bfSBin Meng X86_VENDOR_UNKNOWN = 0xff 2852f952bfSBin Meng }; 2952f952bfSBin Meng 307dfe8bdeSSimon Glass /* Global descriptor table (GDT) bits */ 317dfe8bdeSSimon Glass enum { 327dfe8bdeSSimon Glass GDT_4KB = 1ULL << 55, 337dfe8bdeSSimon Glass GDT_32BIT = 1ULL << 54, 347dfe8bdeSSimon Glass GDT_LONG = 1ULL << 53, 357dfe8bdeSSimon Glass GDT_PRESENT = 1ULL << 47, 367dfe8bdeSSimon Glass GDT_NOTSYS = 1ULL << 44, 377dfe8bdeSSimon Glass GDT_CODE = 1ULL << 43, 387dfe8bdeSSimon Glass GDT_LIMIT_LOW_SHIFT = 0, 397dfe8bdeSSimon Glass GDT_LIMIT_LOW_MASK = 0xffff, 407dfe8bdeSSimon Glass GDT_LIMIT_HIGH_SHIFT = 48, 417dfe8bdeSSimon Glass GDT_LIMIT_HIGH_MASK = 0xf, 427dfe8bdeSSimon Glass GDT_BASE_LOW_SHIFT = 16, 437dfe8bdeSSimon Glass GDT_BASE_LOW_MASK = 0xffff, 447dfe8bdeSSimon Glass GDT_BASE_HIGH_SHIFT = 56, 457dfe8bdeSSimon Glass GDT_BASE_HIGH_MASK = 0xf, 467dfe8bdeSSimon Glass }; 477dfe8bdeSSimon Glass 4898655f3aSSimon Glass /* 4998655f3aSSimon Glass * System controllers in an x86 system. We mostly need to just find these and 5025d5352cSSimon Glass * use them on PCI. At some point these might have their own uclass (e.g. 5125d5352cSSimon Glass * UCLASS_VIDEO for the GMA device). 5298655f3aSSimon Glass */ 5398655f3aSSimon Glass enum { 5498655f3aSSimon Glass X86_NONE, 5598655f3aSSimon Glass X86_SYSCON_ME, /* Intel Management Engine */ 567ac99be6SSimon Glass X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ 57*ca0d29e4SAndy Shevchenko X86_SYSCON_PMU, /* Power Management Unit */ 58bb416465SFelipe Balbi X86_SYSCON_SCU, /* System Controller Unit */ 5998655f3aSSimon Glass }; 6098655f3aSSimon Glass 6152f952bfSBin Meng struct cpuid_result { 6252f952bfSBin Meng uint32_t eax; 6352f952bfSBin Meng uint32_t ebx; 6452f952bfSBin Meng uint32_t ecx; 6552f952bfSBin Meng uint32_t edx; 6652f952bfSBin Meng }; 6752f952bfSBin Meng 6852f952bfSBin Meng /* 6952f952bfSBin Meng * Generic CPUID function 7052f952bfSBin Meng */ 7152f952bfSBin Meng static inline struct cpuid_result cpuid(int op) 7252f952bfSBin Meng { 7352f952bfSBin Meng struct cpuid_result result; 7452f952bfSBin Meng asm volatile( 7552f952bfSBin Meng "mov %%ebx, %%edi;" 7652f952bfSBin Meng "cpuid;" 7752f952bfSBin Meng "mov %%ebx, %%esi;" 7852f952bfSBin Meng "mov %%edi, %%ebx;" 7952f952bfSBin Meng : "=a" (result.eax), 8052f952bfSBin Meng "=S" (result.ebx), 8152f952bfSBin Meng "=c" (result.ecx), 8252f952bfSBin Meng "=d" (result.edx) 8352f952bfSBin Meng : "0" (op) 8452f952bfSBin Meng : "edi"); 8552f952bfSBin Meng return result; 8652f952bfSBin Meng } 8752f952bfSBin Meng 8852f952bfSBin Meng /* 8952f952bfSBin Meng * Generic Extended CPUID function 9052f952bfSBin Meng */ 9152f952bfSBin Meng static inline struct cpuid_result cpuid_ext(int op, unsigned ecx) 9252f952bfSBin Meng { 9352f952bfSBin Meng struct cpuid_result result; 9452f952bfSBin Meng asm volatile( 9552f952bfSBin Meng "mov %%ebx, %%edi;" 9652f952bfSBin Meng "cpuid;" 9752f952bfSBin Meng "mov %%ebx, %%esi;" 9852f952bfSBin Meng "mov %%edi, %%ebx;" 9952f952bfSBin Meng : "=a" (result.eax), 10052f952bfSBin Meng "=S" (result.ebx), 10152f952bfSBin Meng "=c" (result.ecx), 10252f952bfSBin Meng "=d" (result.edx) 10352f952bfSBin Meng : "0" (op), "2" (ecx) 10452f952bfSBin Meng : "edi"); 10552f952bfSBin Meng return result; 10652f952bfSBin Meng } 10752f952bfSBin Meng 10852f952bfSBin Meng /* 10952f952bfSBin Meng * CPUID functions returning a single datum 11052f952bfSBin Meng */ 11152f952bfSBin Meng static inline unsigned int cpuid_eax(unsigned int op) 11252f952bfSBin Meng { 11352f952bfSBin Meng unsigned int eax; 11452f952bfSBin Meng 11552f952bfSBin Meng __asm__("mov %%ebx, %%edi;" 11652f952bfSBin Meng "cpuid;" 11752f952bfSBin Meng "mov %%edi, %%ebx;" 11852f952bfSBin Meng : "=a" (eax) 11952f952bfSBin Meng : "0" (op) 12052f952bfSBin Meng : "ecx", "edx", "edi"); 12152f952bfSBin Meng return eax; 12252f952bfSBin Meng } 12352f952bfSBin Meng 12452f952bfSBin Meng static inline unsigned int cpuid_ebx(unsigned int op) 12552f952bfSBin Meng { 12652f952bfSBin Meng unsigned int eax, ebx; 12752f952bfSBin Meng 12852f952bfSBin Meng __asm__("mov %%ebx, %%edi;" 12952f952bfSBin Meng "cpuid;" 13052f952bfSBin Meng "mov %%ebx, %%esi;" 13152f952bfSBin Meng "mov %%edi, %%ebx;" 13252f952bfSBin Meng : "=a" (eax), "=S" (ebx) 13352f952bfSBin Meng : "0" (op) 13452f952bfSBin Meng : "ecx", "edx", "edi"); 13552f952bfSBin Meng return ebx; 13652f952bfSBin Meng } 13752f952bfSBin Meng 13852f952bfSBin Meng static inline unsigned int cpuid_ecx(unsigned int op) 13952f952bfSBin Meng { 14052f952bfSBin Meng unsigned int eax, ecx; 14152f952bfSBin Meng 14252f952bfSBin Meng __asm__("mov %%ebx, %%edi;" 14352f952bfSBin Meng "cpuid;" 14452f952bfSBin Meng "mov %%edi, %%ebx;" 14552f952bfSBin Meng : "=a" (eax), "=c" (ecx) 14652f952bfSBin Meng : "0" (op) 14752f952bfSBin Meng : "edx", "edi"); 14852f952bfSBin Meng return ecx; 14952f952bfSBin Meng } 15052f952bfSBin Meng 15152f952bfSBin Meng static inline unsigned int cpuid_edx(unsigned int op) 15252f952bfSBin Meng { 15352f952bfSBin Meng unsigned int eax, edx; 15452f952bfSBin Meng 15552f952bfSBin Meng __asm__("mov %%ebx, %%edi;" 15652f952bfSBin Meng "cpuid;" 15752f952bfSBin Meng "mov %%edi, %%ebx;" 15852f952bfSBin Meng : "=a" (eax), "=d" (edx) 15952f952bfSBin Meng : "0" (op) 16052f952bfSBin Meng : "ecx", "edi"); 16152f952bfSBin Meng return edx; 16252f952bfSBin Meng } 16352f952bfSBin Meng 1644b57414aSSimon Glass #if !CONFIG_IS_ENABLED(X86_64) 1654b57414aSSimon Glass 16652f952bfSBin Meng /* Standard macro to see if a specific flag is changeable */ 16752f952bfSBin Meng static inline int flag_is_changeable_p(uint32_t flag) 16852f952bfSBin Meng { 16952f952bfSBin Meng uint32_t f1, f2; 17052f952bfSBin Meng 17152f952bfSBin Meng asm( 17252f952bfSBin Meng "pushfl\n\t" 17352f952bfSBin Meng "pushfl\n\t" 17452f952bfSBin Meng "popl %0\n\t" 17552f952bfSBin Meng "movl %0,%1\n\t" 17652f952bfSBin Meng "xorl %2,%0\n\t" 17752f952bfSBin Meng "pushl %0\n\t" 17852f952bfSBin Meng "popfl\n\t" 17952f952bfSBin Meng "pushfl\n\t" 18052f952bfSBin Meng "popl %0\n\t" 18152f952bfSBin Meng "popfl\n\t" 18252f952bfSBin Meng : "=&r" (f1), "=&r" (f2) 18352f952bfSBin Meng : "ir" (flag)); 18452f952bfSBin Meng return ((f1^f2) & flag) != 0; 18552f952bfSBin Meng } 1864b57414aSSimon Glass #endif 1877bddac94SSimon Glass 188837a136fSSimon Glass static inline void mfence(void) 189837a136fSSimon Glass { 190837a136fSSimon Glass __asm__ __volatile__("mfence" : : : "memory"); 191837a136fSSimon Glass } 192837a136fSSimon Glass 1937bddac94SSimon Glass /** 1947bddac94SSimon Glass * cpu_enable_paging_pae() - Enable PAE-paging 1957bddac94SSimon Glass * 19652f952bfSBin Meng * @cr3: Value to set in cr3 (PDPT or PML4T) 1977bddac94SSimon Glass */ 1987bddac94SSimon Glass void cpu_enable_paging_pae(ulong cr3); 1997bddac94SSimon Glass 2007bddac94SSimon Glass /** 2017bddac94SSimon Glass * cpu_disable_paging_pae() - Disable paging and PAE 2027bddac94SSimon Glass */ 2037bddac94SSimon Glass void cpu_disable_paging_pae(void); 2047bddac94SSimon Glass 20592cc94a1SSimon Glass /** 20692cc94a1SSimon Glass * cpu_has_64bit() - Check if the CPU has 64-bit support 20792cc94a1SSimon Glass * 20892cc94a1SSimon Glass * @return 1 if this CPU supports long mode (64-bit), 0 if not 20992cc94a1SSimon Glass */ 21092cc94a1SSimon Glass int cpu_has_64bit(void); 21192cc94a1SSimon Glass 212200182a7SSimon Glass /** 21352f952bfSBin Meng * cpu_vendor_name() - Get CPU vendor name 21452f952bfSBin Meng * 21552f952bfSBin Meng * @vendor: CPU vendor enumeration number 21652f952bfSBin Meng * 21752f952bfSBin Meng * @return: Address to hold the CPU vendor name string 21852f952bfSBin Meng */ 21952f952bfSBin Meng const char *cpu_vendor_name(int vendor); 22052f952bfSBin Meng 221727c1a98SSimon Glass #define CPU_MAX_NAME_LEN 49 222727c1a98SSimon Glass 22352f952bfSBin Meng /** 224727c1a98SSimon Glass * cpu_get_name() - Get the name of the current cpu 22552f952bfSBin Meng * 226727c1a98SSimon Glass * @name: Place to put name, which must be CPU_MAX_NAME_LEN bytes including 227727c1a98SSimon Glass * @return pointer to name, which will likely be a few bytes after the start 228727c1a98SSimon Glass * of @name 229727c1a98SSimon Glass * \0 terminator 23052f952bfSBin Meng */ 231727c1a98SSimon Glass char *cpu_get_name(char *name); 23252f952bfSBin Meng 23352f952bfSBin Meng /** 234200182a7SSimon Glass * cpu_call64() - Jump to a 64-bit Linux kernel (internal function) 235200182a7SSimon Glass * 236200182a7SSimon Glass * The kernel is uncompressed and the 64-bit entry point is expected to be 237200182a7SSimon Glass * at @target. 238200182a7SSimon Glass * 239200182a7SSimon Glass * This function is used internally - see cpu_jump_to_64bit() for a more 240200182a7SSimon Glass * useful function. 241200182a7SSimon Glass * 242200182a7SSimon Glass * @pgtable: Address of 24KB area containing the page table 243200182a7SSimon Glass * @setup_base: Pointer to the setup.bin information for the kernel 244200182a7SSimon Glass * @target: Pointer to the start of the kernel image 245200182a7SSimon Glass */ 246200182a7SSimon Glass void cpu_call64(ulong pgtable, ulong setup_base, ulong target); 247200182a7SSimon Glass 248200182a7SSimon Glass /** 2496f92ed8fSSimon Glass * cpu_call32() - Jump to a 32-bit entry point 2506f92ed8fSSimon Glass * 2516f92ed8fSSimon Glass * @code_seg32: 32-bit code segment to use (GDT offset, e.g. 0x20) 2526f92ed8fSSimon Glass * @target: Pointer to the start of the 32-bit U-Boot image/entry point 2536f92ed8fSSimon Glass * @table: Pointer to start of info table to pass to U-Boot 2546f92ed8fSSimon Glass */ 2556f92ed8fSSimon Glass void cpu_call32(ulong code_seg32, ulong target, ulong table); 2566f92ed8fSSimon Glass 2576f92ed8fSSimon Glass /** 258200182a7SSimon Glass * cpu_jump_to_64bit() - Jump to a 64-bit Linux kernel 259200182a7SSimon Glass * 260200182a7SSimon Glass * The kernel is uncompressed and the 64-bit entry point is expected to be 261200182a7SSimon Glass * at @target. 262200182a7SSimon Glass * 263200182a7SSimon Glass * @setup_base: Pointer to the setup.bin information for the kernel 264200182a7SSimon Glass * @target: Pointer to the start of the kernel image 265200182a7SSimon Glass */ 266200182a7SSimon Glass int cpu_jump_to_64bit(ulong setup_base, ulong target); 267200182a7SSimon Glass 268342727acSSimon Glass /** 269fa5fcb3bSSimon Glass * cpu_jump_to_64bit_uboot() - special function to jump from SPL to U-Boot 270fa5fcb3bSSimon Glass * 271fa5fcb3bSSimon Glass * This handles calling from 32-bit SPL to 64-bit U-Boot. 272fa5fcb3bSSimon Glass * 273fa5fcb3bSSimon Glass * @target: Address of U-Boot in RAM 274fa5fcb3bSSimon Glass */ 275fa5fcb3bSSimon Glass int cpu_jump_to_64bit_uboot(ulong target); 276fa5fcb3bSSimon Glass 277fa5fcb3bSSimon Glass /** 278342727acSSimon Glass * cpu_get_family_model() - Get the family and model for the CPU 279342727acSSimon Glass * 280342727acSSimon Glass * @return the CPU ID masked with 0x0fff0ff0 281342727acSSimon Glass */ 282342727acSSimon Glass u32 cpu_get_family_model(void); 283342727acSSimon Glass 284342727acSSimon Glass /** 285342727acSSimon Glass * cpu_get_stepping() - Get the stepping value for the CPU 286342727acSSimon Glass * 287342727acSSimon Glass * @return the CPU ID masked with 0xf 288342727acSSimon Glass */ 289342727acSSimon Glass u32 cpu_get_stepping(void); 290342727acSSimon Glass 2910adf8d35SSimon Glass /** 2920adf8d35SSimon Glass * cpu_run_reference_code() - Run the platform reference code 2930adf8d35SSimon Glass * 2940adf8d35SSimon Glass * Some platforms require a binary blob to be executed once SDRAM is 2950adf8d35SSimon Glass * available. This is used to set up various platform features, such as the 2960adf8d35SSimon Glass * platform controller hub (PCH). This function should be implemented by the 2970adf8d35SSimon Glass * CPU-specific code. 2980adf8d35SSimon Glass * 2990adf8d35SSimon Glass * @return 0 on success, -ve on failure 3000adf8d35SSimon Glass */ 3010adf8d35SSimon Glass int cpu_run_reference_code(void); 3020adf8d35SSimon Glass 3037bddac94SSimon Glass #endif 304