summaryrefslogtreecommitdiff
path: root/lib/intel_iosf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/intel_iosf.c')
-rw-r--r--lib/intel_iosf.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/lib/intel_iosf.c b/lib/intel_iosf.c
new file mode 100644
index 00000000..ca206389
--- /dev/null
+++ b/lib/intel_iosf.c
@@ -0,0 +1,175 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include "intel_io.h"
+#include "intel_reg.h"
+
+#define TIMEOUT_US 500000
+
+/* Standard MMIO read, non-posted */
+#define SB_MRD_NP 0x00
+/* Standard MMIO write, non-posted */
+#define SB_MWR_NP 0x01
+/* Private register read, double-word addressing, non-posted */
+#define SB_CRRDDA_NP 0x06
+/* Private register write, double-word addressing, non-posted */
+#define SB_CRWRDA_NP 0x07
+
+static int vlv_sideband_rw(uint32_t port, uint8_t opcode, uint32_t addr,
+ uint32_t *val)
+{
+ int timeout = 0;
+ uint32_t cmd, devfn, be, bar;
+ int is_read = (opcode == SB_CRRDDA_NP || opcode == SB_MRD_NP);
+
+ bar = 0;
+ be = 0xf;
+ devfn = 16;
+
+ cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
+ (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
+ (bar << IOSF_BAR_SHIFT);
+
+ if (intel_register_read(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) {
+ fprintf(stderr, "warning: pcode (%s) mailbox access failed\n",
+ is_read ? "read" : "write");
+ return -EAGAIN;
+ }
+
+ intel_register_write(VLV_IOSF_ADDR, addr);
+ if (!is_read)
+ intel_register_write(VLV_IOSF_DATA, *val);
+
+ intel_register_write(VLV_IOSF_DOORBELL_REQ, cmd);
+
+ do {
+ usleep(1);
+ timeout++;
+ } while (intel_register_read(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY &&
+ timeout < TIMEOUT_US);
+
+ if (timeout >= TIMEOUT_US) {
+ fprintf(stderr, "timeout waiting for pcode %s (%d) to finish\n",
+ is_read ? "read" : "write", addr);
+ return -ETIMEDOUT;
+ }
+
+ if (is_read)
+ *val = intel_register_read(VLV_IOSF_DATA);
+ intel_register_write(VLV_IOSF_DATA, 0);
+
+ return 0;
+}
+
+/**
+ * intel_punit_read:
+ * @addr: register offset
+ * @val: pointer to starge for the read result
+ *
+ * 32-bit read of the register at @offset through the P-Unit sideband port.
+ *
+ * Returns:
+ * 0 when the register access succeeded, negative errno code on failure.
+ */
+int intel_punit_read(uint8_t addr, uint32_t *val)
+{
+ return vlv_sideband_rw(IOSF_PORT_PUNIT, SB_CRRDDA_NP, addr, val);
+}
+
+/**
+ * intel_punit_write:
+ * @addr: register offset
+ * @val: value to write
+ *
+ * 32-bit write of the register at @offset through the P-Unit sideband port.
+ *
+ * Returns:
+ * 0 when the register access succeeded, negative errno code on failure.
+ */
+int intel_punit_write(uint8_t addr, uint32_t val)
+{
+ return vlv_sideband_rw(IOSF_PORT_PUNIT, SB_CRWRDA_NP, addr, &val);
+}
+
+/**
+ * intel_nc_read:
+ * @addr: register offset
+ * @val: pointer to starge for the read result
+ *
+ * 32-bit read of the register at @offset through the NC sideband port.
+ *
+ * Returns:
+ * 0 when the register access succeeded, negative errno code on failure.
+ */
+int intel_nc_read(uint8_t addr, uint32_t *val)
+{
+ return vlv_sideband_rw(IOSF_PORT_NC, SB_CRRDDA_NP, addr, val);
+}
+
+/**
+ * intel_nc_write:
+ * @addr: register offset
+ * @val: value to write
+ *
+ * 32-bit write of the register at @offset through the NC sideband port.
+ *
+ * Returns:
+ * 0 when the register access succeeded, negative errno code on failure.
+ */
+int intel_nc_write(uint8_t addr, uint32_t val)
+{
+ return vlv_sideband_rw(IOSF_PORT_NC, SB_CRWRDA_NP, addr, &val);
+}
+
+/**
+ * intel_dpio_reg_read:
+ * @reg: register offset
+ * @phy: DPIO PHY to use
+ *
+ * 32-bit read of the register at @offset through the DPIO sideband port.
+ *
+ * Returns:
+ * The value read from the register.
+ */
+uint32_t intel_dpio_reg_read(uint32_t reg, int phy)
+{
+ uint32_t val;
+
+ if (phy == 0)
+ vlv_sideband_rw(IOSF_PORT_DPIO, SB_MRD_NP, reg, &val);
+ else
+ vlv_sideband_rw(IOSF_PORT_DPIO_2, SB_MRD_NP, reg, &val);
+ return val;
+}
+
+/**
+ * intel_dpio_reg_write:
+ * @reg: register offset
+ * @val: value to write
+ * @phy: dpio PHY to use
+ *
+ * 32-bit write of the register at @offset through the DPIO sideband port.
+ */
+void intel_dpio_reg_write(uint32_t reg, uint32_t val, int phy)
+{
+ if (phy == 0)
+ vlv_sideband_rw(IOSF_PORT_DPIO, SB_MWR_NP, reg, &val);
+ else
+ vlv_sideband_rw(IOSF_PORT_DPIO_2, SB_MWR_NP, reg, &val);
+}
+
+uint32_t intel_flisdsi_reg_read(uint32_t reg)
+{
+ uint32_t val = 0;
+
+ vlv_sideband_rw(IOSF_PORT_FLISDSI, SB_CRRDDA_NP, reg, &val);
+
+ return val;
+}
+
+void intel_flisdsi_reg_write(uint32_t reg, uint32_t val)
+{
+ vlv_sideband_rw(IOSF_PORT_FLISDSI, SB_CRWRDA_NP, reg, &val);
+}