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