soc/intel/skylake: Make use of common CSE code for skylake
TEST=Ensures global reset could able to reset system. Change-Id: I11ce1812a5a0aa2da6b414555374460d606e220e Signed-off-by: Subrata Banik <subrata.banik@intel.com> Reviewed-on: https://review.coreboot.org/22395 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
parent
4a722f5e2f
commit
bffff54e09
|
@ -54,6 +54,7 @@ config CPU_SPECIFIC_OPTIONS
|
|||
select SOC_INTEL_COMMON_BLOCK
|
||||
select SOC_INTEL_COMMON_BLOCK_CPU
|
||||
select SOC_INTEL_COMMON_BLOCK_CPU_MPINIT
|
||||
select SOC_INTEL_COMMON_BLOCK_CSE
|
||||
select SOC_INTEL_COMMON_BLOCK_EBDA
|
||||
select SOC_INTEL_COMMON_BLOCK_FAST_SPI
|
||||
select SOC_INTEL_COMMON_BLOCK_GPIO
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <chip.h>
|
||||
#include <device/device.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <intelblocks/cse.h>
|
||||
#include <intelblocks/fast_spi.h>
|
||||
#include <intelblocks/itss.h>
|
||||
#include <intelblocks/lpc_lib.h>
|
||||
|
@ -157,27 +158,6 @@ static void soc_config_tco(void)
|
|||
outw(tcocnt, tcobase + TCO1_CNT);
|
||||
}
|
||||
|
||||
static void enable_heci(void)
|
||||
{
|
||||
device_t dev = PCH_DEV_CSE;
|
||||
u8 pcireg;
|
||||
|
||||
/* Assign Resources to HECI1 */
|
||||
/* Clear BIT 1-2 of Command Register */
|
||||
pcireg = pci_read_config8(dev, PCI_COMMAND);
|
||||
pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
pci_write_config8(dev, PCI_COMMAND, pcireg);
|
||||
|
||||
/* Program Temporary BAR for HECI1 */
|
||||
pci_write_config32(dev, PCI_BASE_ADDRESS_0, HECI1_BASE_ADDRESS);
|
||||
pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
|
||||
|
||||
/* Enable Bus Master and MMIO Space */
|
||||
pcireg = pci_read_config8(dev, PCI_COMMAND);
|
||||
pcireg |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
pci_write_config8(dev, PCI_COMMAND, pcireg);
|
||||
}
|
||||
|
||||
void pch_early_iorange_init(void)
|
||||
{
|
||||
/* IO Decode Range */
|
||||
|
@ -216,5 +196,6 @@ void pch_early_init(void)
|
|||
|
||||
enable_rtc_upper_bank();
|
||||
|
||||
enable_heci();
|
||||
/* initialize Heci interface */
|
||||
heci_init(HECI1_BASE_ADDRESS);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
* Copyright (C) 2016 Intel Corporation.
|
||||
* Copyright (C) 2016-2017 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -202,47 +202,6 @@ union me_hfs6 {
|
|||
} __packed fields;
|
||||
};
|
||||
|
||||
/*
|
||||
* Management Engine MMIO registers
|
||||
*/
|
||||
#define MMIO_ME_CB_WW 0x00
|
||||
#define MMIO_HOST_CSR 0x04
|
||||
|
||||
union host_csr {
|
||||
u32 data;
|
||||
struct {
|
||||
u32 int_en: 1;
|
||||
u32 int_sts: 1;
|
||||
u32 int_gen: 1;
|
||||
u32 host_ready: 1;
|
||||
u32 host_reset: 1;
|
||||
u32 rsv: 3;
|
||||
u32 host_read_offset: 8;
|
||||
u32 host_write_offset: 8;
|
||||
u32 me_cir_depth: 8;
|
||||
} __packed fields;
|
||||
};
|
||||
|
||||
#define MMIO_ME_CB_RW 0x08
|
||||
#define MMIO_ME_CSR 0x0C
|
||||
|
||||
union me_csr {
|
||||
u32 data;
|
||||
struct {
|
||||
u32 int_en: 1;
|
||||
u32 int_sts: 1;
|
||||
u32 int_gen: 1;
|
||||
u32 host_ready: 1;
|
||||
u32 host_reset: 1;
|
||||
u32 rsv: 3;
|
||||
u32 me_read_offset: 8;
|
||||
u32 me_write_offset: 8;
|
||||
u32 me_cir_buff: 8;
|
||||
} __packed fields;
|
||||
};
|
||||
|
||||
#define MMIO_ME_D0I3 0x800
|
||||
|
||||
/* Reset Request */
|
||||
#define MKHI_GLOBAL_RESET 0x0b
|
||||
|
||||
|
@ -255,23 +214,6 @@ union me_csr {
|
|||
#define BIOS_HOST_ADD 0x00
|
||||
#define HECI_MKHI_ADD 0x07
|
||||
|
||||
#define MAX_HECI_MESSAGE 5
|
||||
#define HECI_TIMEOUT 15000000 /* 15sec */
|
||||
#define HECI_SEND_TIMEOUT 5000000 /* 5sec */
|
||||
#define HECI_READ_TIMEOUT 5000000 /* 5sec */
|
||||
#define HECI_DELAY 1000 /* 1ms */
|
||||
|
||||
union mei_header {
|
||||
u32 data;
|
||||
struct {
|
||||
u32 client_address: 8;
|
||||
u32 host_address: 8;
|
||||
u32 length: 9;
|
||||
u32 reserved: 6;
|
||||
u32 is_complete: 1;
|
||||
} __packed fields;
|
||||
};
|
||||
|
||||
void intel_me_status(void);
|
||||
int send_global_reset(void);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation.
|
||||
* Copyright (C) 2016-2017 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,40 +15,23 @@
|
|||
|
||||
#include <arch/io.h>
|
||||
#include <commonlib/helpers.h>
|
||||
#include <compiler.h>
|
||||
#include <console/console.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <intelblocks/cse.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <soc/me.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <stdint.h>
|
||||
#include <compiler.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <soc/me.h>
|
||||
#include <delay.h>
|
||||
#include <timer.h>
|
||||
|
||||
static inline u32 me_read_config32(int offset)
|
||||
{
|
||||
return pci_read_config32(PCH_DEV_CSE, offset);
|
||||
}
|
||||
|
||||
static inline void me_write_config32(int offset, u32 value)
|
||||
{
|
||||
pci_write_config32(PCH_DEV_CSE, offset, value);
|
||||
}
|
||||
|
||||
static inline u32 me_read_mmio32(int offset)
|
||||
{
|
||||
return read32((void *)(HECI1_BASE_ADDRESS + offset));
|
||||
}
|
||||
|
||||
static inline void me_write_mmio32(u16 offset, u32 value)
|
||||
{
|
||||
write32((void *)(HECI1_BASE_ADDRESS + offset), value);
|
||||
}
|
||||
|
||||
/* HFSTS1[3:0] Current Working State Values */
|
||||
static const char * const me_cws_values[] = {
|
||||
[ME_HFS_CWS_RESET] = "Reset",
|
||||
|
@ -368,291 +351,6 @@ void intel_me_status(void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Aligning a byte length to length in dwords.
|
||||
*/
|
||||
static u32 get_dword_length(u32 byte_length)
|
||||
{
|
||||
return ALIGN_UP(byte_length, sizeof(uint32_t)) / sizeof(uint32_t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get remaining message count in dword from circular buffer based on
|
||||
* write and read offset.
|
||||
*/
|
||||
static u32 get_cb_msg_count(u32 data)
|
||||
{
|
||||
u8 read_offset = data >> 8;
|
||||
u8 write_offset = data >> 16;
|
||||
|
||||
return get_dword_length(write_offset - read_offset);
|
||||
}
|
||||
|
||||
static int wait_heci_ready(void)
|
||||
{
|
||||
struct stopwatch sw;
|
||||
int timeout = 0;
|
||||
union me_csr csr;
|
||||
|
||||
stopwatch_init_msecs_expire(&sw, HECI_TIMEOUT);
|
||||
while (1) {
|
||||
do {
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
if (csr.fields.host_ready)
|
||||
return 0;
|
||||
} while (!(timeout = stopwatch_expired(&sw)));
|
||||
|
||||
printk(BIOS_ERR, "ME_RDY bit is not set after 15 sec");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int wait_heci_cb_avail(u32 len)
|
||||
{
|
||||
struct stopwatch sw;
|
||||
union host_csr csr;
|
||||
|
||||
csr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
/*
|
||||
* if timeout has happened, return failure as
|
||||
* the circular buffer is not empty
|
||||
*/
|
||||
stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
|
||||
/* Must have room for message and message header */
|
||||
while (len > (get_dword_length(csr.fields.me_cir_depth) -
|
||||
get_cb_msg_count(csr.data))) {
|
||||
if (stopwatch_expired(&sw)) {
|
||||
printk(BIOS_ERR,
|
||||
"Circular Buffer never emptied within 5 sec");
|
||||
return -1;
|
||||
}
|
||||
/* wait before trying again */
|
||||
udelay(HECI_DELAY);
|
||||
/* read HOST_CSR for next iteration */
|
||||
csr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_heci_packet(union mei_header *head, u32 len, u32 *payload)
|
||||
{
|
||||
int sts;
|
||||
int index;
|
||||
union me_csr csr;
|
||||
union host_csr hcsr;
|
||||
|
||||
/*
|
||||
* wait until there is sufficient room in CB
|
||||
*/
|
||||
sts = wait_heci_cb_avail(len + 1);
|
||||
if (sts != 0)
|
||||
return -1;
|
||||
|
||||
/* Write message header */
|
||||
me_write_mmio32(MMIO_ME_CB_WW, head->data);
|
||||
|
||||
/* Write message body */
|
||||
for (index = 0; index < len; index++)
|
||||
me_write_mmio32(MMIO_ME_CB_WW, payload[index]);
|
||||
|
||||
/* Set Interrupt Generate bit */
|
||||
hcsr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
hcsr.fields.int_gen = 1;
|
||||
me_write_mmio32(MMIO_HOST_CSR, hcsr.data);
|
||||
|
||||
/* Check if ME Ready bit is set, if set to 0 then return fatal error */
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
if (csr.fields.host_ready)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int recv_heci_packet(union mei_header *head, u32 *packet,
|
||||
u32 *packet_size)
|
||||
{
|
||||
union me_csr csr;
|
||||
union host_csr hcsr;
|
||||
int rec_msg = 0;
|
||||
struct stopwatch sw;
|
||||
u32 length, index;
|
||||
|
||||
/* Clear Interrupt Status bit */
|
||||
hcsr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
hcsr.fields.int_sts = 1;
|
||||
me_write_mmio32(MMIO_HOST_CSR, hcsr.data);
|
||||
|
||||
/* Check if circular buffer overflow
|
||||
* if yes then return fatal error
|
||||
*/
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
if (get_cb_msg_count(csr.data) >
|
||||
get_dword_length(csr.fields.me_cir_buff))
|
||||
return -1;
|
||||
/*
|
||||
* if timeout has happened, return failure as
|
||||
* the circular buffer is not empty
|
||||
*/
|
||||
stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
|
||||
/* go until we got message pkt */
|
||||
do {
|
||||
if (stopwatch_expired(&sw)) {
|
||||
printk(BIOS_ERR,
|
||||
"Circular Buffer not filled within 5 sec");
|
||||
*packet_size = 0;
|
||||
return -1;
|
||||
}
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
/* Read one message from HECI buffer */
|
||||
if (get_cb_msg_count(csr.data) > 0) {
|
||||
head->data = me_read_mmio32(MMIO_ME_CB_RW);
|
||||
/* calculate the message length in dword */
|
||||
length = get_dword_length(head->fields.length);
|
||||
if (head->fields.length == 0) {
|
||||
*packet_size = 0;
|
||||
goto SET_IG;
|
||||
}
|
||||
/* Make sure, we have enough space to catch all */
|
||||
if (head->fields.length <= *packet_size) {
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
/* get complete message into circular buffer */
|
||||
while (length > get_cb_msg_count(csr.data)) {
|
||||
udelay(HECI_DELAY);
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
}
|
||||
/* here is the message */
|
||||
for (index = 0; index < length; index++)
|
||||
packet[index] =
|
||||
me_read_mmio32(MMIO_ME_CB_RW);
|
||||
|
||||
rec_msg = 1;
|
||||
*packet_size = head->fields.length;
|
||||
} else {
|
||||
/* Too small buffer */
|
||||
*packet_size = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} while (!rec_msg);
|
||||
|
||||
/*
|
||||
* Check if ME Ready bit is set, if set to 0 then return fatal error
|
||||
* because ME might have reset during transaction and we might have
|
||||
* read a junk data from CB
|
||||
*/
|
||||
csr.data = me_read_mmio32(MMIO_ME_CSR);
|
||||
if (!(csr.fields.host_ready))
|
||||
return -1;
|
||||
SET_IG:
|
||||
/* Set Interrupt Generate bit */
|
||||
hcsr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
hcsr.fields.int_gen = 1;
|
||||
me_write_mmio32(MMIO_HOST_CSR, hcsr.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_heci_message(void *msg, int len, u8 hostaddress, u8 clientaddress)
|
||||
{
|
||||
u8 retry;
|
||||
int status = -1;
|
||||
u32 cir_buff_depth;
|
||||
union host_csr csr;
|
||||
union mei_header head;
|
||||
int cur = 0;
|
||||
u32 slength, rlength;
|
||||
|
||||
for (retry = 0; retry < MAX_HECI_MESSAGE; retry++) {
|
||||
if (wait_heci_ready() != 0)
|
||||
continue;
|
||||
/* HECI is ready */
|
||||
csr.data = me_read_mmio32(MMIO_HOST_CSR);
|
||||
cir_buff_depth = csr.fields.me_cir_depth;
|
||||
head.fields.client_address = clientaddress;
|
||||
head.fields.host_address = hostaddress;
|
||||
while (len > cur) {
|
||||
rlength = get_dword_length(len - cur);
|
||||
/*
|
||||
* Set the message complete bit if this is last packet
|
||||
* in message needs to be "less than" to account for
|
||||
* the header OR needs to be exact equal to CB depth
|
||||
*/
|
||||
if (rlength <= cir_buff_depth)
|
||||
head.fields.is_complete = 1;
|
||||
else
|
||||
head.fields.is_complete = 0;
|
||||
/*
|
||||
* calculate length for message header
|
||||
* header length = smaller of CB buffer or
|
||||
* remaining message
|
||||
*/
|
||||
slength = ((cir_buff_depth <= rlength)
|
||||
? ((cir_buff_depth - 1) * 4)
|
||||
: (len - cur));
|
||||
head.fields.length = slength;
|
||||
head.fields.reserved = 0;
|
||||
/*
|
||||
* send the current packet
|
||||
* (cur should be treated as index for message)
|
||||
*/
|
||||
status = send_heci_packet(&head,
|
||||
get_dword_length(head.fields.length), msg);
|
||||
if (status != 0)
|
||||
break;
|
||||
/* update the length information */
|
||||
cur += slength;
|
||||
msg += cur;
|
||||
}
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
recv_heci_message(void *message, u32 *message_size)
|
||||
{
|
||||
union mei_header head;
|
||||
int cur = 0;
|
||||
u8 retry;
|
||||
int status = -1;
|
||||
int msg_complete = 0;
|
||||
u32 pkt_buff;
|
||||
|
||||
for (retry = 0; retry < MAX_HECI_MESSAGE; retry++) {
|
||||
if (wait_heci_ready() != 0)
|
||||
continue;
|
||||
/* HECI is ready */
|
||||
while ((cur < *message_size) && (msg_complete == 0)) {
|
||||
pkt_buff = *message_size - cur;
|
||||
status = recv_heci_packet(&head, message + (cur >> 2),
|
||||
&pkt_buff);
|
||||
if (status == -1) {
|
||||
*message_size = 0;
|
||||
break;
|
||||
}
|
||||
msg_complete = head.fields.is_complete;
|
||||
if (pkt_buff == 0) {
|
||||
/* if not in middle of msg and msg complete bit
|
||||
* is set then this is a valid zero length msg
|
||||
*/
|
||||
if ((cur == 0) && (msg_complete == 1))
|
||||
status = 0;
|
||||
else
|
||||
status = -1;
|
||||
*message_size = 0;
|
||||
break;
|
||||
}
|
||||
cur += pkt_buff;
|
||||
}
|
||||
if (!status) {
|
||||
*message_size = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int send_heci_reset_message(void)
|
||||
{
|
||||
int status;
|
||||
|
@ -675,19 +373,21 @@ static int send_heci_reset_message(void)
|
|||
.req_origin = GR_ORIGIN_BIOS_POST,
|
||||
.reset_type = GLOBAL_RST_TYPE
|
||||
};
|
||||
u32 reply_size;
|
||||
size_t reply_size;
|
||||
|
||||
status = send_heci_message(&msg, sizeof(msg),
|
||||
BIOS_HOST_ADD, HECI_MKHI_ADD);
|
||||
if (status != 0)
|
||||
heci_reset();
|
||||
|
||||
status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADD, HECI_MKHI_ADD);
|
||||
if (!status)
|
||||
return -1;
|
||||
|
||||
reply_size = sizeof(reply);
|
||||
memset(&reply, 0, reply_size);
|
||||
if (recv_heci_message(&reply, &reply_size) == -1)
|
||||
status = heci_receive(&reply, &reply_size);
|
||||
if (!status)
|
||||
return -1;
|
||||
/* get reply result from HECI MSG */
|
||||
if (reply.result != 0) {
|
||||
if (reply.result) {
|
||||
printk(BIOS_DEBUG, "%s: Exit with Failure\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue