blob: 167cccd1ae321ad948e85076a34f951542aa968f [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>
Subrata Banik05e06cd2017-11-09 15:04:09 +053017#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080018#include <commonlib/helpers.h>
19#include <console/console.h>
20#include <delay.h>
21#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <device/pci_ops.h>
24#include <intelblocks/cse.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053025#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080026#include <soc/pci_devs.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080027#include <string.h>
28#include <timer.h>
29
Subrata Banik5c08c732017-11-13 14:54:37 +053030#define MAX_HECI_MESSAGE_RETRY_COUNT 5
31
Andrey Petrov04a72c42017-03-01 15:51:57 -080032/* 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);
Subrata Banik2ee54db2017-03-05 12:37:00 +053083 device_t dev = PCH_DEV_CSE;
Andrey Petrov04a72c42017-03-01 15:51:57 -080084 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
Subrata Banik05e06cd2017-11-09 15:04:09 +0530112/* Get HECI BAR 0 from PCI configuration space */
113static uint32_t get_cse_bar(void)
114{
115 uintptr_t bar;
116
117 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
118 assert(bar != 0);
119 /*
120 * Bits 31-12 are the base address as per EDS for SPI,
121 * Don't care about 0-11 bit
122 */
123 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
124}
125
Andrey Petrov04a72c42017-03-01 15:51:57 -0800126static uint32_t read_bar(uint32_t offset)
127{
128 struct cse_device *cse = car_get_var_ptr(&g_cse);
Subrata Banik05e06cd2017-11-09 15:04:09 +0530129 /* Reach PCI config space to get BAR incase CAR global not available */
130 if (!cse->sec_bar)
131 cse->sec_bar = get_cse_bar();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800132 return read32((void *)(cse->sec_bar + offset));
133}
134
135static void write_bar(uint32_t offset, uint32_t val)
136{
137 struct cse_device *cse = car_get_var_ptr(&g_cse);
Subrata Banik05e06cd2017-11-09 15:04:09 +0530138 /* Reach PCI config space to get BAR incase CAR global not available */
139 if (!cse->sec_bar)
140 cse->sec_bar = get_cse_bar();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800141 return write32((void *)(cse->sec_bar + offset), val);
142}
143
144static uint32_t read_cse_csr(void)
145{
146 return read_bar(MMIO_CSE_CSR);
147}
148
149static uint32_t read_host_csr(void)
150{
151 return read_bar(MMIO_HOST_CSR);
152}
153
154static void write_host_csr(uint32_t data)
155{
156 write_bar(MMIO_HOST_CSR, data);
157}
158
159static size_t filled_slots(uint32_t data)
160{
161 uint8_t wp, rp;
162 rp = data >> CSR_RP_START;
163 wp = data >> CSR_WP_START;
164 return (uint8_t) (wp - rp);
165}
166
167static size_t cse_filled_slots(void)
168{
169 return filled_slots(read_cse_csr());
170}
171
172static size_t host_empty_slots(void)
173{
174 uint32_t csr;
175 csr = read_host_csr();
176
177 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
178}
179
180static void clear_int(void)
181{
182 uint32_t csr;
183 csr = read_host_csr();
184 csr |= CSR_IS;
185 write_host_csr(csr);
186}
187
188static uint32_t read_slot(void)
189{
190 return read_bar(MMIO_CSE_CB_RW);
191}
192
193static void write_slot(uint32_t val)
194{
195 write_bar(MMIO_CSE_CB_WW, val);
196}
197
198static int wait_write_slots(size_t cnt)
199{
200 struct stopwatch sw;
201
202 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
203 while (host_empty_slots() < cnt) {
204 udelay(HECI_DELAY);
205 if (stopwatch_expired(&sw)) {
206 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
207 return 0;
208 }
209 }
210 return 1;
211}
212
213static int wait_read_slots(size_t cnt)
214{
215 struct stopwatch sw;
216
217 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
218 while (cse_filled_slots() < cnt) {
219 udelay(HECI_DELAY);
220 if (stopwatch_expired(&sw)) {
221 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
222 return 0;
223 }
224 }
225 return 1;
226}
227
228/* get number of full 4-byte slots */
229static size_t bytes_to_slots(size_t bytes)
230{
231 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
232}
233
234static int cse_ready(void)
235{
236 uint32_t csr;
237 csr = read_cse_csr();
238 return csr & CSR_READY;
239}
240
241static int wait_heci_ready(void)
242{
243 struct stopwatch sw;
244
245 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
246 while (!cse_ready()) {
247 udelay(HECI_DELAY);
248 if (stopwatch_expired(&sw))
249 return 0;
250 }
251
252 return 1;
253}
254
255static void host_gen_interrupt(void)
256{
257 uint32_t csr;
258 csr = read_host_csr();
259 csr |= CSR_IG;
260 write_host_csr(csr);
261}
262
263static size_t hdr_get_length(uint32_t hdr)
264{
265 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
266}
267
268static int
269send_one_message(uint32_t hdr, const void *buff)
270{
271 size_t pend_len, pend_slots, remainder, i;
272 uint32_t tmp;
273 const uint32_t *p = buff;
274
275 /* Get space for the header */
276 if (!wait_write_slots(1))
277 return 0;
278
279 /* First, write header */
280 write_slot(hdr);
281
282 pend_len = hdr_get_length(hdr);
283 pend_slots = bytes_to_slots(pend_len);
284
285 if (!wait_write_slots(pend_slots))
286 return 0;
287
288 /* Write the body in whole slots */
289 i = 0;
290 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
291 write_slot(*p++);
292 i += SLOT_SIZE;
293 }
294
295 remainder = pend_len % SLOT_SIZE;
296 /* Pad to 4 bytes not touching caller's buffer */
297 if (remainder) {
298 memcpy(&tmp, p, remainder);
299 write_slot(tmp);
300 }
301
302 host_gen_interrupt();
303
304 /* Make sure nothing bad happened during transmission */
305 if (!cse_ready())
306 return 0;
307
308 return pend_len;
309}
310
311int
312heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
313{
Subrata Banik5c08c732017-11-13 14:54:37 +0530314 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800315 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530316 size_t sent, remaining, cb_size, max_length;
317 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800318
319 if (!msg || !len)
320 return 0;
321
322 clear_int();
323
Subrata Banik5c08c732017-11-13 14:54:37 +0530324 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
325 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800326
Subrata Banik5c08c732017-11-13 14:54:37 +0530327 if (!wait_heci_ready()) {
328 printk(BIOS_ERR, "HECI: not ready\n");
329 continue;
330 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800331
Subrata Banik5c08c732017-11-13 14:54:37 +0530332 csr = read_cse_csr();
333 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
334 /*
335 * Reserve one slot for the header. Limit max message
336 * length by 9 bits that are available in the header.
337 */
338 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
339 - SLOT_SIZE;
340 remaining = len;
341
342 /*
343 * Fragment the message into smaller messages not exceeding
344 * useful circullar buffer length. Mark last message complete.
345 */
346 do {
347 hdr = MIN(max_length, remaining)
348 << MEI_HDR_LENGTH_START;
349 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
350 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
351 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800352 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530353 sent = send_one_message(hdr, p);
354 p += sent;
355 remaining -= sent;
356 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800357
Subrata Banik5c08c732017-11-13 14:54:37 +0530358 if (!remaining)
359 return 1;
360 }
361 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800362}
363
364static size_t
365recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
366{
367 uint32_t reg, *p = buff;
368 size_t recv_slots, recv_len, remainder, i;
369
370 /* first get the header */
371 if (!wait_read_slots(1))
372 return 0;
373
374 *hdr = read_slot();
375 recv_len = hdr_get_length(*hdr);
376
377 if (!recv_len)
378 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
379
380 recv_slots = bytes_to_slots(recv_len);
381
382 i = 0;
383 if (recv_len > maxlen) {
384 printk(BIOS_ERR, "HECI: response is too big\n");
385 return 0;
386 }
387
388 /* wait for the rest of messages to arrive */
389 wait_read_slots(recv_slots);
390
391 /* fetch whole slots first */
392 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
393 *p++ = read_slot();
394 i += SLOT_SIZE;
395 }
396
Subrata Banik5c08c732017-11-13 14:54:37 +0530397 /*
398 * If ME is not ready, something went wrong and
399 * we received junk
400 */
401 if (!cse_ready())
402 return 0;
403
Andrey Petrov04a72c42017-03-01 15:51:57 -0800404 remainder = recv_len % SLOT_SIZE;
405
406 if (remainder) {
407 reg = read_slot();
408 memcpy(p, &reg, remainder);
409 }
410
411 return recv_len;
412}
413
414int heci_receive(void *buff, size_t *maxlen)
415{
Subrata Banik5c08c732017-11-13 14:54:37 +0530416 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800417 size_t left, received;
418 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530419 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800420
421 if (!buff || !maxlen || !*maxlen)
422 return 0;
423
Andrey Petrov04a72c42017-03-01 15:51:57 -0800424 clear_int();
425
Subrata Banik5c08c732017-11-13 14:54:37 +0530426 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
427 p = buff;
428 left = *maxlen;
429
430 if (!wait_heci_ready()) {
431 printk(BIOS_ERR, "HECI: not ready\n");
432 continue;
433 }
434
435 /*
436 * Receive multiple packets until we meet one marked
437 * complete or we run out of space in caller-provided buffer.
438 */
439 do {
440 received = recv_one_message(&hdr, p, left);
441 left -= received;
442 p += received;
443 /* If we read out everything ping to send more */
444 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
445 host_gen_interrupt();
446 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
447
448 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
449 *maxlen = p - (uint8_t *) buff;
450 return 1;
451 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800452 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530453 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800454}
455
456/*
457 * Attempt to reset the device. This is useful when host and ME are out
458 * of sync during transmission or ME didn't understand the message.
459 */
460int heci_reset(void)
461{
462 uint32_t csr;
463
464 /* Send reset request */
465 csr = read_host_csr();
466 csr |= CSR_RESET;
467 csr |= CSR_IG;
468 write_host_csr(csr);
469
470 if (wait_heci_ready()) {
471 /* Device is back on its imaginary feet, clear reset */
472 csr = read_host_csr();
473 csr &= ~CSR_RESET;
474 csr |= CSR_IG;
475 csr |= CSR_READY;
476 write_host_csr(csr);
477 return 1;
478 }
479
480 printk(BIOS_CRIT, "HECI: reset failed\n");
481
482 return 0;
483}
484
485#if ENV_RAMSTAGE
486
487static void update_sec_bar(struct device *dev)
488{
489 g_cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
490}
491
492static void cse_set_resources(struct device *dev)
493{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530494 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800495 update_sec_bar(dev);
496
497 pci_dev_set_resources(dev);
498}
499
500static struct device_operations cse_ops = {
501 .set_resources = cse_set_resources,
502 .read_resources = pci_dev_read_resources,
503 .enable_resources = pci_dev_enable_resources,
504 .init = pci_dev_init,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800505};
506
Hannah Williams63142152017-06-12 14:03:18 -0700507static const unsigned short pci_device_ids[] = {
508 PCI_DEVICE_ID_INTEL_APL_CSE0,
509 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700510 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Hannah Williams63142152017-06-12 14:03:18 -0700511 0,
512};
513
Andrey Petrov04a72c42017-03-01 15:51:57 -0800514static const struct pci_driver cse_driver __pci_driver = {
515 .ops = &cse_ops,
516 .vendor = PCI_VENDOR_ID_INTEL,
517 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700518 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800519};
520
521#endif