]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - arch/x86/cpu/ivybridge/cpu.c
x86: ivybridge: Perform Intel microcode update on boot
[karo-tx-uboot.git] / arch / x86 / cpu / ivybridge / cpu.c
1 /*
2  * Copyright (c) 2014 Google, Inc
3  * (C) Copyright 2008
4  * Graeme Russ, graeme.russ@gmail.com.
5  *
6  * Some portions from coreboot src/mainboard/google/link/romstage.c
7  * Copyright (C) 2007-2010 coresystems GmbH
8  * Copyright (C) 2011 Google Inc.
9  *
10  * SPDX-License-Identifier:     GPL-2.0
11  */
12
13 #include <common.h>
14 #include <errno.h>
15 #include <fdtdec.h>
16 #include <asm/cpu.h>
17 #include <asm/io.h>
18 #include <asm/msr.h>
19 #include <asm/mtrr.h>
20 #include <asm/pci.h>
21 #include <asm/post.h>
22 #include <asm/processor.h>
23 #include <asm/arch/model_206ax.h>
24 #include <asm/arch/microcode.h>
25 #include <asm/arch/pch.h>
26
27 DECLARE_GLOBAL_DATA_PTR;
28
29 static void enable_port80_on_lpc(struct pci_controller *hose, pci_dev_t dev)
30 {
31         /* Enable port 80 POST on LPC */
32         pci_hose_write_config_dword(hose, dev, PCH_RCBA_BASE, DEFAULT_RCBA | 1);
33         clrbits_le32(RCB_REG(GCS), 4);
34 }
35
36 /*
37  * Enable Prefetching and Caching.
38  */
39 static void enable_spi_prefetch(struct pci_controller *hose, pci_dev_t dev)
40 {
41         u8 reg8;
42
43         pci_hose_read_config_byte(hose, dev, 0xdc, &reg8);
44         reg8 &= ~(3 << 2);
45         reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
46         pci_hose_write_config_byte(hose, dev, 0xdc, reg8);
47 }
48
49 static void set_var_mtrr(
50         unsigned reg, unsigned base, unsigned size, unsigned type)
51
52 {
53         /* Bit Bit 32-35 of MTRRphysMask should be set to 1 */
54         /* FIXME: It only support 4G less range */
55         wrmsr(MTRRphysBase_MSR(reg), base | type, 0);
56         wrmsr(MTRRphysMask_MSR(reg), ~(size - 1) | MTRRphysMaskValid,
57               (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1);
58 }
59
60 static void enable_rom_caching(void)
61 {
62         disable_caches();
63         set_var_mtrr(1, 0xffc00000, 4 << 20, MTRR_TYPE_WRPROT);
64         enable_caches();
65
66         /* Enable Variable MTRRs */
67         wrmsr(MTRRdefType_MSR, 0x800, 0);
68 }
69
70 static int set_flex_ratio_to_tdp_nominal(void)
71 {
72         msr_t flex_ratio, msr;
73         u8 nominal_ratio;
74
75         /* Minimum CPU revision for configurable TDP support */
76         if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
77                 return -EINVAL;
78
79         /* Check for Flex Ratio support */
80         flex_ratio = msr_read(MSR_FLEX_RATIO);
81         if (!(flex_ratio.lo & FLEX_RATIO_EN))
82                 return -EINVAL;
83
84         /* Check for >0 configurable TDPs */
85         msr = msr_read(MSR_PLATFORM_INFO);
86         if (((msr.hi >> 1) & 3) == 0)
87                 return -EINVAL;
88
89         /* Use nominal TDP ratio for flex ratio */
90         msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
91         nominal_ratio = msr.lo & 0xff;
92
93         /* See if flex ratio is already set to nominal TDP ratio */
94         if (((flex_ratio.lo >> 8) & 0xff) == nominal_ratio)
95                 return 0;
96
97         /* Set flex ratio to nominal TDP ratio */
98         flex_ratio.lo &= ~0xff00;
99         flex_ratio.lo |= nominal_ratio << 8;
100         flex_ratio.lo |= FLEX_RATIO_LOCK;
101         msr_write(MSR_FLEX_RATIO, flex_ratio);
102
103         /* Set flex ratio in soft reset data register bits 11:6 */
104         clrsetbits_le32(RCB_REG(SOFT_RESET_DATA), 0x3f << 6,
105                         (nominal_ratio & 0x3f) << 6);
106
107         /* Set soft reset control to use register value */
108         setbits_le32(RCB_REG(SOFT_RESET_CTRL), 1);
109
110         /* Issue warm reset, will be "CPU only" due to soft reset data */
111         outb(0x0, PORT_RESET);
112         outb(0x6, PORT_RESET);
113         cpu_hlt();
114
115         /* Not reached */
116         return -EINVAL;
117 }
118
119 static void set_spi_speed(void)
120 {
121         u32 fdod;
122
123         /* Observe SPI Descriptor Component Section 0 */
124         writel(0x1000, RCB_REG(SPI_DESC_COMP0));
125
126         /* Extract the1 Write/Erase SPI Frequency from descriptor */
127         fdod = readl(RCB_REG(SPI_FREQ_WR_ERA));
128         fdod >>= 24;
129         fdod &= 7;
130
131         /* Set Software Sequence frequency to match */
132         clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
133 }
134
135 int arch_cpu_init(void)
136 {
137         const void *blob = gd->fdt_blob;
138         struct pci_controller *hose;
139         int node;
140         int ret;
141
142         post_code(POST_CPU_INIT);
143         timer_set_base(rdtsc());
144
145         ret = x86_cpu_init_f();
146         if (ret)
147                 return ret;
148
149         ret = pci_early_init_hose(&hose);
150         if (ret)
151                 return ret;
152
153         node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_LPC);
154         if (node < 0)
155                 return -ENOENT;
156         ret = lpc_early_init(gd->fdt_blob, node, PCH_LPC_DEV);
157         if (ret)
158                 return ret;
159
160         enable_spi_prefetch(hose, PCH_LPC_DEV);
161
162         /* This is already done in start.S, but let's do it in C */
163         enable_port80_on_lpc(hose, PCH_LPC_DEV);
164
165         /* already done in car.S */
166         if (false)
167                 enable_rom_caching();
168
169         set_spi_speed();
170
171         /*
172          * We should do as little as possible before the serial console is
173          * up. Perhaps this should move to later. Our next lot of init
174          * happens in print_cpuinfo() when we have a console
175          */
176         ret = set_flex_ratio_to_tdp_nominal();
177         if (ret)
178                 return ret;
179
180         return 0;
181 }
182
183 static int report_bist_failure(void)
184 {
185         if (gd->arch.bist != 0) {
186                 printf("BIST failed: %08x\n", gd->arch.bist);
187                 return -EFAULT;
188         }
189
190         return 0;
191 }
192
193 int print_cpuinfo(void)
194 {
195         char processor_name[CPU_MAX_NAME_LEN];
196         const char *name;
197         int ret;
198
199         /* Halt if there was a built in self test failure */
200         ret = report_bist_failure();
201         if (ret)
202                 return ret;
203
204         ret = microcode_update_intel();
205         if (ret && ret != -ENOENT && ret != -EEXIST)
206                 return ret;
207
208         /* Print processor name */
209         name = cpu_get_name(processor_name);
210         printf("CPU:   %s\n", name);
211
212         return 0;
213 }