summaryrefslogtreecommitdiff
path: root/arch/x86/cpu/apollolake/cpu_spl.c
blob: 8f48457ee2209e656510cc06b1ef355f52103617 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2019 Google LLC
 *
 * Portions taken from coreboot
 */

#include <common.h>
#include <dm.h>
#include <ec_commands.h>
#include <init.h>
#include <log.h>
#include <spi_flash.h>
#include <spl.h>
#include <syscon.h>
#include <acpi/acpi_s3.h>
#include <asm/cpu.h>
#include <asm/cpu_common.h>
#include <asm/cpu_x86.h>
#include <asm/fast_spi.h>
#include <asm/global_data.h>
#include <asm/intel_pinctrl.h>
#include <asm/intel_regs.h>
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/mtrr.h>
#include <asm/pci.h>
#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h>
#include <asm/arch/iomap.h>
#include <asm/arch/lpc.h>
#include <asm/arch/pch.h>
#include <asm/arch/systemagent.h>
#include <asm/fsp2/fsp_api.h>
#include <linux/sizes.h>
#include <power/acpi_pmc.h>

static int fast_spi_cache_bios_region(void)
{
	uint map_size, offset;
	ulong map_base, base;
	int ret;

	ret = fast_spi_early_init(PCH_DEV_SPI, IOMAP_SPI_BASE);
	if (ret)
		return log_msg_ret("early_init", ret);

	ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size,
				     &offset);
	if (ret)
		return log_msg_ret("get_mmap", ret);

	base = SZ_4G - map_size;
	mtrr_set_next_var(MTRR_TYPE_WRPROT, base, map_size);
	log_debug("BIOS cache base=%lx, size=%x\n", base, (uint)map_size);

	return 0;
}

static void google_chromeec_ioport_range(uint *out_basep, uint *out_sizep)
{
	uint base;
	uint size;

	if (IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_MEC)) {
		base = MEC_EMI_BASE;
		size = MEC_EMI_SIZE;
	} else {
		base = EC_HOST_CMD_REGION0;
		size = 2 * EC_HOST_CMD_REGION_SIZE;
		/* Make sure MEMMAP region follows host cmd region */
		assert(base + size == EC_LPC_ADDR_MEMMAP);
		size += EC_MEMMAP_SIZE;
	}

	*out_basep = base;
	*out_sizep = size;
}

static void early_ec_init(void)
{
	uint base, size;

	/*
	 * Set up LPC decoding for the Chrome OS EC I/O port ranges:
	 * - Ports 62/66, 60/64, and 200->208
	 * - Chrome OS EC communication I/O ports
	 */
	lpc_enable_fixed_io_ranges(LPC_IOE_EC_62_66 | LPC_IOE_KBC_60_64 |
				   LPC_IOE_LGE_200);
	google_chromeec_ioport_range(&base, &size);
	lpc_open_pmio_window(base, size);
}

static int arch_cpu_init_tpl(void)
{
	struct udevice *pmc, *sa, *p2sb, *serial, *spi, *lpc;
	int ret;

	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc);
	if (ret)
		return log_msg_ret("PMC", ret);

	/* Clear global reset promotion bit */
	ret = pmc_global_reset_set_enable(pmc, false);
	if (ret)
		return log_msg_ret("disable global reset", ret);

	enable_pm_timer_emulation(pmc);

	ret = uclass_first_device_err(UCLASS_P2SB, &p2sb);
	if (ret)
		return log_msg_ret("p2sb", ret);
	ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &sa);
	if (ret)
		return log_msg_ret("northbridge", ret);
	gd->baudrate = CONFIG_BAUDRATE;
	ret = uclass_first_device_err(UCLASS_SERIAL, &serial);
	if (ret)
		return log_msg_ret("serial", ret);
	if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) {
		ret = uclass_first_device_err(UCLASS_SPI, &spi);
		if (ret)
			return log_msg_ret("SPI", ret);
	} else {
		/* Alternative code if we don't have SPI in TPL */
		if (IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH))
			printf("Warning: Enable APL_SPI_FLASHBOOT to use SPI-flash driver in TPL");
		ret = fast_spi_cache_bios_region();
		if (ret)
			return log_msg_ret("BIOS cache", ret);
	}
	ret = pmc_disable_tco(pmc);
	if (ret)
		return log_msg_ret("disable TCO", ret);
	ret = pmc_gpe_init(pmc);
	if (ret)
		return log_msg_ret("pmc_gpe", ret);
	ret = uclass_first_device_err(UCLASS_LPC, &lpc);
	if (ret)
		return log_msg_ret("lpc", ret);

	early_ec_init();

	return 0;
}

/*
 * Enables several BARs and devices which are needed for memory init
 * - MCH_BASE_ADDR is needed in order to talk to the memory controller
 * - HPET is enabled because FSP wants to store a pointer to global data in the
 *   HPET comparator register
 */
static int arch_cpu_init_spl(void)
{
	struct udevice *pmc, *p2sb;
	int ret;

	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc);
	if (ret)
		return log_msg_ret("Could not probe PMC", ret);
	ret = uclass_first_device_err(UCLASS_P2SB, &p2sb);
	if (ret)
		return log_msg_ret("Cannot set up p2sb", ret);

	lpc_io_setup_comm_a_b();

	/* TODO(sjg@chromium.org): Enable upper RTC bank here */

	ret = pmc_init(pmc);
	if (ret < 0)
		return log_msg_ret("Could not init PMC", ret);
	if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) {
		ret = pmc_prev_sleep_state(pmc);
		if (ret < 0)
			return log_msg_ret("Could not get PMC sleep state",
					   ret);
		gd->arch.prev_sleep_state = ret;
	}

	return 0;
}

int arch_cpu_init(void)
{
	int ret = 0;

	if (spl_phase() == PHASE_TPL)
		ret = arch_cpu_init_tpl();
	else if (spl_phase() == PHASE_SPL)
		ret = arch_cpu_init_spl();
	if (ret)
		printf("%s: Error %d\n", __func__, ret);

	return ret;
}