blob: 3808bd677ea5095f3d4427ade4b6465211e89438 [file] [log] [blame]
Andrey Petrov04a72c42017-03-01 15:51:57 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2017 Intel Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <arch/early_variables.h>
17#include <commonlib/helpers.h>
18#include <console/console.h>
19#include <delay.h>
20#include <device/pci.h>
21#include <device/pci_ids.h>
22#include <device/pci_ops.h>
23#include <intelblocks/cse.h>
24#include <soc/pci_devs.h>
25#include <soc/pci_ids.h>
26#include <string.h>
27#include <timer.h>
28
29/* default window for early boot, must be at least 12 bytes in size */
30#define HECI1_BASE_ADDRESS 0xfed1a000
31
32/* Wait up to 15 sec for HECI to get ready */
33#define HECI_DELAY_READY (15 * 1000)
34/* Wait up to 100 usec between circullar buffer polls */
35#define HECI_DELAY 100
36/* Wait up to 5 sec for CSE to chew something we sent */
37#define HECI_SEND_TIMEOUT (5 * 1000)
38/* Wait up to 5 sec for CSE to blurp a reply */
39#define HECI_READ_TIMEOUT (5 * 1000)
40
41#define SLOT_SIZE sizeof(uint32_t)
42
43#define MMIO_CSE_CB_WW 0x00
44#define MMIO_HOST_CSR 0x04
45#define MMIO_CSE_CB_RW 0x08
46#define MMIO_CSE_CSR 0x0c
47
48#define CSR_IE (1 << 0)
49#define CSR_IS (1 << 1)
50#define CSR_IG (1 << 2)
51#define CSR_READY (1 << 3)
52#define CSR_RESET (1 << 4)
53#define CSR_RP_START 8
54#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
55#define CSR_WP_START 16
56#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
57#define CSR_CBD_START 24
58#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
59
60#define MEI_HDR_IS_COMPLETE (1 << 31)
61#define MEI_HDR_LENGTH_START 16
62#define MEI_HDR_LENGTH_SIZE 9
63#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
64 << MEI_HDR_LENGTH_START)
65#define MEI_HDR_HOST_ADDR_START 8
66#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
67#define MEI_HDR_CSE_ADDR_START 0
68#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
69
70
71struct cse_device {
72 uintptr_t sec_bar;
73} g_cse CAR_GLOBAL;
74
75/*
76 * Initialize the device with provided temporary BAR. If BAR is 0 use a
77 * default. This is intended for pre-mem usage only where BARs haven't been
78 * assigned yet and devices are not enabled.
79 */
80void heci_init(uintptr_t tempbar)
81{
82 struct cse_device *cse = car_get_var_ptr(&g_cse);
83 device_t dev = HECI1_DEV;
84 u8 pcireg;
85
86 /* Assume it is already initialized, nothing else to do */
87 if (cse->sec_bar)
88 return;
89
90 /* Use default pre-ram bar */
91 if (!tempbar)
92 tempbar = HECI1_BASE_ADDRESS;
93
94 /* Assign Resources to HECI1 */
95 /* Clear BIT 1-2 of Command Register */
96 pcireg = pci_read_config8(dev, PCI_COMMAND);
97 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
98 pci_write_config8(dev, PCI_COMMAND, pcireg);
99
100 /* Program Temporary BAR for HECI1 */
101 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
102 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
103
104 /* Enable Bus Master and MMIO Space */
105 pcireg = pci_read_config8(dev, PCI_COMMAND);
106 pcireg |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
107 pci_write_config8(dev, PCI_COMMAND, pcireg);
108
109 cse->sec_bar = tempbar;
110}
111
112static uint32_t read_bar(uint32_t offset)
113{
114 struct cse_device *cse = car_get_var_ptr(&g_cse);
115 return read32((void *)(cse->sec_bar + offset));
116}
117
118static void write_bar(uint32_t offset, uint32_t val)
119{
120 struct cse_device *cse = car_get_var_ptr(&g_cse);
121 return write32((void *)(cse->sec_bar + offset), val);
122}
123
124static uint32_t read_cse_csr(void)
125{
126 return read_bar(MMIO_CSE_CSR);
127}
128
129static uint32_t read_host_csr(void)
130{
131 return read_bar(MMIO_HOST_CSR);
132}
133
134static void write_host_csr(uint32_t data)
135{
136 write_bar(MMIO_HOST_CSR, data);
137}
138
139static size_t filled_slots(uint32_t data)
140{
141 uint8_t wp, rp;
142 rp = data >> CSR_RP_START;
143 wp = data >> CSR_WP_START;
144 return (uint8_t) (wp - rp);
145}
146
147static size_t cse_filled_slots(void)
148{
149 return filled_slots(read_cse_csr());
150}
151
152static size_t host_empty_slots(void)
153{
154 uint32_t csr;
155 csr = read_host_csr();
156
157 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
158}
159
160static void clear_int(void)
161{
162 uint32_t csr;
163 csr = read_host_csr();
164 csr |= CSR_IS;
165 write_host_csr(csr);
166}
167
168static uint32_t read_slot(void)
169{
170 return read_bar(MMIO_CSE_CB_RW);
171}
172
173static void write_slot(uint32_t val)
174{
175 write_bar(MMIO_CSE_CB_WW, val);
176}
177
178static int wait_write_slots(size_t cnt)
179{
180 struct stopwatch sw;
181
182 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
183 while (host_empty_slots() < cnt) {
184 udelay(HECI_DELAY);
185 if (stopwatch_expired(&sw)) {
186 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
187 return 0;
188 }
189 }
190 return 1;
191}
192
193static int wait_read_slots(size_t cnt)
194{
195 struct stopwatch sw;
196
197 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
198 while (cse_filled_slots() < cnt) {
199 udelay(HECI_DELAY);
200 if (stopwatch_expired(&sw)) {
201 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
202 return 0;
203 }
204 }
205 return 1;
206}
207
208/* get number of full 4-byte slots */
209static size_t bytes_to_slots(size_t bytes)
210{
211 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
212}
213
214static int cse_ready(void)
215{
216 uint32_t csr;
217 csr = read_cse_csr();
218 return csr & CSR_READY;
219}
220
221static int wait_heci_ready(void)
222{
223 struct stopwatch sw;
224
225 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
226 while (!cse_ready()) {
227 udelay(HECI_DELAY);
228 if (stopwatch_expired(&sw))
229 return 0;
230 }
231
232 return 1;
233}
234
235static void host_gen_interrupt(void)
236{
237 uint32_t csr;
238 csr = read_host_csr();
239 csr |= CSR_IG;
240 write_host_csr(csr);
241}
242
243static size_t hdr_get_length(uint32_t hdr)
244{
245 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
246}
247
248static int
249send_one_message(uint32_t hdr, const void *buff)
250{
251 size_t pend_len, pend_slots, remainder, i;
252 uint32_t tmp;
253 const uint32_t *p = buff;
254
255 /* Get space for the header */
256 if (!wait_write_slots(1))
257 return 0;
258
259 /* First, write header */
260 write_slot(hdr);
261
262 pend_len = hdr_get_length(hdr);
263 pend_slots = bytes_to_slots(pend_len);
264
265 if (!wait_write_slots(pend_slots))
266 return 0;
267
268 /* Write the body in whole slots */
269 i = 0;
270 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
271 write_slot(*p++);
272 i += SLOT_SIZE;
273 }
274
275 remainder = pend_len % SLOT_SIZE;
276 /* Pad to 4 bytes not touching caller's buffer */
277 if (remainder) {
278 memcpy(&tmp, p, remainder);
279 write_slot(tmp);
280 }
281
282 host_gen_interrupt();
283
284 /* Make sure nothing bad happened during transmission */
285 if (!cse_ready())
286 return 0;
287
288 return pend_len;
289}
290
291int
292heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
293{
294 uint32_t csr, hdr;
295 size_t sent = 0, remaining, cb_size, max_length;
296 uint8_t *p = (uint8_t *) msg;
297
298 if (!msg || !len)
299 return 0;
300
301 clear_int();
302
303 if (!wait_heci_ready()) {
304 printk(BIOS_ERR, "HECI: not ready\n");
305 return 0;
306 }
307
308 csr = read_cse_csr();
309 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
310 /*
311 * Reserve one slot for the header. Limit max message length by 9
312 * bits that are available in the header.
313 */
314 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1) - SLOT_SIZE;
315 remaining = len;
316
317 /*
318 * Fragment the message into smaller messages not exceeding useful
319 * circullar buffer length. Mark last message complete.
320 */
321 do {
322 hdr = MIN(max_length, remaining) << MEI_HDR_LENGTH_START;
323 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
324 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
325 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800326 MEI_HDR_IS_COMPLETE : 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800327 sent = send_one_message(hdr, p);
328 p += sent;
329 remaining -= sent;
330 } while (remaining > 0 && sent != 0);
331
332 return remaining == 0;
333}
334
335static size_t
336recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
337{
338 uint32_t reg, *p = buff;
339 size_t recv_slots, recv_len, remainder, i;
340
341 /* first get the header */
342 if (!wait_read_slots(1))
343 return 0;
344
345 *hdr = read_slot();
346 recv_len = hdr_get_length(*hdr);
347
348 if (!recv_len)
349 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
350
351 recv_slots = bytes_to_slots(recv_len);
352
353 i = 0;
354 if (recv_len > maxlen) {
355 printk(BIOS_ERR, "HECI: response is too big\n");
356 return 0;
357 }
358
359 /* wait for the rest of messages to arrive */
360 wait_read_slots(recv_slots);
361
362 /* fetch whole slots first */
363 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
364 *p++ = read_slot();
365 i += SLOT_SIZE;
366 }
367
368 remainder = recv_len % SLOT_SIZE;
369
370 if (remainder) {
371 reg = read_slot();
372 memcpy(p, &reg, remainder);
373 }
374
375 return recv_len;
376}
377
378int heci_receive(void *buff, size_t *maxlen)
379{
380 size_t left, received;
381 uint32_t hdr = 0;
382 uint8_t *p = buff;
383
384 if (!buff || !maxlen || !*maxlen)
385 return 0;
386
387 left = *maxlen;
388
389 clear_int();
390
391 if (!wait_heci_ready()) {
392 printk(BIOS_ERR, "HECI: not ready\n");
393 return 0;
394 }
395
396 /*
397 * Receive multiple packets until we meet one marked complete or we run
398 * out of space in caller-provided buffer.
399 */
400 do {
401 received = recv_one_message(&hdr, p, left);
402 left -= received;
403 p += received;
404 /* If we read out everything ping to send more */
405 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
406 host_gen_interrupt();
407 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
408
409 *maxlen = p - (uint8_t *) buff;
410
411 /* If ME is not ready, something went wrong and we received junk */
412 if (!cse_ready())
413 return 0;
414
415 return !!((hdr & MEI_HDR_IS_COMPLETE) && received);
416}
417
418/*
419 * Attempt to reset the device. This is useful when host and ME are out
420 * of sync during transmission or ME didn't understand the message.
421 */
422int heci_reset(void)
423{
424 uint32_t csr;
425
426 /* Send reset request */
427 csr = read_host_csr();
428 csr |= CSR_RESET;
429 csr |= CSR_IG;
430 write_host_csr(csr);
431
432 if (wait_heci_ready()) {
433 /* Device is back on its imaginary feet, clear reset */
434 csr = read_host_csr();
435 csr &= ~CSR_RESET;
436 csr |= CSR_IG;
437 csr |= CSR_READY;
438 write_host_csr(csr);
439 return 1;
440 }
441
442 printk(BIOS_CRIT, "HECI: reset failed\n");
443
444 return 0;
445}
446
447#if ENV_RAMSTAGE
448
449static void update_sec_bar(struct device *dev)
450{
451 g_cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
452}
453
454static void cse_set_resources(struct device *dev)
455{
456 if (dev->path.pci.devfn == HECI1_DEVFN)
457 update_sec_bar(dev);
458
459 pci_dev_set_resources(dev);
460}
461
462static struct device_operations cse_ops = {
463 .set_resources = cse_set_resources,
464 .read_resources = pci_dev_read_resources,
465 .enable_resources = pci_dev_enable_resources,
466 .init = pci_dev_init,
467 .enable_resources = pci_dev_enable_resources
468};
469
470static const struct pci_driver cse_driver __pci_driver = {
471 .ops = &cse_ops,
472 .vendor = PCI_VENDOR_ID_INTEL,
473 /* SoC/chipset needs to provide PCI device ID */
474 .device = PCI_DEVICE_ID_HECI1
475};
476
477#endif