1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2014 Google, Inc
4 * (C) Copyright 2008
5 * Graeme Russ, graeme.russ@gmail.com.
6 *
7 * Some portions from coreboot src/mainboard/google/link/romstage.c
8 * and src/cpu/intel/model_206ax/bootblock.c
9 * Copyright (C) 2007-2010 coresystems GmbH
10 * Copyright (C) 2011 Google Inc.
11 */
12
13#include <common.h>
14#include <cpu_func.h>
15#include <dm.h>
16#include <errno.h>
17#include <event.h>
18#include <fdtdec.h>
19#include <init.h>
20#include <log.h>
21#include <pch.h>
22#include <asm/cpu.h>
23#include <asm/cpu_common.h>
24#include <asm/global_data.h>
25#include <asm/intel_regs.h>
26#include <asm/io.h>
27#include <asm/lapic.h>
28#include <asm/lpc_common.h>
29#include <asm/microcode.h>
30#include <asm/msr.h>
31#include <asm/mtrr.h>
32#include <asm/pci.h>
33#include <asm/post.h>
34#include <asm/processor.h>
35#include <asm/arch/model_206ax.h>
36#include <asm/arch/pch.h>
37#include <asm/arch/sandybridge.h>
38
39DECLARE_GLOBAL_DATA_PTR;
40
41static int set_flex_ratio_to_tdp_nominal(void)
42{
43	/* Minimum CPU revision for configurable TDP support */
44	if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
45		return -EINVAL;
46
47	return cpu_set_flex_ratio_to_tdp_nominal();
48}
49
50int arch_cpu_init(void)
51{
52	post_code(POST_CPU_INIT);
53
54	return x86_cpu_init_f();
55}
56
57static int ivybridge_cpu_init(void)
58{
59	struct pci_controller *hose;
60	struct udevice *bus, *dev;
61	int ret;
62
63	post_code(0x70);
64	ret = uclass_get_device(UCLASS_PCI, 0, &bus);
65	post_code(0x71);
66	if (ret)
67		return ret;
68	post_code(0x72);
69	hose = dev_get_uclass_priv(bus);
70
71	/* TODO(sjg@chromium.org): Get rid of gd->hose */
72	gd->hose = hose;
73
74	ret = uclass_first_device_err(UCLASS_LPC, &dev);
75	if (ret)
76		return ret;
77
78	/*
79	 * We should do as little as possible before the serial console is
80	 * up. Perhaps this should move to later. Our next lot of init
81	 * happens in checkcpu() when we have a console
82	 */
83	ret = set_flex_ratio_to_tdp_nominal();
84	if (ret)
85		return ret;
86
87	return 0;
88}
89EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, ivybridge_cpu_init);
90
91#define PCH_EHCI0_TEMP_BAR0 0xe8000000
92#define PCH_EHCI1_TEMP_BAR0 0xe8000400
93#define PCH_XHCI_TEMP_BAR0  0xe8001000
94
95/*
96 * Setup USB controller MMIO BAR to prevent the reference code from
97 * resetting the controller.
98 *
99 * The BAR will be re-assigned during device enumeration so these are only
100 * temporary.
101 *
102 * This is used to speed up the resume path.
103 */
104static void enable_usb_bar(struct udevice *bus)
105{
106	pci_dev_t usb0 = PCH_EHCI1_DEV;
107	pci_dev_t usb1 = PCH_EHCI2_DEV;
108	pci_dev_t usb3 = PCH_XHCI_DEV;
109	ulong cmd;
110
111	/* USB Controller 1 */
112	pci_bus_write_config(bus, usb0, PCI_BASE_ADDRESS_0,
113			     PCH_EHCI0_TEMP_BAR0, PCI_SIZE_32);
114	pci_bus_read_config(bus, usb0, PCI_COMMAND, &cmd, PCI_SIZE_32);
115	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
116	pci_bus_write_config(bus, usb0, PCI_COMMAND, cmd, PCI_SIZE_32);
117
118	/* USB Controller 2 */
119	pci_bus_write_config(bus, usb1, PCI_BASE_ADDRESS_0,
120			     PCH_EHCI1_TEMP_BAR0, PCI_SIZE_32);
121	pci_bus_read_config(bus, usb1, PCI_COMMAND, &cmd, PCI_SIZE_32);
122	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
123	pci_bus_write_config(bus, usb1, PCI_COMMAND, cmd, PCI_SIZE_32);
124
125	/* USB3 Controller 1 */
126	pci_bus_write_config(bus, usb3, PCI_BASE_ADDRESS_0,
127			     PCH_XHCI_TEMP_BAR0, PCI_SIZE_32);
128	pci_bus_read_config(bus, usb3, PCI_COMMAND, &cmd, PCI_SIZE_32);
129	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
130	pci_bus_write_config(bus, usb3, PCI_COMMAND, cmd, PCI_SIZE_32);
131}
132
133int checkcpu(void)
134{
135	enum pei_boot_mode_t boot_mode = PEI_BOOT_NONE;
136	struct udevice *dev, *lpc;
137	uint32_t pm1_cnt;
138	uint16_t pm1_sts;
139	int ret;
140
141	/* TODO: cmos_post_init() */
142	if (readl(MCHBAR_REG(SSKPD)) == 0xCAFE) {
143		debug("soft reset detected\n");
144		boot_mode = PEI_BOOT_SOFT_RESET;
145
146		/* System is not happy after keyboard reset... */
147		debug("Issuing CF9 warm reset\n");
148		reset_cpu();
149	}
150
151	ret = cpu_common_init();
152	if (ret) {
153		debug("%s: cpu_common_init() failed\n", __func__);
154		return ret;
155	}
156
157	/* Check PM1_STS[15] to see if we are waking from Sx */
158	pm1_sts = inw(DEFAULT_PMBASE + PM1_STS);
159
160	/* Read PM1_CNT[12:10] to determine which Sx state */
161	pm1_cnt = inl(DEFAULT_PMBASE + PM1_CNT);
162
163	if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) {
164		debug("Resume from S3 detected, but disabled.\n");
165	} else {
166		/*
167		 * TODO: An indication of life might be possible here (e.g.
168		 * keyboard light)
169		 */
170	}
171	post_code(POST_EARLY_INIT);
172
173	/* Enable SPD ROMs and DDR-III DRAM */
174	ret = uclass_first_device_err(UCLASS_I2C, &dev);
175	if (ret) {
176		debug("%s: Failed to get I2C (ret=%d)\n", __func__, ret);
177		return ret;
178	}
179
180	/* Prepare USB controller early in S3 resume */
181	if (boot_mode == PEI_BOOT_RESUME) {
182		uclass_first_device(UCLASS_LPC, &lpc);
183		enable_usb_bar(pci_get_controller(lpc->parent));
184	}
185
186	gd->arch.pei_boot_mode = boot_mode;
187
188	return 0;
189}
190
191int print_cpuinfo(void)
192{
193	char processor_name[CPU_MAX_NAME_LEN];
194	const char *name;
195
196	/* Print processor name */
197	name = cpu_get_name(processor_name);
198	printf("CPU:   %s\n", name);
199
200	post_code(POST_CPU_INFO);
201
202	return 0;
203}
204
205void board_debug_uart_init(void)
206{
207	/* This enables the debug UART */
208	pci_x86_write_config(PCH_LPC_DEV, LPC_EN, COMA_LPC_EN, PCI_SIZE_16);
209}
210