Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/23809
Change subject: soc/intel/common/block/pcr: Function for executing PCH SBI message ......................................................................
soc/intel/common/block/pcr: Function for executing PCH SBI message
This function to perform 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 --- M src/soc/intel/common/block/include/intelblocks/pcr.h M src/soc/intel/common/block/pcr/pcr.c 2 files changed, 233 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/09/23809/1
diff --git a/src/soc/intel/common/block/include/intelblocks/pcr.h b/src/soc/intel/common/block/include/intelblocks/pcr.h index cfe0015..0127f17 100644 --- a/src/soc/intel/common/block/include/intelblocks/pcr.h +++ b/src/soc/intel/common/block/include/intelblocks/pcr.h @@ -38,6 +38,39 @@ void pcr_or16(uint8_t pid, uint16_t offset, uint16_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, +}; + +/* + * API to perform sideband 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 + */ +int pcr_execute_sideband_msg(uint8_t pid, uint32_t offset, uint8_t opcode, + bool is_posted, uint16_t fast_byte_enable, uint16_t bar, + uint16_t fid, uint32_t *data, uint8_t *response); + /* Get the starting address of the port's registers. */ void *pcr_reg_address(uint8_t pid, uint16_t offset); #endif /* if !defined(__ACPI__) */ diff --git a/src/soc/intel/common/block/pcr/pcr.c b/src/soc/intel/common/block/pcr/pcr.c index 4264cdf..28c93c2 100644 --- a/src/soc/intel/common/block/pcr/pcr.c +++ b/src/soc/intel/common/block/pcr/pcr.c @@ -15,13 +15,41 @@
#include <arch/io.h> #include <assert.h> +#include <console/console.h> #include <intelblocks/pcr.h> +#include <soc/pci_devs.h> #include <soc/pcr_ids.h>
#if !defined(CONFIG_PCR_BASE_ADDRESS) || (CONFIG_PCR_BASE_ADDRESS == 0) #error "PCR_BASE_ADDRESS need to be non-zero!" #endif
+/* 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 +/* Bit 7 */ +#define P2SB_CR_SBI_POSTED 7 +/* Bit 2-1 */ +#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 +/* Bit 10-8 */ +#define P2SB_CR_SBI_BAR 8 +/* Bit 7-0 */ +#define P2SB_CR_SBI_FID 0 +#define P2SB_CR_SBI_EXT_ADDR 0xdc + static void *__pcr_reg_address(uint8_t pid, uint16_t offset) { uintptr_t reg_addr; @@ -178,3 +206,175 @@ data8 |= ordata; pcr_write8(pid, offset, data8); } + +static int pcr_check_for_timeout(device_t dev) +{ + uint32_t timeout; + + timeout = 0xFFFFFFF; + while (timeout > 0) { + if ((pci_read_config16 (dev, P2SB_CR_SBI_STATUS) & + P2SB_CR_SBI_STATUS_BUSY) == 0) + break; + timeout--; + } + + /* Timed out */ + if (timeout == 0) + return -1; + + return 0; +} + +/* + * API to perform sideband 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 + */ +int pcr_execute_sideband_msg(uint8_t pid, uint32_t offset, uint8_t opcode, + bool is_posted, uint16_t fast_byte_enable, uint16_t bar, + uint16_t fid, uint32_t *data, uint8_t *response) +{ + device_t dev = PCH_DEV_P2SB; + uint32_t sbi_data; + uint16_t sbi_status; + + switch(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_DEBUG, "SBI Failure: Wrong Input!\n"); + return -1; + break; + } + + if (pci_read_config16(dev, PCI_VENDOR_ID) == 0xffff) { + printk(BIOS_DEBUG, "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 opeartion is completed. + */ + if (pcr_check_for_timeout(dev)) { + printk(BIOS_DEBUG, "SBI Failure: Time Out!\n"); + return -1; + } + + /* Initial Response status */ + *response = 0xFF; + sbi_status = 0; + + /* + * 2. Write P2SB PCI offset D0h[31:0] with Address + * and Destination Port ID + */ + pci_write_config32 (dev, P2SB_CR_SBI_ADDR, + (uint32_t) ((pid << P2SB_CR_SBI_DESTID) | (uint16_t) offset)); + + /* + * 3. Write P2SB PCI offset DCh[31:0] with extended address, + * which is expected to be 0 in CNL PCH + */ + pci_write_config32 (dev, P2SB_CR_SBI_EXT_ADDR, + (uint32_t) (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 &= ~(0xFF00 | (1 << P2SB_CR_SBI_POSTED)); + sbi_status |= ((opcode << P2SB_CR_SBI_OPCODE) | + (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 + */ + pci_write_config16 (dev, P2SB_CR_SBI_ROUTE_IDEN, (uint16_t) ( + ((fast_byte_enable & 0x000F) << P2SB_CR_SBI_FBE) | + ((bar & 0x0007) << P2SB_CR_SBI_BAR) | + (fid & 0x00FF))); + + switch(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 */ + sbi_data = 0; + pci_write_config32 (dev, P2SB_CR_SBI_DATA, sbi_data); + 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_check_for_timeout(dev)) { + printk(BIOS_DEBUG, "SBI Failure: Time Out!\n"); + return -1; + } + + /* + * 8. Check if P2SB PCI offset D8h[2:1] = 00b for + * successful transaction + */ + *response = (uint8_t) ((sbi_status & 0x0006) >> 1); + if (*response == P2SB_CR_SBI_STATUS_SUCCESS) { + switch(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_DEBUG, "SBI Failure: Transaction Failure!\n"); + return -1; + } +}