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