---
hw/arm/aspeed.c | 1 +
hw/misc/intel_me.c | 176 ++++++++++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 3 +-
3 files changed, 179 insertions(+), 1 deletion(-)
create mode 100644 hw/misc/intel_me.c
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 2b9c1600c6..88e9a47dc2 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1447,6 +1447,7 @@ static void oby35_cl_i2c_init(AspeedMachineState *bmc)
i2c_slave_create_simple(i2c[1], "tmp105", 0x4a);
i2c_slave_create_simple(i2c[1], "adm1272", 0x40);
i2c_slave_create_simple(i2c[1], "tmp421", 0x4c);
+ i2c_slave_create_simple(i2c[2], "intel-me", 0x16);
i2c_slave_create_simple(i2c[4], "isl69259", 0x76);
i2c_slave_create_simple(i2c[4], "isl69259", 0x62);
i2c_slave_create_simple(i2c[4], "isl69259", 0x60);
diff --git a/hw/misc/intel_me.c b/hw/misc/intel_me.c
new file mode 100644
index 0000000000..fdc9180c26
--- /dev/null
+++ b/hw/misc/intel_me.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "hw/i2c/i2c.h"
+
+#define TYPE_INTEL_ME "intel-me"
+OBJECT_DECLARE_SIMPLE_TYPE(IntelMEState, INTEL_ME);
+
+#define printf(...)
+
+struct IntelMEState {
+ I2CSlave parent_obj;
+
+ I2CBus *bus;
+ QEMUBH *bh;
+ int rx_len;
+ int tx_len;
+ int tx_pos;
+ uint8_t rx_buf[512];
+ uint8_t tx_buf[512];
+};
+
+static void intel_me_bh(void *opaque)
+{
+ IntelMEState *s = opaque;
+
+ assert(s->bus->bh == s->bh);
+
+ if (s->tx_pos == 0) {
+ if (i2c_start_send_async(s->bus, s->tx_buf[s->tx_pos++]) != 0) {
+ goto done;
+ }
+ return;
+ }
+
+ if (s->tx_pos < s->tx_len) {
+ if (i2c_send_async(s->bus, s->tx_buf[s->tx_pos++]) != 0) {
+ goto done;
+ }
+ return;
+ }
+
+done:
+ i2c_end_transfer(s->bus);
+ i2c_bus_release(s->bus);
+ s->tx_len = 0;
+ s->tx_pos = 0;
+ memset(s->tx_buf, 0, sizeof(s->tx_buf));
+}
+
+static void intel_me_realize(DeviceState *dev, Error **errp)
+{
+ IntelMEState *s = INTEL_ME(dev);
+
+ s->bus = I2C_BUS(qdev_get_parent_bus(dev));
+ s->bh = qemu_bh_new(intel_me_bh, s);
+ s->rx_len = 0;
+ s->tx_len = 0;
+ s->tx_pos = 0;
+ memset(s->rx_buf, 0, sizeof(s->rx_buf));
+ memset(s->tx_buf, 0, sizeof(s->tx_buf));
+}
+
+static uint8_t checksum(const uint8_t *ptr, int len)
+{
+ int sum = 0;
+
+ for (int i = 0; i < len; i++) {
+ sum += ptr[i];
+ }
+
+ return 256 - sum;
+}
+
+static int intel_me_i2c_event(I2CSlave *i2c, enum i2c_event event)
+{
+ IntelMEState *s = INTEL_ME(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ break;
+ case I2C_START_SEND:
+ s->rx_len = 0;
+ memset(s->rx_buf, 0, sizeof(s->rx_buf));
+ break;
+ case I2C_START_SEND_ASYNC:
+ break;
+ case I2C_FINISH:
+ printf("IntelME rx: [");
+ for (int i = 0; i < s->rx_len; i++) {
+ if (i) {
+ printf(", ");
+ }
+ printf("0x%02x", s->rx_buf[i]);
+ }
+ printf("]\n");
+
+ s->tx_len = 10;
+ s->tx_pos = 0;
+ s->tx_buf[0] = s->rx_buf[2];
+ s->tx_buf[1] = ((s->rx_buf[0] >> 2) + 1) << 2;
+ s->tx_buf[2] = 256 - s->tx_buf[0] - s->tx_buf[1];
+ s->tx_buf[3] = i2c->address; // rsSA response Slave Address
+ s->tx_buf[4] = (s->rx_buf[3] >> 2) << 2; // sequence number
+ s->tx_buf[5] = s->rx_buf[4]; // Same command code
+ s->tx_buf[6] = 0x00; // OK
+ s->tx_buf[7] = 0x55; // NO_ERROR
+ s->tx_buf[8] = 0x00;
+ s->tx_buf[9] = checksum(s->tx_buf, s->tx_len - 1);
+ s->tx_buf[0] >>= 1;
+ i2c_bus_master(s->bus, s->bh);
+ break;
+ case I2C_NACK:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t intel_me_i2c_recv(I2CSlave *i2c)
+{
+ return 0xff;
+}
+
+static int intel_me_i2c_send(I2CSlave *i2c, uint8_t data)
+{
+ IntelMEState *s = INTEL_ME(i2c);
+
+ assert(s->rx_len < sizeof(s->rx_buf));
+ s->rx_buf[s->rx_len++] = data;
+
+ return 0;
+}
+
+static void intel_me_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ I2CSlaveClass *i2c = I2C_SLAVE_CLASS(oc);
+
+ dc->realize = intel_me_realize;
+ i2c->event = intel_me_i2c_event;
+ i2c->recv = intel_me_i2c_recv;
+ i2c->send = intel_me_i2c_send;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_INTEL_ME,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(IntelMEState),
+ .class_init = intel_me_class_init,
+ },
+};
+
+DEFINE_TYPES(types);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 1edad44b6b..a2c75894a3 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -118,7 +118,8 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_sdmc.c',
'aspeed_xdma.c',
'aspeed_peci.c',
- 'fby35_cpld.c'))
+ 'fby35_cpld.c',
+ 'intel_me.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))