summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/include/intelblocks/pcr.h41
-rw-r--r--src/soc/intel/common/block/pcr/pcr.c209
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