blob: e54b05867cb7f1cfa55d25f56ea95e5392048ee5 [file] [log] [blame]
Angel Pons4e722d02022-02-14 12:33:19 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
4#include <device/mmio.h>
5#include <device/pci_def.h>
6#include <device/pci_ops.h>
7#include <northbridge/intel/ironlake/raminit.h>
8#include <southbridge/intel/ibexpeak/me.h>
9#include <types.h>
10
Angel Pons4e722d02022-02-14 12:33:19 +010011#define HECIDEV PCI_DEV(0, 0x16, 0)
12
13/* FIXME: add timeout. */
14static void wait_heci_ready(void)
15{
16 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
17 ;
18
19 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
20}
21
22/* FIXME: add timeout. */
23static void wait_heci_cb_avail(int len)
24{
25 union {
26 struct mei_csr csr;
27 u32 raw;
28 } csr;
29
30 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
31 ;
32
33 do {
34 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
35 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
36 csr.csr.buffer_read_ptr));
37}
38
39static void send_heci_packet(struct mei_header *head, u32 *payload)
40{
41 int len = (head->length + 3) / 4;
42 int i;
43
44 wait_heci_cb_avail(len + 1);
45
46 /* FIXME: handle leftovers correctly. */
47 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
48 for (i = 0; i < len - 1; i++)
49 write32(DEFAULT_HECIBAR + 0, payload[i]);
50
51 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
52 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
53}
54
55static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
56{
57 struct mei_header head;
58 int maxlen;
59
60 wait_heci_ready();
61 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
62
63 while (len) {
64 int cur = len;
65 if (cur > maxlen) {
66 cur = maxlen;
67 head.is_complete = 0;
68 } else
69 head.is_complete = 1;
70 head.length = cur;
71 head.reserved = 0;
72 head.client_address = clientaddress;
73 head.host_address = hostaddress;
74 send_heci_packet(&head, (u32 *) msg);
75 len -= cur;
76 msg += cur;
77 }
78}
79
80/* FIXME: Add timeout. */
81static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
82{
83 union {
84 struct mei_csr csr;
85 u32 raw;
86 } csr;
87 int i = 0;
88
89 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
90 do {
91 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
92 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
93
94 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
95 if (!head->length) {
96 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
97 *packet_size = 0;
98 return 0;
99 }
100 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
101 *packet_size = 0;
102 return -1;
103 }
104
105 do {
106 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
107 } while (((head->length + 3) >> 2) >
108 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
109
110 for (i = 0; i < (head->length + 3) >> 2; i++)
111 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
112 *packet_size = head->length;
113 if (!csr.csr.ready)
114 *packet_size = 0;
115 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
116 return 0;
117}
118
119union uma_reply {
120 struct {
121 u8 group_id;
122 u8 command;
123 u8 reserved;
124 u8 result;
125 u8 field2;
126 u8 unk3[0x48 - 4 - 1];
127 };
128 u32 dwords[0x48 / sizeof(u32)];
129} __packed;
130
131/* FIXME: Add timeout. */
132static int recv_heci_message(union uma_reply *message, u32 *message_size)
133{
134 struct mei_header head;
135 int current_position;
136
137 current_position = 0;
138 while (1) {
139 u32 current_size;
140 current_size = *message_size - current_position;
141 if (recv_heci_packet
142 (&head, &message->dwords[current_position / sizeof(u32)],
143 &current_size) == -1)
144 break;
145 if (!current_size)
146 break;
147 current_position += current_size;
148 if (head.is_complete) {
149 *message_size = current_position;
150 return 0;
151 }
152
153 if (current_position >= *message_size)
154 break;
155 }
156 *message_size = 0;
157 return -1;
158}
159
160static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
161{
162 union uma_reply reply;
163
164 struct uma_message {
165 u8 group_id;
166 u8 cmd;
167 u8 reserved;
168 u8 result;
169 u32 c2;
170 u64 heci_uma_addr;
171 u32 heci_uma_size;
172 u16 c3;
173 } __packed msg = {
174 .group_id = 0,
175 .cmd = MKHI_SET_UMA,
176 .reserved = 0,
177 .result = 0,
178 .c2 = 0x82,
179 .heci_uma_addr = heci_uma_addr,
180 .heci_uma_size = heci_uma_size,
181 .c3 = 0,
182 };
183 u32 reply_size;
184
185 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
186
187 reply_size = sizeof(reply);
188 if (recv_heci_message(&reply, &reply_size) == -1)
189 return;
190
191 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
192 die("HECI init failed\n");
193}
194
Angel Pons34619172022-02-14 12:48:42 +0100195void setup_heci_uma(u64 heci_uma_addr, unsigned int heci_uma_size)
Angel Pons4e722d02022-02-14 12:33:19 +0100196{
Angel Pons34619172022-02-14 12:48:42 +0100197 if (!heci_uma_size && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Angel Pons4e722d02022-02-14 12:33:19 +0100198 return;
199
Angel Pons34619172022-02-14 12:48:42 +0100200 if (heci_uma_size) {
Angel Pons4e722d02022-02-14 12:33:19 +0100201 dmibar_clrbits32(DMIVC0RCTL, 1 << 7);
202 RCBA32(0x14) &= ~0x80;
203 dmibar_clrbits32(DMIVC1RCTL, 1 << 7);
204 RCBA32(0x20) &= ~0x80;
205 dmibar_clrbits32(DMIVCPRCTL, 1 << 7);
206 RCBA32(0x30) &= ~0x80;
207 dmibar_clrbits32(DMIVCMRCTL, 1 << 7);
208 RCBA32(0x40) &= ~0x80;
209
210 RCBA32(0x40) = 0x87000080; // OK
211 dmibar_write32(DMIVCMRCTL, 0x87000080); // OK
212
213 while ((RCBA16(0x46) & 2) && dmibar_read16(DMIVCMRSTS) & VCMNP)
214 ;
215 }
216
Angel Pons34619172022-02-14 12:48:42 +0100217 mchbar_write32(0x24, 0x10000 + heci_uma_size);
Angel Pons4e722d02022-02-14 12:33:19 +0100218
Angel Pons34619172022-02-14 12:48:42 +0100219 send_heci_uma_message(heci_uma_addr, heci_uma_size);
Angel Pons4e722d02022-02-14 12:33:19 +0100220
221 pci_write_config32(HECIDEV, 0x10, 0x0);
222 pci_write_config8(HECIDEV, 0x4, 0x0);
223}