xref: /openbmc/u-boot/arch/x86/cpu/ivybridge/early_me.c (revision 65dd74a674d636afcc14594c8308ff516e95a445)
1*65dd74a6SSimon Glass /*
2*65dd74a6SSimon Glass  * From Coreboot src/southbridge/intel/bd82x6x/early_me.c
3*65dd74a6SSimon Glass  *
4*65dd74a6SSimon Glass  * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
5*65dd74a6SSimon Glass  *
6*65dd74a6SSimon Glass  * SPDX-License-Identifier:	GPL-2.0
7*65dd74a6SSimon Glass  */
8*65dd74a6SSimon Glass 
9*65dd74a6SSimon Glass #include <common.h>
10*65dd74a6SSimon Glass #include <errno.h>
11*65dd74a6SSimon Glass #include <asm/pci.h>
12*65dd74a6SSimon Glass #include <asm/processor.h>
13*65dd74a6SSimon Glass #include <asm/arch/me.h>
14*65dd74a6SSimon Glass #include <asm/arch/pch.h>
15*65dd74a6SSimon Glass #include <asm/io.h>
16*65dd74a6SSimon Glass 
17*65dd74a6SSimon Glass static const char *const me_ack_values[] = {
18*65dd74a6SSimon Glass 	[ME_HFS_ACK_NO_DID]	= "No DID Ack received",
19*65dd74a6SSimon Glass 	[ME_HFS_ACK_RESET]	= "Non-power cycle reset",
20*65dd74a6SSimon Glass 	[ME_HFS_ACK_PWR_CYCLE]	= "Power cycle reset",
21*65dd74a6SSimon Glass 	[ME_HFS_ACK_S3]		= "Go to S3",
22*65dd74a6SSimon Glass 	[ME_HFS_ACK_S4]		= "Go to S4",
23*65dd74a6SSimon Glass 	[ME_HFS_ACK_S5]		= "Go to S5",
24*65dd74a6SSimon Glass 	[ME_HFS_ACK_GBL_RESET]	= "Global Reset",
25*65dd74a6SSimon Glass 	[ME_HFS_ACK_CONTINUE]	= "Continue to boot"
26*65dd74a6SSimon Glass };
27*65dd74a6SSimon Glass 
28*65dd74a6SSimon Glass static inline void pci_read_dword_ptr(void *ptr, int offset)
29*65dd74a6SSimon Glass {
30*65dd74a6SSimon Glass 	u32 dword;
31*65dd74a6SSimon Glass 
32*65dd74a6SSimon Glass 	dword = pci_read_config32(PCH_ME_DEV, offset);
33*65dd74a6SSimon Glass 	memcpy(ptr, &dword, sizeof(dword));
34*65dd74a6SSimon Glass }
35*65dd74a6SSimon Glass 
36*65dd74a6SSimon Glass static inline void pci_write_dword_ptr(void *ptr, int offset)
37*65dd74a6SSimon Glass {
38*65dd74a6SSimon Glass 	u32 dword = 0;
39*65dd74a6SSimon Glass 	memcpy(&dword, ptr, sizeof(dword));
40*65dd74a6SSimon Glass 	pci_write_config32(PCH_ME_DEV, offset, dword);
41*65dd74a6SSimon Glass }
42*65dd74a6SSimon Glass 
43*65dd74a6SSimon Glass void intel_early_me_status(void)
44*65dd74a6SSimon Glass {
45*65dd74a6SSimon Glass 	struct me_hfs hfs;
46*65dd74a6SSimon Glass 	struct me_gmes gmes;
47*65dd74a6SSimon Glass 
48*65dd74a6SSimon Glass 	pci_read_dword_ptr(&hfs, PCI_ME_HFS);
49*65dd74a6SSimon Glass 	pci_read_dword_ptr(&gmes, PCI_ME_GMES);
50*65dd74a6SSimon Glass 
51*65dd74a6SSimon Glass 	intel_me_status(&hfs, &gmes);
52*65dd74a6SSimon Glass }
53*65dd74a6SSimon Glass 
54*65dd74a6SSimon Glass int intel_early_me_init(void)
55*65dd74a6SSimon Glass {
56*65dd74a6SSimon Glass 	int count;
57*65dd74a6SSimon Glass 	struct me_uma uma;
58*65dd74a6SSimon Glass 	struct me_hfs hfs;
59*65dd74a6SSimon Glass 
60*65dd74a6SSimon Glass 	debug("Intel ME early init\n");
61*65dd74a6SSimon Glass 
62*65dd74a6SSimon Glass 	/* Wait for ME UMA SIZE VALID bit to be set */
63*65dd74a6SSimon Glass 	for (count = ME_RETRY; count > 0; --count) {
64*65dd74a6SSimon Glass 		pci_read_dword_ptr(&uma, PCI_ME_UMA);
65*65dd74a6SSimon Glass 		if (uma.valid)
66*65dd74a6SSimon Glass 			break;
67*65dd74a6SSimon Glass 		udelay(ME_DELAY);
68*65dd74a6SSimon Glass 	}
69*65dd74a6SSimon Glass 	if (!count) {
70*65dd74a6SSimon Glass 		printf("ERROR: ME is not ready!\n");
71*65dd74a6SSimon Glass 		return -EBUSY;
72*65dd74a6SSimon Glass 	}
73*65dd74a6SSimon Glass 
74*65dd74a6SSimon Glass 	/* Check for valid firmware */
75*65dd74a6SSimon Glass 	pci_read_dword_ptr(&hfs, PCI_ME_HFS);
76*65dd74a6SSimon Glass 	if (hfs.fpt_bad) {
77*65dd74a6SSimon Glass 		printf("WARNING: ME has bad firmware\n");
78*65dd74a6SSimon Glass 		return -EBADF;
79*65dd74a6SSimon Glass 	}
80*65dd74a6SSimon Glass 
81*65dd74a6SSimon Glass 	debug("Intel ME firmware is ready\n");
82*65dd74a6SSimon Glass 
83*65dd74a6SSimon Glass 	return 0;
84*65dd74a6SSimon Glass }
85*65dd74a6SSimon Glass 
86*65dd74a6SSimon Glass int intel_early_me_uma_size(void)
87*65dd74a6SSimon Glass {
88*65dd74a6SSimon Glass 	struct me_uma uma;
89*65dd74a6SSimon Glass 
90*65dd74a6SSimon Glass 	pci_read_dword_ptr(&uma, PCI_ME_UMA);
91*65dd74a6SSimon Glass 	if (uma.valid) {
92*65dd74a6SSimon Glass 		debug("ME: Requested %uMB UMA\n", uma.size);
93*65dd74a6SSimon Glass 		return uma.size;
94*65dd74a6SSimon Glass 	}
95*65dd74a6SSimon Glass 
96*65dd74a6SSimon Glass 	debug("ME: Invalid UMA size\n");
97*65dd74a6SSimon Glass 	return -EINVAL;
98*65dd74a6SSimon Glass }
99*65dd74a6SSimon Glass 
100*65dd74a6SSimon Glass static inline void set_global_reset(int enable)
101*65dd74a6SSimon Glass {
102*65dd74a6SSimon Glass 	u32 etr3;
103*65dd74a6SSimon Glass 
104*65dd74a6SSimon Glass 	etr3 = pci_read_config32(PCH_LPC_DEV, ETR3);
105*65dd74a6SSimon Glass 
106*65dd74a6SSimon Glass 	/* Clear CF9 Without Resume Well Reset Enable */
107*65dd74a6SSimon Glass 	etr3 &= ~ETR3_CWORWRE;
108*65dd74a6SSimon Glass 
109*65dd74a6SSimon Glass 	/* CF9GR indicates a Global Reset */
110*65dd74a6SSimon Glass 	if (enable)
111*65dd74a6SSimon Glass 		etr3 |= ETR3_CF9GR;
112*65dd74a6SSimon Glass 	else
113*65dd74a6SSimon Glass 		etr3 &= ~ETR3_CF9GR;
114*65dd74a6SSimon Glass 
115*65dd74a6SSimon Glass 	pci_write_config32(PCH_LPC_DEV, ETR3, etr3);
116*65dd74a6SSimon Glass }
117*65dd74a6SSimon Glass 
118*65dd74a6SSimon Glass int intel_early_me_init_done(u8 status)
119*65dd74a6SSimon Glass {
120*65dd74a6SSimon Glass 	u8 reset;
121*65dd74a6SSimon Glass 	int count;
122*65dd74a6SSimon Glass 	u32 mebase_l, mebase_h;
123*65dd74a6SSimon Glass 	struct me_hfs hfs;
124*65dd74a6SSimon Glass 	struct me_did did = {
125*65dd74a6SSimon Glass 		.init_done = ME_INIT_DONE,
126*65dd74a6SSimon Glass 		.status = status
127*65dd74a6SSimon Glass 	};
128*65dd74a6SSimon Glass 
129*65dd74a6SSimon Glass 	/* MEBASE from MESEG_BASE[35:20] */
130*65dd74a6SSimon Glass 	mebase_l = pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L);
131*65dd74a6SSimon Glass 	mebase_h = pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H);
132*65dd74a6SSimon Glass 	mebase_h &= 0xf;
133*65dd74a6SSimon Glass 	did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
134*65dd74a6SSimon Glass 
135*65dd74a6SSimon Glass 	/* Send message to ME */
136*65dd74a6SSimon Glass 	debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n",
137*65dd74a6SSimon Glass 	      status, did.uma_base);
138*65dd74a6SSimon Glass 
139*65dd74a6SSimon Glass 	pci_write_dword_ptr(&did, PCI_ME_H_GS);
140*65dd74a6SSimon Glass 
141*65dd74a6SSimon Glass 	/* Must wait for ME acknowledgement */
142*65dd74a6SSimon Glass 	for (count = ME_RETRY; count > 0; --count) {
143*65dd74a6SSimon Glass 		pci_read_dword_ptr(&hfs, PCI_ME_HFS);
144*65dd74a6SSimon Glass 		if (hfs.bios_msg_ack)
145*65dd74a6SSimon Glass 			break;
146*65dd74a6SSimon Glass 		udelay(ME_DELAY);
147*65dd74a6SSimon Glass 	}
148*65dd74a6SSimon Glass 	if (!count) {
149*65dd74a6SSimon Glass 		printf("ERROR: ME failed to respond\n");
150*65dd74a6SSimon Glass 		return -1;
151*65dd74a6SSimon Glass 	}
152*65dd74a6SSimon Glass 
153*65dd74a6SSimon Glass 	/* Return the requested BIOS action */
154*65dd74a6SSimon Glass 	debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]);
155*65dd74a6SSimon Glass 
156*65dd74a6SSimon Glass 	/* Check status after acknowledgement */
157*65dd74a6SSimon Glass 	intel_early_me_status();
158*65dd74a6SSimon Glass 
159*65dd74a6SSimon Glass 	reset = 0;
160*65dd74a6SSimon Glass 	switch (hfs.ack_data) {
161*65dd74a6SSimon Glass 	case ME_HFS_ACK_CONTINUE:
162*65dd74a6SSimon Glass 		/* Continue to boot */
163*65dd74a6SSimon Glass 		return 0;
164*65dd74a6SSimon Glass 	case ME_HFS_ACK_RESET:
165*65dd74a6SSimon Glass 		/* Non-power cycle reset */
166*65dd74a6SSimon Glass 		set_global_reset(0);
167*65dd74a6SSimon Glass 		reset = 0x06;
168*65dd74a6SSimon Glass 		break;
169*65dd74a6SSimon Glass 	case ME_HFS_ACK_PWR_CYCLE:
170*65dd74a6SSimon Glass 		/* Power cycle reset */
171*65dd74a6SSimon Glass 		set_global_reset(0);
172*65dd74a6SSimon Glass 		reset = 0x0e;
173*65dd74a6SSimon Glass 		break;
174*65dd74a6SSimon Glass 	case ME_HFS_ACK_GBL_RESET:
175*65dd74a6SSimon Glass 		/* Global reset */
176*65dd74a6SSimon Glass 		set_global_reset(1);
177*65dd74a6SSimon Glass 		reset = 0x0e;
178*65dd74a6SSimon Glass 		break;
179*65dd74a6SSimon Glass 	case ME_HFS_ACK_S3:
180*65dd74a6SSimon Glass 	case ME_HFS_ACK_S4:
181*65dd74a6SSimon Glass 	case ME_HFS_ACK_S5:
182*65dd74a6SSimon Glass 		break;
183*65dd74a6SSimon Glass 	}
184*65dd74a6SSimon Glass 
185*65dd74a6SSimon Glass 	/* Perform the requested reset */
186*65dd74a6SSimon Glass 	if (reset) {
187*65dd74a6SSimon Glass 		outb(reset, 0xcf9);
188*65dd74a6SSimon Glass 		cpu_hlt();
189*65dd74a6SSimon Glass 	}
190*65dd74a6SSimon Glass 	return -1;
191*65dd74a6SSimon Glass }
192