blob: 572e5e7a76a9428763b220e69fbbe1636570a374 [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>
Angel Ponsd00cfcb2022-02-14 12:55:31 +01007#include <northbridge/intel/ironlake/ironlake.h>
Angel Pons4e722d02022-02-14 12:33:19 +01008#include <southbridge/intel/ibexpeak/me.h>
Angel Ponse2531ff2022-02-14 13:04:34 +01009#include <southbridge/intel/ibexpeak/pch.h>
Angel Pons4e722d02022-02-14 12:33:19 +010010#include <types.h>
11
Angel Pons4e722d02022-02-14 12:33:19 +010012#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
Arthur Heymansbd90a222022-02-15 06:33:13 +010040static void send_heci_packet_dword(u8 *payload, size_t length)
Angel Pons4e722d02022-02-14 12:33:19 +010041{
Angel Pons4e722d02022-02-14 12:33:19 +010042 int i;
Arthur Heymansbd90a222022-02-15 06:33:13 +010043 for (i = 0; i < length; i += sizeof(uint32_t)) {
44 uint32_t dword = 0;
45 size_t bytes = MIN(length - i, sizeof(dword));
46 memcpy(&dword, payload + i, bytes);
47 write32(DEFAULT_HECIBAR + 0, dword);
48 }
49}
Angel Pons4e722d02022-02-14 12:33:19 +010050
Arthur Heymansbd90a222022-02-15 06:33:13 +010051static void send_heci_packet(struct mei_header *head, u8 *payload)
52{
53 wait_heci_cb_avail(DIV_ROUND_UP(sizeof(*head) + head->length, sizeof(u32)));
Angel Pons4e722d02022-02-14 12:33:19 +010054
Arthur Heymansbd90a222022-02-15 06:33:13 +010055 send_heci_packet_dword((u8 *)head, sizeof(*head));
56 send_heci_packet_dword(payload, head->length);
Angel Pons4e722d02022-02-14 12:33:19 +010057
Angel Pons4e722d02022-02-14 12:33:19 +010058 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
59}
60
61static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
62{
63 struct mei_header head;
64 int maxlen;
65
66 wait_heci_ready();
67 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
68
69 while (len) {
70 int cur = len;
71 if (cur > maxlen) {
72 cur = maxlen;
73 head.is_complete = 0;
74 } else
75 head.is_complete = 1;
76 head.length = cur;
77 head.reserved = 0;
78 head.client_address = clientaddress;
79 head.host_address = hostaddress;
Arthur Heymansbd90a222022-02-15 06:33:13 +010080 send_heci_packet(&head, msg);
Angel Pons4e722d02022-02-14 12:33:19 +010081 len -= cur;
82 msg += cur;
83 }
84}
85
86/* FIXME: Add timeout. */
87static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
88{
89 union {
90 struct mei_csr csr;
91 u32 raw;
92 } csr;
93 int i = 0;
94
95 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
96 do {
97 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
98 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
99
Elyes Haouas723b8962022-11-18 15:07:03 +0100100 *(u32 *)head = read32(DEFAULT_HECIBAR + 0x8);
Angel Pons4e722d02022-02-14 12:33:19 +0100101 if (!head->length) {
102 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
103 *packet_size = 0;
104 return 0;
105 }
106 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
107 *packet_size = 0;
108 return -1;
109 }
110
111 do {
112 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
113 } while (((head->length + 3) >> 2) >
114 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
115
116 for (i = 0; i < (head->length + 3) >> 2; i++)
117 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
118 *packet_size = head->length;
119 if (!csr.csr.ready)
120 *packet_size = 0;
121 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
122 return 0;
123}
124
125union uma_reply {
126 struct {
127 u8 group_id;
128 u8 command;
129 u8 reserved;
130 u8 result;
131 u8 field2;
132 u8 unk3[0x48 - 4 - 1];
133 };
134 u32 dwords[0x48 / sizeof(u32)];
135} __packed;
136
137/* FIXME: Add timeout. */
138static int recv_heci_message(union uma_reply *message, u32 *message_size)
139{
140 struct mei_header head;
141 int current_position;
142
143 current_position = 0;
144 while (1) {
145 u32 current_size;
146 current_size = *message_size - current_position;
147 if (recv_heci_packet
148 (&head, &message->dwords[current_position / sizeof(u32)],
149 &current_size) == -1)
150 break;
151 if (!current_size)
152 break;
153 current_position += current_size;
154 if (head.is_complete) {
155 *message_size = current_position;
156 return 0;
157 }
158
159 if (current_position >= *message_size)
160 break;
161 }
162 *message_size = 0;
163 return -1;
164}
165
166static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
167{
168 union uma_reply reply;
169
170 struct uma_message {
171 u8 group_id;
172 u8 cmd;
173 u8 reserved;
174 u8 result;
175 u32 c2;
176 u64 heci_uma_addr;
177 u32 heci_uma_size;
178 u16 c3;
179 } __packed msg = {
180 .group_id = 0,
181 .cmd = MKHI_SET_UMA,
182 .reserved = 0,
183 .result = 0,
184 .c2 = 0x82,
185 .heci_uma_addr = heci_uma_addr,
186 .heci_uma_size = heci_uma_size,
187 .c3 = 0,
188 };
189 u32 reply_size;
190
Elyes Haouas723b8962022-11-18 15:07:03 +0100191 send_heci_message((u8 *)&msg, sizeof(msg), 0, 7);
Angel Pons4e722d02022-02-14 12:33:19 +0100192
193 reply_size = sizeof(reply);
194 if (recv_heci_message(&reply, &reply_size) == -1)
195 return;
196
197 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
198 die("HECI init failed\n");
199}
200
Angel Pons34619172022-02-14 12:48:42 +0100201void setup_heci_uma(u64 heci_uma_addr, unsigned int heci_uma_size)
Angel Pons4e722d02022-02-14 12:33:19 +0100202{
Angel Pons34619172022-02-14 12:48:42 +0100203 if (!heci_uma_size && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Angel Pons4e722d02022-02-14 12:33:19 +0100204 return;
205
Angel Pons34619172022-02-14 12:48:42 +0100206 if (heci_uma_size) {
Angel Pons4e722d02022-02-14 12:33:19 +0100207 dmibar_clrbits32(DMIVC0RCTL, 1 << 7);
208 RCBA32(0x14) &= ~0x80;
209 dmibar_clrbits32(DMIVC1RCTL, 1 << 7);
210 RCBA32(0x20) &= ~0x80;
211 dmibar_clrbits32(DMIVCPRCTL, 1 << 7);
212 RCBA32(0x30) &= ~0x80;
213 dmibar_clrbits32(DMIVCMRCTL, 1 << 7);
214 RCBA32(0x40) &= ~0x80;
215
216 RCBA32(0x40) = 0x87000080; // OK
217 dmibar_write32(DMIVCMRCTL, 0x87000080); // OK
218
219 while ((RCBA16(0x46) & 2) && dmibar_read16(DMIVCMRSTS) & VCMNP)
220 ;
221 }
222
Angel Pons34619172022-02-14 12:48:42 +0100223 mchbar_write32(0x24, 0x10000 + heci_uma_size);
Angel Pons4e722d02022-02-14 12:33:19 +0100224
Angel Pons34619172022-02-14 12:48:42 +0100225 send_heci_uma_message(heci_uma_addr, heci_uma_size);
Angel Pons4e722d02022-02-14 12:33:19 +0100226
227 pci_write_config32(HECIDEV, 0x10, 0x0);
228 pci_write_config8(HECIDEV, 0x4, 0x0);
229}