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:
Subrata Banik 2017-11-09 15:07:44 +05:30 committed by Aaron Durbin
parent 4a722f5e2f
commit bffff54e09
4 changed files with 19 additions and 395 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}