diff options
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/pcr.h | 41 | ||||
-rw-r--r-- | src/soc/intel/common/block/pcr/pcr.c | 209 |
2 files changed, 250 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/include/intelblocks/pcr.h b/src/soc/intel/common/block/include/intelblocks/pcr.h index cfe0015f70..c3af2fddc3 100644 --- a/src/soc/intel/common/block/include/intelblocks/pcr.h +++ b/src/soc/intel/common/block/include/intelblocks/pcr.h @@ -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_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. */ 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 e106c4193f..cf487c5589 100644 --- a/src/soc/intel/common/block/pcr/pcr.c +++ b/src/soc/intel/common/block/pcr/pcr.c @@ -15,13 +15,53 @@ #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> +#include <timer.h> #if !defined(CONFIG_PCR_BASE_ADDRESS) || (CONFIG_PCR_BASE_ADDRESS == 0) #error "PCR_BASE_ADDRESS need to be non-zero!" #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) { uintptr_t reg_addr; @@ -178,3 +218,172 @@ void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata) data8 |= ordata; 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 |