2 * Copyright (c) 2014 Google, Inc
4 * Graeme Russ, graeme.russ@gmail.com.
6 * Some portions from coreboot src/mainboard/google/link/romstage.c
7 * and src/cpu/intel/model_206ax/bootblock.c
8 * Copyright (C) 2007-2010 coresystems GmbH
9 * Copyright (C) 2011 Google Inc.
11 * SPDX-License-Identifier: GPL-2.0
20 #include <asm/lapic.h>
25 #include <asm/processor.h>
26 #include <asm/arch/model_206ax.h>
27 #include <asm/arch/microcode.h>
28 #include <asm/arch/pch.h>
29 #include <asm/arch/sandybridge.h>
31 DECLARE_GLOBAL_DATA_PTR;
33 static int set_flex_ratio_to_tdp_nominal(void)
35 msr_t flex_ratio, msr;
38 /* Minimum CPU revision for configurable TDP support */
39 if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
42 /* Check for Flex Ratio support */
43 flex_ratio = msr_read(MSR_FLEX_RATIO);
44 if (!(flex_ratio.lo & FLEX_RATIO_EN))
47 /* Check for >0 configurable TDPs */
48 msr = msr_read(MSR_PLATFORM_INFO);
49 if (((msr.hi >> 1) & 3) == 0)
52 /* Use nominal TDP ratio for flex ratio */
53 msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
54 nominal_ratio = msr.lo & 0xff;
56 /* See if flex ratio is already set to nominal TDP ratio */
57 if (((flex_ratio.lo >> 8) & 0xff) == nominal_ratio)
60 /* Set flex ratio to nominal TDP ratio */
61 flex_ratio.lo &= ~0xff00;
62 flex_ratio.lo |= nominal_ratio << 8;
63 flex_ratio.lo |= FLEX_RATIO_LOCK;
64 msr_write(MSR_FLEX_RATIO, flex_ratio);
66 /* Set flex ratio in soft reset data register bits 11:6 */
67 clrsetbits_le32(RCB_REG(SOFT_RESET_DATA), 0x3f << 6,
68 (nominal_ratio & 0x3f) << 6);
70 /* Set soft reset control to use register value */
71 setbits_le32(RCB_REG(SOFT_RESET_CTRL), 1);
73 /* Issue warm reset, will be "CPU only" due to soft reset data */
74 outb(0x0, PORT_RESET);
75 outb(SYS_RST | RST_CPU, PORT_RESET);
82 int arch_cpu_init(void)
84 post_code(POST_CPU_INIT);
86 return x86_cpu_init_f();
89 int arch_cpu_init_dm(void)
91 struct pci_controller *hose;
92 struct udevice *bus, *dev;
96 ret = uclass_get_device(UCLASS_PCI, 0, &bus);
101 hose = dev_get_uclass_priv(bus);
103 /* TODO(sjg@chromium.org): Get rid of gd->hose */
106 ret = uclass_first_device(UCLASS_LPC, &dev);
111 * We should do as little as possible before the serial console is
112 * up. Perhaps this should move to later. Our next lot of init
113 * happens in print_cpuinfo() when we have a console
115 ret = set_flex_ratio_to_tdp_nominal();
122 static int enable_smbus(void)
127 /* Set the SMBus device statically. */
128 dev = PCI_BDF(0x0, 0x1f, 0x3);
130 /* Check to make sure we've got the right device. */
131 value = x86_pci_read_config16(dev, 0x0);
132 if (value != 0x8086) {
133 printf("SMBus controller not found\n");
137 /* Set SMBus I/O base. */
138 x86_pci_write_config32(dev, SMB_BASE,
139 SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
141 /* Set SMBus enable. */
142 x86_pci_write_config8(dev, HOSTC, HST_EN);
144 /* Set SMBus I/O space enable. */
145 x86_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
147 /* Disable interrupt generation. */
148 outb(0, SMBUS_IO_BASE + SMBHSTCTL);
150 /* Clear any lingering errors, so transactions can run. */
151 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
152 debug("SMBus controller enabled\n");
157 #define PCH_EHCI0_TEMP_BAR0 0xe8000000
158 #define PCH_EHCI1_TEMP_BAR0 0xe8000400
159 #define PCH_XHCI_TEMP_BAR0 0xe8001000
162 * Setup USB controller MMIO BAR to prevent the reference code from
163 * resetting the controller.
165 * The BAR will be re-assigned during device enumeration so these are only
168 * This is used to speed up the resume path.
170 static void enable_usb_bar(void)
172 pci_dev_t usb0 = PCH_EHCI1_DEV;
173 pci_dev_t usb1 = PCH_EHCI2_DEV;
174 pci_dev_t usb3 = PCH_XHCI_DEV;
177 /* USB Controller 1 */
178 x86_pci_write_config32(usb0, PCI_BASE_ADDRESS_0,
179 PCH_EHCI0_TEMP_BAR0);
180 cmd = x86_pci_read_config32(usb0, PCI_COMMAND);
181 cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
182 x86_pci_write_config32(usb0, PCI_COMMAND, cmd);
184 /* USB Controller 1 */
185 x86_pci_write_config32(usb1, PCI_BASE_ADDRESS_0,
186 PCH_EHCI1_TEMP_BAR0);
187 cmd = x86_pci_read_config32(usb1, PCI_COMMAND);
188 cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
189 x86_pci_write_config32(usb1, PCI_COMMAND, cmd);
191 /* USB3 Controller */
192 x86_pci_write_config32(usb3, PCI_BASE_ADDRESS_0,
194 cmd = x86_pci_read_config32(usb3, PCI_COMMAND);
195 cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
196 x86_pci_write_config32(usb3, PCI_COMMAND, cmd);
199 static int report_bist_failure(void)
201 if (gd->arch.bist != 0) {
202 post_code(POST_BIST_FAILURE);
203 printf("BIST failed: %08x\n", gd->arch.bist);
210 int print_cpuinfo(void)
212 enum pei_boot_mode_t boot_mode = PEI_BOOT_NONE;
213 char processor_name[CPU_MAX_NAME_LEN];
219 /* Halt if there was a built in self test failure */
220 ret = report_bist_failure();
226 ret = microcode_update_intel();
230 /* Enable upper 128bytes of CMOS */
231 writel(1 << 2, RCB_REG(RC));
233 /* TODO: cmos_post_init() */
234 if (readl(MCHBAR_REG(SSKPD)) == 0xCAFE) {
235 debug("soft reset detected\n");
236 boot_mode = PEI_BOOT_SOFT_RESET;
238 /* System is not happy after keyboard reset... */
239 debug("Issuing CF9 warm reset\n");
243 /* Early chipset init required before RAM init can work */
244 sandybridge_early_init(SANDYBRIDGE_MOBILE);
246 /* Check PM1_STS[15] to see if we are waking from Sx */
247 pm1_sts = inw(DEFAULT_PMBASE + PM1_STS);
249 /* Read PM1_CNT[12:10] to determine which Sx state */
250 pm1_cnt = inl(DEFAULT_PMBASE + PM1_CNT);
252 if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) {
253 debug("Resume from S3 detected, but disabled.\n");
256 * TODO: An indication of life might be possible here (e.g.
260 post_code(POST_EARLY_INIT);
262 /* Enable SPD ROMs and DDR-III DRAM */
263 ret = enable_smbus();
267 /* Prepare USB controller early in S3 resume */
268 if (boot_mode == PEI_BOOT_RESUME)
271 gd->arch.pei_boot_mode = boot_mode;
273 /* TODO: Move this to the board or driver */
274 x86_pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE | 1);
275 x86_pci_write_config32(PCH_LPC_DEV, GPIO_CNTL, 0x10);
277 /* Print processor name */
278 name = cpu_get_name(processor_name);
279 printf("CPU: %s\n", name);
281 post_code(POST_CPU_INFO);
286 void board_debug_uart_init(void)
288 /* This enables the debug UART */
289 pci_x86_write_config(NULL, PCH_LPC_DEV, LPC_EN, COMA_LPC_EN,