blob: b217eac285f4eedbb34e98777037b5de428be89d [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Aaron Durbin76c37002012-10-30 09:03:43 -05003
Aaron Durbin76c37002012-10-30 09:03:43 -05004#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05006#include <console/console.h>
7#include <delay.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +01008#include <halt.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05009#include <string.h>
10#include "me.h"
11#include "pch.h"
12
13static const char *me_ack_values[] = {
14 [ME_HFS_ACK_NO_DID] = "No DID Ack received",
15 [ME_HFS_ACK_RESET] = "Non-power cycle reset",
16 [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset",
17 [ME_HFS_ACK_S3] = "Go to S3",
18 [ME_HFS_ACK_S4] = "Go to S4",
19 [ME_HFS_ACK_S5] = "Go to S5",
20 [ME_HFS_ACK_GBL_RESET] = "Global Reset",
21 [ME_HFS_ACK_CONTINUE] = "Continue to boot"
22};
23
24static inline void pci_read_dword_ptr(void *ptr, int offset)
25{
26 u32 dword = pci_read_config32(PCH_ME_DEV, offset);
27 memcpy(ptr, &dword, sizeof(dword));
28}
29
30static inline void pci_write_dword_ptr(void *ptr, int offset)
31{
32 u32 dword = 0;
33 memcpy(&dword, ptr, sizeof(dword));
34 pci_write_config32(PCH_ME_DEV, offset, dword);
35}
36
37void intel_early_me_status(void)
38{
39 struct me_hfs hfs;
Aaron Durbin9aa031e2012-11-02 09:16:46 -050040 struct me_hfs2 hfs2;
Aaron Durbin76c37002012-10-30 09:03:43 -050041
42 pci_read_dword_ptr(&hfs, PCI_ME_HFS);
Aaron Durbin9aa031e2012-11-02 09:16:46 -050043 pci_read_dword_ptr(&hfs2, PCI_ME_HFS2);
Aaron Durbin76c37002012-10-30 09:03:43 -050044
Aaron Durbin9aa031e2012-11-02 09:16:46 -050045 intel_me_status(&hfs, &hfs2);
Aaron Durbin76c37002012-10-30 09:03:43 -050046}
47
48int intel_early_me_init(void)
49{
50 int count;
51 struct me_uma uma;
52 struct me_hfs hfs;
53
54 printk(BIOS_INFO, "Intel ME early init\n");
55
56 /* Wait for ME UMA SIZE VALID bit to be set */
Aaron Durbin9aa031e2012-11-02 09:16:46 -050057 /* FIXME: ME9 BGW indicates a 5 sec poll timeout. */
Aaron Durbin76c37002012-10-30 09:03:43 -050058 for (count = ME_RETRY; count > 0; --count) {
59 pci_read_dword_ptr(&uma, PCI_ME_UMA);
60 if (uma.valid)
61 break;
62 udelay(ME_DELAY);
63 }
64 if (!count) {
65 printk(BIOS_ERR, "ERROR: ME is not ready!\n");
66 return -1;
67 }
68
69 /* Check for valid firmware */
70 pci_read_dword_ptr(&hfs, PCI_ME_HFS);
71 if (hfs.fpt_bad) {
72 printk(BIOS_WARNING, "WARNING: ME has bad firmware\n");
73 return -1;
74 }
75
76 printk(BIOS_INFO, "Intel ME firmware is ready\n");
77 return 0;
78}
79
80int intel_early_me_uma_size(void)
81{
82 struct me_uma uma;
83
84 pci_read_dword_ptr(&uma, PCI_ME_UMA);
85 if (uma.valid) {
86 printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size);
87 return uma.size;
88 }
89
90 printk(BIOS_DEBUG, "ME: Invalid UMA size\n");
91 return 0;
92}
93
94static inline void set_global_reset(int enable)
95{
Aaron Durbinb9ea8b32012-11-02 09:10:30 -050096 u32 pmir = pci_read_config32(PCH_LPC_DEV, PMIR);
Aaron Durbin76c37002012-10-30 09:03:43 -050097
98 /* CF9GR indicates a Global Reset */
99 if (enable)
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500100 pmir |= PMIR_CF9GR;
Aaron Durbin76c37002012-10-30 09:03:43 -0500101 else
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500102 pmir &= ~PMIR_CF9GR;
Aaron Durbin76c37002012-10-30 09:03:43 -0500103
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500104 pci_write_config32(PCH_LPC_DEV, PMIR, pmir);
Aaron Durbin76c37002012-10-30 09:03:43 -0500105}
106
107int intel_early_me_init_done(u8 status)
108{
109 u8 reset;
110 int count;
111 u32 mebase_l, mebase_h;
112 struct me_hfs hfs;
113 struct me_did did = {
114 .init_done = ME_INIT_DONE,
115 .status = status
116 };
117
118 /* MEBASE from MESEG_BASE[35:20] */
119 mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L);
120 mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf;
121 did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
122
123 /* Send message to ME */
124 printk(BIOS_DEBUG, "ME: Sending Init Done with status: %d, "
125 "UMA base: 0x%04x\n", status, did.uma_base);
126
127 pci_write_dword_ptr(&did, PCI_ME_H_GS);
128
Aaron Durbin9aa031e2012-11-02 09:16:46 -0500129 /*
130 * The ME firmware does not respond with an ACK when NOMEM or ERROR
131 * are sent.
132 */
133 if (status == ME_INIT_STATUS_NOMEM || status == ME_INIT_STATUS_ERROR)
134 return 0;
135
Aaron Durbin76c37002012-10-30 09:03:43 -0500136 /* Must wait for ME acknowledgement */
137 for (count = ME_RETRY; count > 0; --count) {
138 pci_read_dword_ptr(&hfs, PCI_ME_HFS);
139 if (hfs.bios_msg_ack)
140 break;
141 udelay(ME_DELAY);
142 }
143 if (!count) {
144 printk(BIOS_ERR, "ERROR: ME failed to respond\n");
145 return -1;
146 }
147
148 /* Return the requested BIOS action */
149 printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n",
150 me_ack_values[hfs.ack_data]);
151
152 /* Check status after acknowledgement */
153 intel_early_me_status();
154
155 reset = 0;
156 switch (hfs.ack_data) {
157 case ME_HFS_ACK_CONTINUE:
158 /* Continue to boot */
159 return 0;
160 case ME_HFS_ACK_RESET:
161 /* Non-power cycle reset */
162 set_global_reset(0);
163 reset = 0x06;
164 break;
165 case ME_HFS_ACK_PWR_CYCLE:
166 /* Power cycle reset */
167 set_global_reset(0);
168 reset = 0x0e;
169 break;
170 case ME_HFS_ACK_GBL_RESET:
171 /* Global reset */
172 set_global_reset(1);
173 reset = 0x0e;
174 break;
175 case ME_HFS_ACK_S3:
176 case ME_HFS_ACK_S4:
177 case ME_HFS_ACK_S5:
178 break;
179 }
180
181 /* Perform the requested reset */
182 if (reset) {
183 outb(reset, 0xcf9);
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100184 halt();
Aaron Durbin76c37002012-10-30 09:03:43 -0500185 }
186 return -1;
187}