blob: 9520242d2e9a2b7b60aa1561553a48a85864e874 [file] [log] [blame]
Andrey Petrov04a72c42017-03-01 15:51:57 -08001/*
2 * This file is part of the coreboot project.
3 *
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +08004 * Copyright 2017-2018 Intel Inc.
Andrey Petrov04a72c42017-03-01 15:51:57 -08005 *
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
Subrata Banik05e06cd2017-11-09 15:04:09 +053016#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080017#include <commonlib/helpers.h>
18#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020019#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080020#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)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010034/* Wait up to 100 usec between circular buffer polls */
Andrey Petrov04a72c42017-03-01 15:51:57 -080035#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
Arthur Heymans3d6ccd02019-05-27 17:25:23 +020071static struct cse_device {
Andrey Petrov04a72c42017-03-01 15:51:57 -080072 uintptr_t sec_bar;
Arthur Heymansa5eed802019-05-25 10:28:11 +020073} g_cse;
Andrey Petrov04a72c42017-03-01 15:51:57 -080074
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{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020082#if defined(__SIMPLE_DEVICE__)
83 pci_devfn_t dev = PCH_DEV_CSE;
84#else
85 struct device *dev = PCH_DEV_CSE;
86#endif
Andrey Petrov04a72c42017-03-01 15:51:57 -080087 u8 pcireg;
88
89 /* Assume it is already initialized, nothing else to do */
Arthur Heymansa5eed802019-05-25 10:28:11 +020090 if (g_cse.sec_bar)
Andrey Petrov04a72c42017-03-01 15:51:57 -080091 return;
92
93 /* Use default pre-ram bar */
94 if (!tempbar)
95 tempbar = HECI1_BASE_ADDRESS;
96
97 /* Assign Resources to HECI1 */
98 /* Clear BIT 1-2 of Command Register */
99 pcireg = pci_read_config8(dev, PCI_COMMAND);
100 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
101 pci_write_config8(dev, PCI_COMMAND, pcireg);
102
103 /* Program Temporary BAR for HECI1 */
104 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
105 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
106
107 /* Enable Bus Master and MMIO Space */
108 pcireg = pci_read_config8(dev, PCI_COMMAND);
109 pcireg |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
110 pci_write_config8(dev, PCI_COMMAND, pcireg);
111
Arthur Heymansa5eed802019-05-25 10:28:11 +0200112 g_cse.sec_bar = tempbar;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800113}
114
Subrata Banik05e06cd2017-11-09 15:04:09 +0530115/* Get HECI BAR 0 from PCI configuration space */
116static uint32_t get_cse_bar(void)
117{
118 uintptr_t bar;
119
120 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
121 assert(bar != 0);
122 /*
123 * Bits 31-12 are the base address as per EDS for SPI,
124 * Don't care about 0-11 bit
125 */
126 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
127}
128
Andrey Petrov04a72c42017-03-01 15:51:57 -0800129static uint32_t read_bar(uint32_t offset)
130{
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100131 /* Reach PCI config space to get BAR in case CAR global not available */
Arthur Heymansa5eed802019-05-25 10:28:11 +0200132 if (!g_cse.sec_bar)
133 g_cse.sec_bar = get_cse_bar();
134 return read32((void *)(g_cse.sec_bar + offset));
Andrey Petrov04a72c42017-03-01 15:51:57 -0800135}
136
137static void write_bar(uint32_t offset, uint32_t val)
138{
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100139 /* Reach PCI config space to get BAR in case CAR global not available */
Arthur Heymansa5eed802019-05-25 10:28:11 +0200140 if (!g_cse.sec_bar)
141 g_cse.sec_bar = get_cse_bar();
142 return write32((void *)(g_cse.sec_bar + offset), val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800143}
144
145static uint32_t read_cse_csr(void)
146{
147 return read_bar(MMIO_CSE_CSR);
148}
149
150static uint32_t read_host_csr(void)
151{
152 return read_bar(MMIO_HOST_CSR);
153}
154
155static void write_host_csr(uint32_t data)
156{
157 write_bar(MMIO_HOST_CSR, data);
158}
159
160static size_t filled_slots(uint32_t data)
161{
162 uint8_t wp, rp;
163 rp = data >> CSR_RP_START;
164 wp = data >> CSR_WP_START;
165 return (uint8_t) (wp - rp);
166}
167
168static size_t cse_filled_slots(void)
169{
170 return filled_slots(read_cse_csr());
171}
172
173static size_t host_empty_slots(void)
174{
175 uint32_t csr;
176 csr = read_host_csr();
177
178 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
179}
180
181static void clear_int(void)
182{
183 uint32_t csr;
184 csr = read_host_csr();
185 csr |= CSR_IS;
186 write_host_csr(csr);
187}
188
189static uint32_t read_slot(void)
190{
191 return read_bar(MMIO_CSE_CB_RW);
192}
193
194static void write_slot(uint32_t val)
195{
196 write_bar(MMIO_CSE_CB_WW, val);
197}
198
199static int wait_write_slots(size_t cnt)
200{
201 struct stopwatch sw;
202
203 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
204 while (host_empty_slots() < cnt) {
205 udelay(HECI_DELAY);
206 if (stopwatch_expired(&sw)) {
207 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
208 return 0;
209 }
210 }
211 return 1;
212}
213
214static int wait_read_slots(size_t cnt)
215{
216 struct stopwatch sw;
217
218 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
219 while (cse_filled_slots() < cnt) {
220 udelay(HECI_DELAY);
221 if (stopwatch_expired(&sw)) {
222 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
223 return 0;
224 }
225 }
226 return 1;
227}
228
229/* get number of full 4-byte slots */
230static size_t bytes_to_slots(size_t bytes)
231{
232 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
233}
234
235static int cse_ready(void)
236{
237 uint32_t csr;
238 csr = read_cse_csr();
239 return csr & CSR_READY;
240}
241
242static int wait_heci_ready(void)
243{
244 struct stopwatch sw;
245
246 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
247 while (!cse_ready()) {
248 udelay(HECI_DELAY);
249 if (stopwatch_expired(&sw))
250 return 0;
251 }
252
253 return 1;
254}
255
256static void host_gen_interrupt(void)
257{
258 uint32_t csr;
259 csr = read_host_csr();
260 csr |= CSR_IG;
261 write_host_csr(csr);
262}
263
264static size_t hdr_get_length(uint32_t hdr)
265{
266 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
267}
268
269static int
270send_one_message(uint32_t hdr, const void *buff)
271{
272 size_t pend_len, pend_slots, remainder, i;
273 uint32_t tmp;
274 const uint32_t *p = buff;
275
276 /* Get space for the header */
277 if (!wait_write_slots(1))
278 return 0;
279
280 /* First, write header */
281 write_slot(hdr);
282
283 pend_len = hdr_get_length(hdr);
284 pend_slots = bytes_to_slots(pend_len);
285
286 if (!wait_write_slots(pend_slots))
287 return 0;
288
289 /* Write the body in whole slots */
290 i = 0;
291 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
292 write_slot(*p++);
293 i += SLOT_SIZE;
294 }
295
296 remainder = pend_len % SLOT_SIZE;
297 /* Pad to 4 bytes not touching caller's buffer */
298 if (remainder) {
299 memcpy(&tmp, p, remainder);
300 write_slot(tmp);
301 }
302
303 host_gen_interrupt();
304
305 /* Make sure nothing bad happened during transmission */
306 if (!cse_ready())
307 return 0;
308
309 return pend_len;
310}
311
312int
313heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
314{
Subrata Banik5c08c732017-11-13 14:54:37 +0530315 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800316 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530317 size_t sent, remaining, cb_size, max_length;
318 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800319
320 if (!msg || !len)
321 return 0;
322
323 clear_int();
324
Subrata Banik5c08c732017-11-13 14:54:37 +0530325 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
326 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800327
Subrata Banik5c08c732017-11-13 14:54:37 +0530328 if (!wait_heci_ready()) {
329 printk(BIOS_ERR, "HECI: not ready\n");
330 continue;
331 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800332
Subrata Banik4a722f52017-11-13 14:56:42 +0530333 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530334 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
335 /*
336 * Reserve one slot for the header. Limit max message
337 * length by 9 bits that are available in the header.
338 */
339 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
340 - SLOT_SIZE;
341 remaining = len;
342
343 /*
344 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100345 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530346 */
347 do {
348 hdr = MIN(max_length, remaining)
349 << MEI_HDR_LENGTH_START;
350 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
351 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
352 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800353 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530354 sent = send_one_message(hdr, p);
355 p += sent;
356 remaining -= sent;
357 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800358
Subrata Banik5c08c732017-11-13 14:54:37 +0530359 if (!remaining)
360 return 1;
361 }
362 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800363}
364
365static size_t
366recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
367{
368 uint32_t reg, *p = buff;
369 size_t recv_slots, recv_len, remainder, i;
370
371 /* first get the header */
372 if (!wait_read_slots(1))
373 return 0;
374
375 *hdr = read_slot();
376 recv_len = hdr_get_length(*hdr);
377
378 if (!recv_len)
379 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
380
381 recv_slots = bytes_to_slots(recv_len);
382
383 i = 0;
384 if (recv_len > maxlen) {
385 printk(BIOS_ERR, "HECI: response is too big\n");
386 return 0;
387 }
388
389 /* wait for the rest of messages to arrive */
390 wait_read_slots(recv_slots);
391
392 /* fetch whole slots first */
393 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
394 *p++ = read_slot();
395 i += SLOT_SIZE;
396 }
397
Subrata Banik5c08c732017-11-13 14:54:37 +0530398 /*
399 * If ME is not ready, something went wrong and
400 * we received junk
401 */
402 if (!cse_ready())
403 return 0;
404
Andrey Petrov04a72c42017-03-01 15:51:57 -0800405 remainder = recv_len % SLOT_SIZE;
406
407 if (remainder) {
408 reg = read_slot();
409 memcpy(p, &reg, remainder);
410 }
411
412 return recv_len;
413}
414
415int heci_receive(void *buff, size_t *maxlen)
416{
Subrata Banik5c08c732017-11-13 14:54:37 +0530417 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800418 size_t left, received;
419 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530420 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800421
422 if (!buff || !maxlen || !*maxlen)
423 return 0;
424
Andrey Petrov04a72c42017-03-01 15:51:57 -0800425 clear_int();
426
Subrata Banik5c08c732017-11-13 14:54:37 +0530427 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
428 p = buff;
429 left = *maxlen;
430
431 if (!wait_heci_ready()) {
432 printk(BIOS_ERR, "HECI: not ready\n");
433 continue;
434 }
435
436 /*
437 * Receive multiple packets until we meet one marked
438 * complete or we run out of space in caller-provided buffer.
439 */
440 do {
441 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800442 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200443 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800444 return 0;
445 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530446 left -= received;
447 p += received;
448 /* If we read out everything ping to send more */
449 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
450 host_gen_interrupt();
451 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
452
453 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
454 *maxlen = p - (uint8_t *) buff;
455 return 1;
456 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800457 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530458 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800459}
460
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530461int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz)
462{
463 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, HECI_MKHI_ADDR)) {
464 printk(BIOS_ERR, "HECI: send Failed\n");
465 return 0;
466 }
467
468 if (rcv_msg != NULL) {
469 if (!heci_receive(rcv_msg, rcv_sz)) {
470 printk(BIOS_ERR, "HECI: receive Failed\n");
471 return 0;
472 }
473 }
474 return 1;
475}
476
Andrey Petrov04a72c42017-03-01 15:51:57 -0800477/*
478 * Attempt to reset the device. This is useful when host and ME are out
479 * of sync during transmission or ME didn't understand the message.
480 */
481int heci_reset(void)
482{
483 uint32_t csr;
484
485 /* Send reset request */
486 csr = read_host_csr();
487 csr |= CSR_RESET;
488 csr |= CSR_IG;
489 write_host_csr(csr);
490
491 if (wait_heci_ready()) {
492 /* Device is back on its imaginary feet, clear reset */
493 csr = read_host_csr();
494 csr &= ~CSR_RESET;
495 csr |= CSR_IG;
496 csr |= CSR_READY;
497 write_host_csr(csr);
498 return 1;
499 }
500
501 printk(BIOS_CRIT, "HECI: reset failed\n");
502
503 return 0;
504}
505
506#if ENV_RAMSTAGE
507
508static void update_sec_bar(struct device *dev)
509{
510 g_cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
511}
512
513static void cse_set_resources(struct device *dev)
514{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530515 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800516 update_sec_bar(dev);
517
518 pci_dev_set_resources(dev);
519}
520
521static struct device_operations cse_ops = {
522 .set_resources = cse_set_resources,
523 .read_resources = pci_dev_read_resources,
524 .enable_resources = pci_dev_enable_resources,
525 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530526 .ops_pci = &pci_dev_ops_pci,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800527};
528
Hannah Williams63142152017-06-12 14:03:18 -0700529static const unsigned short pci_device_ids[] = {
530 PCI_DEVICE_ID_INTEL_APL_CSE0,
531 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700532 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +0530533 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +0300534 PCI_DEVICE_ID_INTEL_LWB_CSE0,
535 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800536 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530537 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530538 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Hannah Williams63142152017-06-12 14:03:18 -0700539 0,
540};
541
Andrey Petrov04a72c42017-03-01 15:51:57 -0800542static const struct pci_driver cse_driver __pci_driver = {
543 .ops = &cse_ops,
544 .vendor = PCI_VENDOR_ID_INTEL,
545 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700546 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800547};
548
549#endif