summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--driver/build.mk3
-rw-r--r--driver/sb_rmi.c187
-rw-r--r--driver/sb_rmi.h58
-rw-r--r--include/config.h3
-rw-r--r--zephyr/Kconfig8
-rw-r--r--zephyr/shim/include/config_chip.h5
6 files changed, 264 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk
index 0c7a183a1f..0bc42fca47 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -220,3 +220,6 @@ driver-$(CONFIG_MP4245)+=mp4245.o
# Power Management ICs
driver-$(CONFIG_MP2964)+=mp2964.o
+
+# SOC Interface
+driver-$(CONFIG_AMD_SB_RMI)+=sb_rmi.o
diff --git a/driver/sb_rmi.c b/driver/sb_rmi.c
new file mode 100644
index 0000000000..448e149456
--- /dev/null
+++ b/driver/sb_rmi.c
@@ -0,0 +1,187 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* AMD SB-RMI (Side-band Remote Management Interface) Driver */
+
+#include "common.h"
+#include "i2c.h"
+#include "sb_rmi.h"
+#include "stdbool.h"
+#include "time.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_SYSTEM, outstr)
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+
+#define SB_RMI_MAILBOX_TIMEOUT_MS 10
+#define SB_RMI_MAILBOX_RETRY_DELAY_US 200
+
+/**
+ * Write an SB-RMI register
+ */
+static int sb_rmi_write(const int reg, int data)
+{
+ return i2c_write8(I2C_PORT_THERMAL_AP, SB_RMI_I2C_ADDR_FLAGS0, reg,
+ data);
+}
+
+/**
+ * Read an SB-RMI register
+ */
+static int sb_rmi_read(const int reg, int *data)
+{
+ return i2c_read8(I2C_PORT_THERMAL_AP, SB_RMI_I2C_ADDR_FLAGS0, reg,
+ data);
+}
+
+/**
+ * Set SB-RMI software interrupt
+ */
+static int sb_rmi_assert_interrupt(bool assert)
+{
+ return sb_rmi_write(SB_RMI_SW_INTR_REG, assert ? 0x1 : 0x0);
+}
+
+
+/**
+ * Execute a SB-RMI mailbox transaction
+ *
+ * cmd:
+ * See "SB-RMI Soft Mailbox Message" table in PPR for command id
+ * msg_in:
+ * Message In buffer
+ * msg_out:
+ * Message Out buffer
+ */
+int sb_rmi_mailbox_xfer(int cmd, uint32_t msg_in, uint32_t *msg_out_ptr)
+{
+ /**
+ * The sequence is as follows:
+ * 1. The initiator (BMC) indicates that command is to be serviced by
+ * firmware by writing 0x80 to SBRMI::InBndMsg_inst7 (SBRMI_x3F). This
+ * register must be set to 0x80 after reset.
+ * 2. The initiator (BMC) writes the command to SBRMI::InBndMsg_inst0
+ * (SBRMI_x38).
+ * 3. For write operations or read operations which require additional
+ * addressing information as shown in the table above, the initiator
+ * (BMC) writes Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
+ * {SBRMI_x3C(MSB):SBRMI_x39(LSB)}.
+ * 4. The initiator (BMC) writes 0x01 to SBRMI::SoftwareInterrupt to
+ * notify firmware to perform the requested read or write command.
+ * 5. Firmware reads the message and performs the defined action.
+ * 6. Firmware writes the original command to outbound message register
+ * SBRMI::OutBndMsg_inst0 (SBRMI_x30).
+ * 7. Firmware will write SBRMI::Status[SwAlertSts]=1 to generate an
+ * ALERT (if enabled) to initiator (BMC) to indicate completion of the
+ * requested command. Firmware must (if applicable) put the message
+ * data into the message registers SBRMI::OutBndMsg_inst[4:1]
+ * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
+ * 8. For a read operation, the initiator (BMC) reads the firmware
+ * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
+ * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
+ * 9. Firmware clears the interrupt on SBRMI::SoftwareInterrupt.
+ * 10. BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
+ * ALERT to initiator (BMC). It is recommended to clear the ALERT
+ * upon completion of the current mailbox command.
+ */
+ int val;
+ bool alerted;
+ timestamp_t start;
+ /**
+ * Step 1: writing 0x80 to SBRMI::InBndMsg_inst7 (SBRMI_x3F) to
+ * indicate that command is to be serviced and to make sure
+ * SBRMIx40[Software Interrupt] is cleared
+ */
+ RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG7_REG, 0x80));
+ RETURN_ERROR(sb_rmi_assert_interrupt(0));
+
+ /* Step 2: writes the command to SBRMI::InBndMsg_inst0 (SBRMI_x38) */
+ RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG0_REG, cmd));
+ /* Step 3: msgIn to {SBRMI_x3C(MSB):SBRMI_x39(LSB)} */
+ RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG1_REG, msg_in & 0xFF));
+ RETURN_ERROR(
+ sb_rmi_write(SB_RMI_IN_BND_MSG2_REG, (msg_in >> 8) & 0xFF));
+ RETURN_ERROR(
+ sb_rmi_write(SB_RMI_IN_BND_MSG3_REG, (msg_in >> 16) & 0xFF));
+ RETURN_ERROR(
+ sb_rmi_write(SB_RMI_IN_BND_MSG4_REG, (msg_in >> 24) & 0xFF));
+
+ /**
+ * Step 4: writes 0x01 to SBRMIx40[Software Interrupt] to notify
+ * firmware to start service.
+ */
+ RETURN_ERROR(sb_rmi_assert_interrupt(1));
+
+ /**
+ * Step 5: SoC do the service
+ * Step 6: The original command will be copied to SBRMI::OutBndMsg_inst0
+ * (SBRMI_x30)
+ * Step 7: wait SBRMIx02[SwAlertSts] to 1 which indicate the completion
+ * of a mailbox operation
+ */
+ alerted = false;
+ start = get_time();
+ do {
+ if (sb_rmi_read(SB_RMI_STATUS_REG, &val))
+ break;
+ if (val & 0x02) {
+ alerted = true;
+ break;
+ }
+ msleep(1);
+ } while (time_since32(start) < SB_RMI_MAILBOX_TIMEOUT_MS * MSEC);
+
+ if (!alerted) {
+ CPRINTS("SB-SMI: Mailbox transfer timeout");
+ /* Clear interrupt */
+ sb_rmi_assert_interrupt(0);
+ return EC_ERROR_TIMEOUT;
+ }
+
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG0_REG, &val));
+ if (val != cmd) {
+ CPRINTS("RMI: Unexpected command value in out bound message");
+ sb_rmi_assert_interrupt(0);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ /* Step 8: read msgOut from {SBRMI_x34(MSB):SBRMI_x31(LSB)} */
+ *msg_out_ptr = 0;
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG1_REG, &val));
+ *msg_out_ptr |= val;
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG2_REG, &val));
+ *msg_out_ptr |= val << 8;
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG3_REG, &val));
+ *msg_out_ptr |= val << 16;
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG4_REG, &val));
+ *msg_out_ptr |= val << 24;
+
+ /* Step 9: clear SBRMIx40[Software Interrupt] */
+ RETURN_ERROR(sb_rmi_assert_interrupt(0));
+
+ /**
+ * Step 10: BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear
+ * the ALERT to initiator (BMC). It is recommended to clear the
+ * ALERT upon completion of the current mailbox command.
+ */
+ RETURN_ERROR(sb_rmi_write(SB_RMI_STATUS_REG, 0x2));
+
+ /* Step 11: read the return code from OutBndMsg_inst7 (SBRMI_x37) */
+ RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG7_REG, &val));
+
+ switch (val) {
+ case SB_RMI_MAILBOX_SUCCESS:
+ return EC_SUCCESS;
+ case SB_RMI_MAILBOX_ERROR_ABORTED:
+ return EC_ERROR_UNKNOWN;
+ case SB_RMI_MAILBOX_ERROR_UNKNOWN_CMD:
+ return EC_ERROR_INVAL;
+ case SB_RMI_MAILBOX_ERROR_INVALID_CORE:
+ return EC_ERROR_PARAM1;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+}
diff --git a/driver/sb_rmi.h b/driver/sb_rmi.h
new file mode 100644
index 0000000000..132af0e70a
--- /dev/null
+++ b/driver/sb_rmi.h
@@ -0,0 +1,58 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* AMD SB-RMI (Side-band Remote Management Interface) Driver */
+
+#ifndef __CROS_EC_SB_RMI_H
+#define __CROS_EC_SB_RMI_H
+
+#include "common.h"
+
+#define SB_RMI_OUT_BND_MSG0_REG 0x30
+#define SB_RMI_OUT_BND_MSG1_REG 0x31
+#define SB_RMI_OUT_BND_MSG2_REG 0x32
+#define SB_RMI_OUT_BND_MSG3_REG 0x33
+#define SB_RMI_OUT_BND_MSG4_REG 0x34
+#define SB_RMI_OUT_BND_MSG5_REG 0x35
+#define SB_RMI_OUT_BND_MSG6_REG 0x36
+#define SB_RMI_OUT_BND_MSG7_REG 0x37
+
+#define SB_RMI_IN_BND_MSG0_REG 0x38
+#define SB_RMI_IN_BND_MSG1_REG 0x39
+#define SB_RMI_IN_BND_MSG2_REG 0x3a
+#define SB_RMI_IN_BND_MSG3_REG 0x3b
+#define SB_RMI_IN_BND_MSG4_REG 0x3c
+#define SB_RMI_IN_BND_MSG5_REG 0x3d
+#define SB_RMI_IN_BND_MSG6_REG 0x3e
+#define SB_RMI_IN_BND_MSG7_REG 0x3f
+
+#define SB_RMI_SW_INTR_REG 0x40
+#define SB_RMI_STATUS_REG 0x02
+
+#define SB_RMI_WRITE_STT_SENSOR_CMD 0x3A
+
+#define SB_RMI_MAILBOX_SUCCESS 0x0
+#define SB_RMI_MAILBOX_ERROR_ABORTED 0x1
+#define SB_RMI_MAILBOX_ERROR_UNKNOWN_CMD 0x2
+#define SB_RMI_MAILBOX_ERROR_INVALID_CORE 0x3
+
+/* Socket ID 0 */
+#define SB_RMI_I2C_ADDR_FLAGS0 0x3c
+/* Socket ID 1 */
+#define SB_RMI_I2C_ADDR_FLAGS1 0x30
+
+/**
+ * Execute a SB-RMI mailbox transaction
+ *
+ * cmd:
+ * See "SB-RMI Soft Mailbox Message" table in PPR for command id
+ * msg_in:
+ * Message In buffer
+ * msg_out:
+ * Message Out buffer
+ */
+int sb_rmi_mailbox_xfer(int cmd, uint32_t msg_in, uint32_t *msg_out_ptr);
+
+#endif /* __CROS_EC_SB_RMI_H */
diff --git a/include/config.h b/include/config.h
index 43df9737fd..a6bd31276d 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1296,6 +1296,9 @@
/* Redefine when we need a different power-on sequence on the same chipset. */
#define CONFIG_CHIPSET_POWER_SEQ_VERSION 0
+/* AMD Side-Band Remote Management Interface (SB-RMI) support */
+#undef CONFIG_AMD_SB_RMI
+
/*****************************************************************************/
/*
* Chip config for clock circuitry
diff --git a/zephyr/Kconfig b/zephyr/Kconfig
index 05b9d5d055..b11031b8b4 100644
--- a/zephyr/Kconfig
+++ b/zephyr/Kconfig
@@ -794,4 +794,12 @@ config PLATFORM_EC_HOST_COMMAND_STATUS
command finishes processing, and the AP may then inquire the status
of the current command and/or the result of the previous command.
+config PLATFORM_EC_AMD_SB_RMI
+ bool "Enable driver for AMD SB-RMI interface"
+ help
+ AMD platforms provide the Side-Band Remote Management Interface.
+ SB-RMI provides an interface for an external SMBus master to perform
+ tasks such as managing power consumption and power limits of the CPU
+ socket.
+
endif # PLATFORM_EC
diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h
index 639f71b266..d8bb7c27ac 100644
--- a/zephyr/shim/include/config_chip.h
+++ b/zephyr/shim/include/config_chip.h
@@ -1755,4 +1755,9 @@
#define CONFIG_HOSTCMD_DEBUG_MODE 3
#endif
+#undef CONFIG_AMD_SB_RMI
+#ifdef CONFIG_PLATFORM_EC_AMD_SB_RMI
+#define CONFIG_AMD_SB_RMI
+#endif
+
#endif /* __CROS_EC_CONFIG_CHIP_H */