soc/intel/common/block/pcr: Add function for executing PCH SBI message

This function performs SBI communication

Input:
 * PID: Port ID of the SBI message
 * Offset: Register offset of the SBI message
 * Opcode: Opcode
 * Posted: Posted message
 * Fast_Byte_Enable: First Byte Enable
 * BAR: base address
 * FID: Function ID
 * Data: Read/Write Data
 * Response: Response

Output:
 * 0: SBI message is successfully completed
 * -1: SBI message failure

Change-Id: I4e49311564e20cedbfabaaceaf5f72c480e5ea26
Signed-off-by: Subrata Banik <subrata.banik@intel.com>
Reviewed-on: https://review.coreboot.org/23809
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Subrata Banik 2018-02-19 13:43:56 +05:30 committed by Patrick Georgi
parent 5f1da55b49
commit 736a03fd24
2 changed files with 250 additions and 0 deletions

View File

@ -38,6 +38,47 @@ void pcr_or32(uint8_t pid, uint16_t offset, uint32_t ordata);
void pcr_or16(uint8_t pid, uint16_t offset, uint16_t ordata); void pcr_or16(uint8_t pid, uint16_t offset, uint16_t ordata);
void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata); void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata);
/* SBI command */
enum {
MEM_READ = 0,
MEM_WRITE = 1,
PCI_CONFIG_READ = 4,
PCI_CONFIG_WRITE = 5,
PCR_READ = 6,
PCR_WRITE = 7,
GPIO_LOCK_UNLOCK = 13,
};
struct pcr_sbi_msg {
uint8_t pid; /* 0x00 - Port ID of the SBI message */
uint32_t offset; /* 0x01 - Register offset of the SBI message */
uint8_t opcode; /* 0x05 - Opcode */
bool is_posted; /* 0x06 - Posted message */
uint16_t fast_byte_enable; /* 0x07 - First Byte Enable */
uint16_t bar; /* 0x09 - base address */
uint16_t fid; /* 0x0B - Function ID */
};
/*
* API to perform sideband communication
*
* Input:
* struct pcr_sbi_msg
* data - read/write for sbi message
* response -
* 0 - successful
* 1 - unsuccessful
* 2 - powered down
* 3 - multi-cast mixed
*
* Output:
* 0: SBI message is successfully completed
* -1: SBI message failure
*/
int pcr_execute_sideband_msg(struct pcr_sbi_msg *msg, uint32_t *data,
uint8_t *response);
/* Get the starting address of the port's registers. */ /* Get the starting address of the port's registers. */
void *pcr_reg_address(uint8_t pid, uint16_t offset); void *pcr_reg_address(uint8_t pid, uint16_t offset);
#endif /* if !defined(__ACPI__) */ #endif /* if !defined(__ACPI__) */

View File

@ -15,13 +15,53 @@
#include <arch/io.h> #include <arch/io.h>
#include <assert.h> #include <assert.h>
#include <console/console.h>
#include <intelblocks/pcr.h> #include <intelblocks/pcr.h>
#include <soc/pci_devs.h>
#include <soc/pcr_ids.h> #include <soc/pcr_ids.h>
#include <timer.h>
#if !defined(CONFIG_PCR_BASE_ADDRESS) || (CONFIG_PCR_BASE_ADDRESS == 0) #if !defined(CONFIG_PCR_BASE_ADDRESS) || (CONFIG_PCR_BASE_ADDRESS == 0)
#error "PCR_BASE_ADDRESS need to be non-zero!" #error "PCR_BASE_ADDRESS need to be non-zero!"
#endif #endif
#if !IS_ENABLED(CONFIG_PCR_COMMON_IOSF_1_0)
#define PCR_SBI_CMD_TIMEOUT 10 /* 10ms */
/* P2SB PCI configuration register */
#define P2SB_CR_SBI_ADDR 0xd0
#define P2SB_CR_SBI_DESTID 24
#define P2SB_CR_SBI_DATA 0xd4
#define P2SB_CR_SBI_STATUS 0xd8
/* Bit 15:8 */
#define P2SB_CR_SBI_OPCODE 8
#define P2SB_CR_SBI_OPCODE_MASK 0xFF00
/* Bit 7 */
#define P2SB_CR_SBI_POSTED 7
#define P2SB_CR_SBI_POSTED_MASK 0x0080
/* Bit 2-1 */
#define P2SB_CR_SBI_STATUS_MASK 0x0006
#define P2SB_CR_SBI_STATUS_SUCCESS 0
#define P2SB_CR_SBI_STATUS_NOT_SUPPORTED 1
#define P2SB_CR_SBI_STATUS_POWERED_DOWN 2
#define P2SB_CR_SBI_STATUS_MULTI_CAST_MIXED 3
/* Bit 0 */
#define P2SB_CR_SBI_STATUS_READY 0
#define P2SB_CR_SBI_STATUS_BUSY 1
#define P2SB_CR_SBI_ROUTE_IDEN 0xda
/* Bit 15-12 */
#define P2SB_CR_SBI_FBE 12
#define P2SB_CR_SBI_FBE_MASK 0xF
/* Bit 10-8 */
#define P2SB_CR_SBI_BAR 8
#define P2SB_CR_SBI_MASK 0x7
/* Bit 7-0 */
#define P2SB_CR_SBI_FID 0
#define P2SB_CR_SBI_FID_MASK 0xFF
#define P2SB_CR_SBI_EXT_ADDR 0xdc
#endif
static void *__pcr_reg_address(uint8_t pid, uint16_t offset) static void *__pcr_reg_address(uint8_t pid, uint16_t offset)
{ {
uintptr_t reg_addr; uintptr_t reg_addr;
@ -178,3 +218,172 @@ void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata)
data8 |= ordata; data8 |= ordata;
pcr_write8(pid, offset, data8); pcr_write8(pid, offset, data8);
} }
#if !IS_ENABLED(CONFIG_PCR_COMMON_IOSF_1_0)
static int pcr_wait_for_completion(device_t dev)
{
struct stopwatch sw;
stopwatch_init_msecs_expire(&sw, PCR_SBI_CMD_TIMEOUT);
do {
if ((pci_read_config16(dev, P2SB_CR_SBI_STATUS) &
P2SB_CR_SBI_STATUS_BUSY) == 0)
return 0;
} while (!stopwatch_expired(&sw));
return -1;
}
/*
* API to perform sideband communication
*
* Input:
* struct pcr_sbi_msg
* data - read/write for sbi message
* response -
* 0 - successful
* 1 - unsuccessful
* 2 - powered down
* 3 - multi-cast mixed
*
* Output:
* 0: SBI message is successfully completed
* -1: SBI message failure
*/
int pcr_execute_sideband_msg(struct pcr_sbi_msg *msg, uint32_t *data,
uint8_t *response)
{
device_t dev = PCH_DEV_P2SB;
uint32_t sbi_data;
uint16_t sbi_status;
uint16_t sbi_rid;
assert(msg && data && response);
switch (msg->opcode) {
case MEM_READ:
case MEM_WRITE:
case PCI_CONFIG_READ:
case PCI_CONFIG_WRITE:
case PCR_READ:
case PCR_WRITE:
case GPIO_LOCK_UNLOCK:
break;
default:
printk(BIOS_ERR, "SBI Failure: Wrong Input!\n");
return -1;
break;
}
if (pci_read_config16(dev, PCI_VENDOR_ID) == 0xffff) {
printk(BIOS_ERR, "SBI Failure: P2SB device Hidden!\n");
return -1;
}
/*
* BWG Section 2.2.1
* 1. Poll P2SB PCI offset D8h[0] = 0b
* Make sure the previous operation is completed.
*/
if (pcr_wait_for_completion(dev)) {
printk(BIOS_ERR, "SBI Failure: Time Out!\n");
return -1;
}
/* Initial Response status */
*response = P2SB_CR_SBI_STATUS_NOT_SUPPORTED;
/*
* 2. Write P2SB PCI offset D0h[31:0] with Address
* and Destination Port ID
*/
pci_write_config32(dev, P2SB_CR_SBI_ADDR,
(msg->pid << P2SB_CR_SBI_DESTID) | msg->offset);
/*
* 3. Write P2SB PCI offset DCh[31:0] with extended address,
* which is expected to be 0
*/
pci_write_config32(dev, P2SB_CR_SBI_EXT_ADDR, msg->offset >> 16);
/*
* 4. Set P2SB PCI offset D8h[15:8] = 00000110b for read
* Set P2SB PCI offset D8h[15:8] = 00000111b for write
*
* Set SBISTAT[15:8] to the opcode passed in
* Set SBISTAT[7] to the posted passed in
*/
sbi_status = pci_read_config16(dev, P2SB_CR_SBI_STATUS);
sbi_status &= ~(P2SB_CR_SBI_OPCODE_MASK | P2SB_CR_SBI_POSTED_MASK);
sbi_status |= (msg->opcode << P2SB_CR_SBI_OPCODE) |
(msg->is_posted << P2SB_CR_SBI_POSTED);
pci_write_config16(dev, P2SB_CR_SBI_STATUS, sbi_status);
/*
* 5. Write P2SB PCI offset DAh[15:0] = F000h
*
* Set RID[15:0] = Fbe << 12 | Bar << 8 | Fid
*/
sbi_rid = ((msg->fast_byte_enable & P2SB_CR_SBI_FBE_MASK)
<< P2SB_CR_SBI_FBE) |
((msg->bar & P2SB_CR_SBI_MASK) << P2SB_CR_SBI_BAR) |
(msg->fid & P2SB_CR_SBI_FID_MASK);
pci_write_config16(dev, P2SB_CR_SBI_ROUTE_IDEN, sbi_rid);
switch (msg->opcode) {
case MEM_WRITE:
case PCI_CONFIG_WRITE:
case PCR_WRITE:
/*
* 6. Write P2SB PCI offset D4h[31:0] with the
* intended data accordingly
*/
sbi_data = *data;
pci_write_config32(dev, P2SB_CR_SBI_DATA, sbi_data);
break;
default:
/* 6. Write P2SB PCI offset D4h[31:0] with dummy data */
pci_write_config32(dev, P2SB_CR_SBI_DATA, 0);
break;
}
/*
* 7. Set P2SB PCI offset D8h[0] = 1b, Poll P2SB PCI offset D8h[0] = 0b
*
* Set SBISTAT[0] = 1b, trigger the SBI operation
*/
sbi_status = pci_read_config16(dev, P2SB_CR_SBI_STATUS);
sbi_status |= P2SB_CR_SBI_STATUS_BUSY;
pci_write_config16(dev, P2SB_CR_SBI_STATUS, sbi_status);
/* Poll SBISTAT[0] = 0b, Polling for Busy bit */
if (pcr_wait_for_completion(dev)) {
printk(BIOS_ERR, "SBI Failure: Time Out!\n");
return -1;
}
/*
* 8. Check if P2SB PCI offset D8h[2:1] = 00b for
* successful transaction
*/
*response = (sbi_status & P2SB_CR_SBI_STATUS_MASK) >> 1;
if (*response == P2SB_CR_SBI_STATUS_SUCCESS) {
switch (msg->opcode) {
case MEM_READ:
case PCI_CONFIG_READ:
case PCR_READ:
sbi_data = pci_read_config32(dev, P2SB_CR_SBI_DATA);
*data = sbi_data;
break;
default:
break;
}
return 0;
} else {
printk(BIOS_ERR, "SBI Failure: Transaction Status = %x\n",
*response);
return -1;
}
}
#endif