Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[oweals/u-boot.git] / arch / x86 / cpu / cpu.c
index a4e639dcf3379f26613aa7ab0888905488f2e848..bb4a110c0072e0d96b8efee2b58069233de7fdad 100644 (file)
 
 #include <common.h>
 #include <command.h>
+#include <cpu.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <asm/control_regs.h>
 #include <asm/cpu.h>
+#include <asm/post.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
 #include <asm/interrupt.h>
+#include <asm/tables.h>
 #include <linux/compiler.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -123,7 +127,7 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries)
 {
        struct gdt_ptr gdt;
 
-       gdt.len = (num_entries * 8) - 1;
+       gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1;
        gdt.ptr = (u32)boot_gdt;
 
        asm volatile("lgdtl %0\n" : : "m" (gdt));
@@ -131,6 +135,7 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries)
 
 void setup_gdt(gd_t *id, u64 *gdt_addr)
 {
+       id->arch.gdt = gdt_addr;
        /* CS: code, read/execute, 4 GB, base 0 */
        gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff);
 
@@ -143,10 +148,13 @@ void setup_gdt(gd_t *id, u64 *gdt_addr)
                     (ulong)&id->arch.gd_addr, 0xfffff);
 
        /* 16-bit CS: code, read/execute, 64 kB, base 0 */
-       gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff);
+       gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff);
 
        /* 16-bit DS: data, read/write, 64 kB, base 0 */
-       gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff);
+       gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff);
+
+       gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff);
+       gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff);
 
        load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES);
        load_ds(X86_GDT_ENTRY_32BIT_DS);
@@ -159,7 +167,7 @@ void setup_gdt(gd_t *id, u64 *gdt_addr)
 int __weak x86_cleanup_before_linux(void)
 {
 #ifdef CONFIG_BOOTSTAGE_STASH
-       bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH,
+       bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
                        CONFIG_BOOTSTAGE_STASH_SIZE);
 #endif
 
@@ -219,6 +227,11 @@ static bool has_cpuid(void)
        return flag_is_changeable_p(X86_EFLAGS_ID);
 }
 
+static bool has_mtrr(void)
+{
+       return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
+}
+
 static int build_vendor_name(char *vendor_name)
 {
        struct cpuid_result result;
@@ -238,6 +251,7 @@ static void identify_cpu(struct cpu_device_id *cpu)
        int i;
 
        vendor_name[0] = '\0'; /* Unset */
+       cpu->device = 0; /* fix gcc 4.4.4 warning */
 
        /* Find the id and vendor_name */
        if (!has_cpuid()) {
@@ -313,18 +327,12 @@ int x86_cpu_init_f(void)
                gd->arch.x86_model = c.x86_model;
                gd->arch.x86_mask = c.x86_mask;
                gd->arch.x86_device = cpu.device;
-       }
 
-       return 0;
-}
+               gd->arch.has_mtrr = has_mtrr();
+       }
 
-int x86_cpu_init_r(void)
-{
-       /* Initialize core interrupt and exception functionality of CPU */
-       cpu_init_interrupts();
        return 0;
 }
-int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r")));
 
 void x86_enable_caches(void)
 {
@@ -375,21 +383,17 @@ void  flush_cache(unsigned long dummy1, unsigned long dummy2)
        asm("wbinvd\n");
 }
 
-void __attribute__ ((regparm(0))) generate_gpf(void);
-
-/* segment 0x70 is an arbitrary segment which does not exist */
-asm(".globl generate_gpf\n"
-       ".hidden generate_gpf\n"
-       ".type generate_gpf, @function\n"
-       "generate_gpf:\n"
-       "ljmp   $0x70, $0x47114711\n");
-
 __weak void reset_cpu(ulong addr)
 {
-       printf("Resetting using x86 Triple Fault\n");
-       set_vector(13, generate_gpf);   /* general protection fault handler */
-       set_vector(8, generate_gpf);    /* double fault handler */
-       generate_gpf();                 /* start the show */
+       /* Do a hard reset through the chipset's reset control register */
+       outb(SYS_RST | RST_CPU, PORT_RESET);
+       for (;;)
+               cpu_hlt();
+}
+
+void x86_full_reset(void)
+{
+       outb(FULL_RST | SYS_RST | RST_CPU, PORT_RESET);
 }
 
 int dcache_status(void)
@@ -491,14 +495,14 @@ const char *cpu_vendor_name(int vendor)
        return name;
 }
 
-void fill_processor_name(char *processor_name)
+char *cpu_get_name(char *name)
 {
+       unsigned int *name_as_ints = (unsigned int *)name;
        struct cpuid_result regs;
-       char temp_processor_name[49];
-       char *processor_name_start;
-       unsigned int *name_as_ints = (unsigned int *)temp_processor_name;
+       char *ptr;
        int i;
 
+       /* This bit adds up to 48 bytes */
        for (i = 0; i < 3; i++) {
                regs = cpuid(0x80000002 + i);
                name_as_ints[i * 4 + 0] = regs.eax;
@@ -506,19 +510,27 @@ void fill_processor_name(char *processor_name)
                name_as_ints[i * 4 + 2] = regs.ecx;
                name_as_ints[i * 4 + 3] = regs.edx;
        }
-
-       temp_processor_name[48] = 0;
+       name[CPU_MAX_NAME_LEN - 1] = '\0';
 
        /* Skip leading spaces. */
-       processor_name_start = temp_processor_name;
-       while (*processor_name_start == ' ')
-               processor_name_start++;
+       ptr = name;
+       while (*ptr == ' ')
+               ptr++;
 
-       memset(processor_name, 0, 49);
-       strcpy(processor_name, processor_name_start);
+       return ptr;
 }
 
-int print_cpuinfo(void)
+int x86_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+       if (size < CPU_MAX_NAME_LEN)
+               return -ENOSPC;
+
+       cpu_get_name(buf);
+
+       return 0;
+}
+
+int default_print_cpuinfo(void)
 {
        printf("CPU: %s, vendor %s, device %xh\n",
               cpu_has_64bit() ? "x86_64" : "x86",
@@ -568,3 +580,61 @@ int cpu_jump_to_64bit(ulong setup_base, ulong target)
 
        return -EFAULT;
 }
+
+void show_boot_progress(int val)
+{
+#if MIN_PORT80_KCLOCKS_DELAY
+       /*
+        * Scale the time counter reading to avoid using 64 bit arithmetics.
+        * Can't use get_timer() here becuase it could be not yet
+        * initialized or even implemented.
+        */
+       if (!gd->arch.tsc_prev) {
+               gd->arch.tsc_base_kclocks = rdtsc() / 1000;
+               gd->arch.tsc_prev = 0;
+       } else {
+               uint32_t now;
+
+               do {
+                       now = rdtsc() / 1000 - gd->arch.tsc_base_kclocks;
+               } while (now < (gd->arch.tsc_prev + MIN_PORT80_KCLOCKS_DELAY));
+               gd->arch.tsc_prev = now;
+       }
+#endif
+       outb(val, POST_PORT);
+}
+
+#ifndef CONFIG_SYS_COREBOOT
+int last_stage_init(void)
+{
+       write_tables();
+
+       return 0;
+}
+#endif
+
+__weak int x86_init_cpus(void)
+{
+       return 0;
+}
+
+int cpu_init_r(void)
+{
+       return x86_init_cpus();
+}
+
+static const struct cpu_ops cpu_x86_ops = {
+       .get_desc       = x86_cpu_get_desc,
+};
+
+static const struct udevice_id cpu_x86_ids[] = {
+       { .compatible = "cpu-x86" },
+       { }
+};
+
+U_BOOT_DRIVER(cpu_x86_drv) = {
+       .name           = "cpu_x86",
+       .id             = UCLASS_CPU,
+       .of_match       = cpu_x86_ids,
+       .ops            = &cpu_x86_ops,
+};