xref: /aosp_15_r20/external/coreboot/src/southbridge/intel/ibexpeak/setup_heci_uma.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* 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/ironlake.h>
8 #include <southbridge/intel/ibexpeak/me.h>
9 #include <southbridge/intel/ibexpeak/pch.h>
10 #include <types.h>
11 
12 #define HECIDEV PCI_DEV(0, 0x16, 0)
13 
14 /* FIXME: add timeout.  */
wait_heci_ready(void)15 static 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.  */
wait_heci_cb_avail(int len)24 static 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 
send_heci_packet_dword(u8 * payload,size_t length)40 static void send_heci_packet_dword(u8 *payload, size_t length)
41 {
42 	int i;
43 	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 }
50 
send_heci_packet(struct mei_header * head,u8 * payload)51 static 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)));
54 
55 	send_heci_packet_dword((u8 *)head, sizeof(*head));
56 	send_heci_packet_dword(payload, head->length);
57 
58 	write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
59 }
60 
send_heci_message(u8 * msg,int len,u8 hostaddress,u8 clientaddress)61 static 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;
80 		send_heci_packet(&head, msg);
81 		len -= cur;
82 		msg += cur;
83 	}
84 }
85 
86 /* FIXME: Add timeout.  */
recv_heci_packet(struct mei_header * head,u32 * packet,u32 * packet_size)87 static 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 
100 	*(u32 *)head = read32(DEFAULT_HECIBAR + 0x8);
101 	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 
125 union 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.  */
recv_heci_message(union uma_reply * message,u32 * message_size)138 static 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 
send_heci_uma_message(const u64 heci_uma_addr,const unsigned int heci_uma_size)166 static 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 
191 	send_heci_message((u8 *)&msg, sizeof(msg), 0, 7);
192 
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 
setup_heci_uma(u64 heci_uma_addr,unsigned int heci_uma_size)201 void setup_heci_uma(u64 heci_uma_addr, unsigned int heci_uma_size)
202 {
203 	if (!heci_uma_size && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
204 		return;
205 
206 	if (heci_uma_size) {
207 		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 
223 	mchbar_write32(0x24, 0x10000 + heci_uma_size);
224 
225 	send_heci_uma_message(heci_uma_addr, heci_uma_size);
226 
227 	pci_write_config32(HECIDEV, 0x10, 0x0);
228 	pci_write_config8(HECIDEV, 0x4, 0x0);
229 }
230