1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 Google LLC
4 */
5
6#include <cpu.h>
7#include <dm.h>
8#include <log.h>
9#include <acpi/acpigen.h>
10#include <acpi/acpi_table.h>
11#include <asm/cpu_common.h>
12#include <asm/cpu_x86.h>
13#include <asm/global_data.h>
14#include <asm/intel_acpi.h>
15#include <asm/msr.h>
16#include <asm/mtrr.h>
17#include <asm/arch/cpu.h>
18#include <asm/arch/iomap.h>
19#include <dm/acpi.h>
20
21#ifdef CONFIG_ACPIGEN
22#define CSTATE_RES(address_space, width, offset, address)		\
23	{								\
24	.space_id = address_space,					\
25	.bit_width = width,						\
26	.bit_offset = offset,						\
27	.addrl = address,						\
28	}
29
30static struct acpi_cstate cstate_map[] = {
31	{
32		/* C1 */
33		.ctype = 1,		/* ACPI C1 */
34		.latency = 1,
35		.power = 1000,
36		.resource = {
37			.space_id = ACPI_ADDRESS_SPACE_FIXED,
38		},
39	}, {
40		.ctype = 2,		/* ACPI C2 */
41		.latency = 50,
42		.power = 10,
43		.resource = {
44			.space_id = ACPI_ADDRESS_SPACE_IO,
45			.bit_width = 8,
46			.addrl = 0x415,
47		},
48	}, {
49		.ctype = 3,		/* ACPI C3 */
50		.latency = 150,
51		.power = 10,
52		.resource = {
53			.space_id = ACPI_ADDRESS_SPACE_IO,
54			.bit_width = 8,
55			.addrl = 0x419,
56		},
57	},
58};
59
60static int acpi_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
61{
62	uint core_id = dev_seq(dev);
63	int cores_per_package;
64	int ret;
65
66	cores_per_package = cpu_get_cores_per_package();
67	ret = acpi_generate_cpu_header(ctx, core_id, cstate_map,
68				       ARRAY_SIZE(cstate_map));
69
70	/* Generate P-state tables */
71	generate_p_state_entries(ctx, core_id, cores_per_package);
72
73	/* Generate T-state tables */
74	generate_t_state_entries(ctx, core_id, cores_per_package, NULL, 0);
75
76	acpigen_pop_len(ctx);
77
78	if (device_is_last_sibling(dev)) {
79		ret = acpi_generate_cpu_package_final(ctx, cores_per_package);
80
81		if (ret)
82			return ret;
83	}
84
85	return 0;
86}
87#endif /* CONFIG_ACPIGEN */
88
89static int apl_get_info(const struct udevice *dev, struct cpu_info *info)
90{
91	return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
92}
93
94static void update_fixed_mtrrs(void)
95{
96	native_write_msr(MTRR_FIX_64K_00000_MSR,
97			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
98			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
99	native_write_msr(MTRR_FIX_16K_80000_MSR,
100			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
101			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
102	native_write_msr(MTRR_FIX_4K_E0000_MSR,
103			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
104			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
105	native_write_msr(MTRR_FIX_4K_E8000_MSR,
106			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
107			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
108	native_write_msr(MTRR_FIX_4K_F0000_MSR,
109			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
110			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
111	native_write_msr(MTRR_FIX_4K_F8000_MSR,
112			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
113			 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
114}
115
116static void setup_core_msrs(void)
117{
118	wrmsrl(MSR_PMG_CST_CONFIG_CONTROL,
119	       PKG_C_STATE_LIMIT_C2_MASK | CORE_C_STATE_LIMIT_C10_MASK |
120	       IO_MWAIT_REDIRECT_MASK | CST_CFG_LOCK_MASK);
121	/* Power Management I/O base address for I/O trapping to C-states */
122	wrmsrl(MSR_PMG_IO_CAPTURE_ADR, ACPI_PMIO_CST_REG |
123	       (PMG_IO_BASE_CST_RNG_BLK_SIZE << 16));
124	/* Disable C1E */
125	msr_clrsetbits_64(MSR_POWER_CTL, 0x2, 0);
126	/* Disable support for MONITOR and MWAIT instructions */
127	msr_clrsetbits_64(MSR_IA32_MISC_ENABLE, MISC_ENABLE_MWAIT, 0);
128	/*
129	 * Enable and Lock the Advanced Encryption Standard (AES-NI)
130	 * feature register
131	 */
132	msr_clrsetbits_64(MSR_FEATURE_CONFIG, FEATURE_CONFIG_RESERVED_MASK,
133			  FEATURE_CONFIG_LOCK);
134
135	update_fixed_mtrrs();
136}
137
138static int soc_core_init(void)
139{
140	struct udevice *pmc;
141	int ret;
142
143	/* Clear out pending MCEs */
144	cpu_mca_configure();
145
146	/* Set core MSRs */
147	setup_core_msrs();
148	/*
149	 * Enable ACPI PM timer emulation, which also lets microcode know
150	 * location of ACPI_BASE_ADDRESS. This also enables other features
151	 * implemented in microcode.
152	 */
153	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc);
154	if (ret)
155		return log_msg_ret("PMC", ret);
156	enable_pm_timer_emulation(pmc);
157
158	return 0;
159}
160
161static int cpu_apl_probe(struct udevice *dev)
162{
163	if (gd->flags & GD_FLG_RELOC) {
164		int ret;
165
166		ret = soc_core_init();
167		if (ret)
168			return log_ret(ret);
169	}
170
171	return 0;
172}
173
174#ifdef CONFIG_ACPIGEN
175struct acpi_ops apl_cpu_acpi_ops = {
176	.fill_ssdt	= acpi_cpu_fill_ssdt,
177};
178#endif
179
180static const struct cpu_ops cpu_x86_apl_ops = {
181	.get_desc	= cpu_x86_get_desc,
182	.get_info	= apl_get_info,
183	.get_count	= cpu_x86_get_count,
184	.get_vendor	= cpu_x86_get_vendor,
185};
186
187static const struct udevice_id cpu_x86_apl_ids[] = {
188	{ .compatible = "intel,apl-cpu" },
189	{ }
190};
191
192U_BOOT_DRIVER(intel_apl_cpu) = {
193	.name		= "intel_apl_cpu",
194	.id		= UCLASS_CPU,
195	.of_match	= cpu_x86_apl_ids,
196	.bind		= cpu_x86_bind,
197	.probe		= cpu_apl_probe,
198	.ops		= &cpu_x86_apl_ops,
199	ACPI_OPS_PTR(&apl_cpu_acpi_ops)
200	.flags		= DM_FLAG_PRE_RELOC,
201};
202