summaryrefslogtreecommitdiff
path: root/src/northbridge/intel/haswell/vcu_mailbox.c
diff options
context:
space:
mode:
authorAngel Pons <th3fanbus@gmail.com>2022-05-06 21:56:48 +0200
committerFelix Held <felix-coreboot@felixheld.de>2022-12-16 17:08:00 +0000
commit567ece44eafaee3e1a3fef644efd018a877b533b (patch)
tree0ae5eea3cb7b2d6e94f77a18dd5b43d24b8ef0b3 /src/northbridge/intel/haswell/vcu_mailbox.c
parentb739fd287dc70aa253de946541b91d12afce8da3 (diff)
haswell/lynxpoint: Add native DMI init
Implement native DMI init for Haswell and Lynx Point. This is only needed on non-ULT platforms, and only when MRC.bin is not used. TEST=Verify DMI initialises correctly on Asrock B85M Pro4. Change-Id: I5fb1a2adc4ffbf0ebbf0d2d3a444055c53765faa Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/64177 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/northbridge/intel/haswell/vcu_mailbox.c')
-rw-r--r--src/northbridge/intel/haswell/vcu_mailbox.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/northbridge/intel/haswell/vcu_mailbox.c b/src/northbridge/intel/haswell/vcu_mailbox.c
new file mode 100644
index 0000000000..196b720c82
--- /dev/null
+++ b/src/northbridge/intel/haswell/vcu_mailbox.c
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <assert.h>
+#include <console/console.h>
+#include <delay.h>
+#include <northbridge/intel/haswell/haswell.h>
+#include <northbridge/intel/haswell/vcu_mailbox.h>
+#include <types.h>
+
+/*
+ * This is a library for the VCU (Validation Control Unit) mailbox. This
+ * mailbox is primarily used to adjust some magic PCIe tuning parameters.
+ *
+ * There are two revisions of the VCU mailbox. Rev1 is specific to Haswell
+ * stepping A0, and all other steppings use Rev2. Haswell stepping A0 CPUs
+ * are early Engineering Samples with undocumented errata, and most likely
+ * need special microcode updates to boot. Thus, the code does not support
+ * VCU mailbox Rev1, because no one should need it anymore.
+ */
+
+#define VCU_MAILBOX_INTERFACE 0x6c00
+#define VCU_MAILBOX_DATA 0x6c04
+
+#define VCU_RUN_BUSY (1U << 31)
+
+enum vcu_opcode {
+ VCU_INVALID_OPCODE = 0x00,
+ VCU_OPCODE_READ_VCU_API_VER_ID = 0x01,
+ VCU_OPCODE_OPEN_SEQ = 0x02,
+ VCU_OPCODE_CLOSE_SEQ = 0x03,
+ VCU_OPCODE_READ_DATA = 0x07,
+ VCU_OPCODE_WRITE_DATA = 0x08,
+ VCU_OPCODE_READ_CSR = 0x13,
+ VCU_OPCODE_WRITE_CSR = 0x14,
+ VCU_OPCODE_READ_MMIO = 0x15,
+ VCU_OPCODE_WRITE_MMIO = 0x16,
+};
+
+enum vcu_sequence {
+ SEQ_ID_READ_CSR = 0x1,
+ SEQ_ID_WRITE_CSR = 0x2,
+ SEQ_ID_READ_MMIO = 0x3,
+ SEQ_ID_WRITE_MMIO = 0x4,
+};
+
+#define VCU_RESPONSE_MASK 0xffff
+#define VCU_RESPONSE_SUCCESS 0x40
+#define VCU_RESPONSE_BUSY 0x80
+#define VCU_RESPONSE_THREAD_UNAVAILABLE 0x82
+#define VCU_RESPONSE_ILLEGAL 0x90
+
+/* FIXME: Use timer API */
+static void send_vcu_command(const enum vcu_opcode opcode, const uint32_t data)
+{
+ if (opcode == VCU_INVALID_OPCODE)
+ return;
+
+ for (unsigned int i = 0; i < 10; i++) {
+ mchbar_write32(VCU_MAILBOX_DATA, data);
+ mchbar_write32(VCU_MAILBOX_INTERFACE, opcode | VCU_RUN_BUSY);
+ uint32_t vcu_interface;
+ for (unsigned int j = 0; j < 100; j++) {
+ vcu_interface = mchbar_read32(VCU_MAILBOX_INTERFACE);
+ if (!(vcu_interface & VCU_RUN_BUSY))
+ break;
+
+ udelay(10);
+ }
+ if (vcu_interface & VCU_RUN_BUSY)
+ continue;
+
+ if ((vcu_interface & VCU_RESPONSE_MASK) == VCU_RESPONSE_SUCCESS)
+ return;
+ }
+ printk(BIOS_ERR, "VCU: Failed to send command\n");
+}
+
+static enum vcu_opcode get_register_opcode(enum vcu_sequence seq)
+{
+ switch (seq) {
+ case SEQ_ID_READ_CSR:
+ return VCU_OPCODE_READ_CSR;
+ case SEQ_ID_WRITE_CSR:
+ return VCU_OPCODE_WRITE_CSR;
+ case SEQ_ID_READ_MMIO:
+ return VCU_OPCODE_READ_MMIO;
+ case SEQ_ID_WRITE_MMIO:
+ return VCU_OPCODE_WRITE_MMIO;
+ default:
+ BUG();
+ return VCU_INVALID_OPCODE;
+ }
+}
+
+static enum vcu_opcode get_data_opcode(enum vcu_sequence seq)
+{
+ switch (seq) {
+ case SEQ_ID_READ_CSR:
+ case SEQ_ID_READ_MMIO:
+ return VCU_OPCODE_READ_DATA;
+ case SEQ_ID_WRITE_CSR:
+ case SEQ_ID_WRITE_MMIO:
+ return VCU_OPCODE_WRITE_DATA;
+ default:
+ BUG();
+ return VCU_INVALID_OPCODE;
+ }
+}
+
+static uint32_t send_vcu_sequence(uint32_t addr, enum vcu_sequence seq, uint32_t wr_data)
+{
+ send_vcu_command(VCU_OPCODE_OPEN_SEQ, seq);
+
+ send_vcu_command(get_register_opcode(seq), addr);
+
+ send_vcu_command(get_data_opcode(seq), wr_data);
+
+ const uint32_t rd_data = mchbar_read32(VCU_MAILBOX_DATA);
+
+ send_vcu_command(VCU_OPCODE_CLOSE_SEQ, seq);
+
+ return rd_data;
+}
+
+#define VCU_WRITE_IGNORED 0
+
+uint32_t vcu_read_csr(uint32_t addr)
+{
+ return send_vcu_sequence(addr, SEQ_ID_READ_CSR, VCU_WRITE_IGNORED);
+}
+
+void vcu_write_csr(uint32_t addr, uint32_t data)
+{
+ send_vcu_sequence(addr, SEQ_ID_WRITE_CSR, data);
+}
+
+void vcu_update_csr(uint32_t addr, uint32_t andvalue, uint32_t orvalue)
+{
+ vcu_write_csr(addr, (vcu_read_csr(addr) & andvalue) | orvalue);
+}
+
+uint32_t vcu_read_mmio(uint32_t addr)
+{
+ return send_vcu_sequence(addr, SEQ_ID_READ_MMIO, VCU_WRITE_IGNORED);
+}
+
+void vcu_write_mmio(uint32_t addr, uint32_t data)
+{
+ send_vcu_sequence(addr, SEQ_ID_WRITE_MMIO, data);
+}
+
+void vcu_update_mmio(uint32_t addr, uint32_t andvalue, uint32_t orvalue)
+{
+ vcu_write_mmio(addr, (vcu_read_mmio(addr) & andvalue) | orvalue);
+}