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