Signed-off-by: Peter Delevoryas <pdel@fb.com>
---
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'))
--
2.30.2
On 6/28/22 00:27, Peter Delevoryas wrote:
> Signed-off-by: Peter Delevoryas <pdel@fb.com>
Intro ?
I would rather have 2 patches, one for the slave model and one adding
a device to the machine.
Please replace the printf with trace events.
Thanks,
C.
> ---
> 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'))
> On Jun 27, 2022, at 11:58 PM, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 6/28/22 00:27, Peter Delevoryas wrote:
>> Signed-off-by: Peter Delevoryas <pdel@fb.com>
>
> Intro ?
Yep, will do
>
> I would rather have 2 patches, one for the slave model and one adding
> a device to the machine.
Got it, I’ll split it.
>
> Please replace the printf with trace events.
Yeah sorry about that
>
> Thanks,
>
> C.
>
>> ---
>> 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'))
>
Signed-off-by: Peter Delevoryas <pdel@fb.com>
---
hw/arm/aspeed.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 88e9a47dc2..375d87e6c7 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1448,6 +1448,7 @@ static void oby35_cl_i2c_init(AspeedMachineState *bmc)
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[6], "intel-me", 0x10);
i2c_slave_create_simple(i2c[4], "isl69259", 0x76);
i2c_slave_create_simple(i2c[4], "isl69259", 0x62);
i2c_slave_create_simple(i2c[4], "isl69259", 0x60);
--
2.30.2
Signed-off-by: Peter Delevoryas <pdel@fb.com>
---
hw/i2c/aspeed_i2c.c | 133 ++++++++++++++++++++++++++++++++----
include/hw/i2c/aspeed_i2c.h | 3 +
2 files changed, 124 insertions(+), 12 deletions(-)
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 8a8514586f..fc8b6b62cf 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -78,6 +78,18 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
}
}
+static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus)
+{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+
+ if (!bus->regs[R_I2CS_INTR_STS]) {
+ return;
+ }
+
+ bus->controller->intr_status |= 1 << bus->id;
+ qemu_irq_raise(aic->bus_get_irq(bus));
+}
+
static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
unsigned size)
{
@@ -140,8 +152,17 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_LEN_STS:
case A_I2CC_DMA_ADDR:
case A_I2CC_DMA_LEN:
+
+ case A_I2CS_DEV_ADDR:
+ case A_I2CS_DMA_RX_ADDR:
+ case A_I2CS_DMA_LEN:
+ case A_I2CS_CMD:
+ case A_I2CS_INTR_CTRL:
+ case A_I2CS_DMA_LEN_STS:
/* Value is already set, don't do anything. */
break;
+ case A_I2CS_INTR_STS:
+ break;
case A_I2CM_CMD:
value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
break;
@@ -547,12 +568,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
switch (offset) {
case A_I2CC_FUN_CTRL:
- if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
- __func__);
- break;
- }
- bus->regs[R_I2CC_FUN_CTRL] = value & 0x007dc3ff;
+ bus->regs[R_I2CC_FUN_CTRL] = value;
break;
case A_I2CC_AC_TIMING:
bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff;
@@ -580,6 +596,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(aic->bus_get_irq(bus));
}
+ aspeed_i2c_bus_raise_slave_interrupt(bus);
break;
}
bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f);
@@ -668,15 +685,53 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
case A_I2CC_DMA_LEN:
/* RO */
break;
- case A_I2CS_DMA_LEN_STS:
- case A_I2CS_DMA_TX_ADDR:
- case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DEV_ADDR:
+ bus->regs[R_I2CS_DEV_ADDR] = value;
+ break;
+ case A_I2CS_DMA_RX_ADDR:
+ bus->regs[R_I2CS_DMA_RX_ADDR] = value;
+ break;
+ case A_I2CS_DMA_LEN:
+ assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0);
+ if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) {
+ ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN,
+ FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN));
+ } else {
+ bus->regs[R_I2CS_DMA_LEN] = value;
+ }
+ break;
+ case A_I2CS_CMD:
+ if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) {
+ bus->regs[R_I2CS_CMD] |= value;
+ } else {
+ bus->regs[R_I2CS_CMD] = value;
+ }
+ i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]);
+ break;
case A_I2CS_INTR_CTRL:
+ bus->regs[R_I2CS_INTR_CTRL] = value;
+ break;
+
case A_I2CS_INTR_STS:
- case A_I2CS_CMD:
- case A_I2CS_DMA_LEN:
- qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n",
+ if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) {
+ if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) &&
+ FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) {
+ bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000;
+ }
+ } else {
+ bus->regs[R_I2CS_INTR_STS] &= ~value;
+ }
+ if (!bus->regs[R_I2CS_INTR_STS]) {
+ bus->controller->intr_status &= ~(1 << bus->id);
+ qemu_irq_lower(aic->bus_get_irq(bus));
+ }
+ aspeed_i2c_bus_raise_interrupt(bus);
+ break;
+ case A_I2CS_DMA_LEN_STS:
+ bus->regs[R_I2CS_DMA_LEN_STS] = 0;
+ break;
+ case A_I2CS_DMA_TX_ADDR:
+ qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
__func__);
break;
default:
@@ -1037,6 +1092,39 @@ static const TypeInfo aspeed_i2c_info = {
.abstract = true,
};
+static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
+ enum i2c_event event)
+{
+ switch (event) {
+ case I2C_START_SEND_ASYNC:
+ if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Slave mode RX DMA is not enabled\n", __func__);
+ return -1;
+ }
+ ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
+ bus->regs[R_I2CC_DMA_ADDR] =
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
+ bus->regs[R_I2CC_DMA_LEN] =
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
+ i2c_ack(bus->bus);
+ break;
+ case I2C_FINISH:
+ ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1);
+ ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
+ SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1);
+ SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1);
+ aspeed_i2c_bus_raise_slave_interrupt(bus);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n",
+ __func__, event);
+ return -1;
+ }
+
+ return 0;
+}
+
static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
@@ -1045,6 +1133,10 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
uint32_t value;
+ if (aspeed_i2c_is_new_mode(bus->controller)) {
+ return aspeed_i2c_bus_new_slave_event(bus, event);
+ }
+
switch (event) {
case I2C_START_SEND_ASYNC:
value = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_byte_buf, TX_BUF);
@@ -1073,6 +1165,19 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
return 0;
}
+static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
+{
+ assert(address_space_write(&bus->controller->dram_as,
+ bus->regs[R_I2CC_DMA_ADDR],
+ MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
+
+ bus->regs[R_I2CC_DMA_ADDR]++;
+ bus->regs[R_I2CC_DMA_LEN]--;
+ ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
+ i2c_ack(bus->bus);
+}
+
static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
@@ -1080,6 +1185,10 @@ static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
+ if (aspeed_i2c_is_new_mode(bus->controller)) {
+ return aspeed_i2c_bus_new_slave_send_async(bus, data);
+ }
+
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index ba148b2f6d..300a89b343 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -174,6 +174,8 @@ REG32(I2CM_DMA_LEN, 0x1c)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
REG32(I2CS_INTR_CTRL, 0x20)
+ FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1)
+ FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1)
REG32(I2CS_INTR_STS, 0x24)
/* 31:29 shared with I2CD_INTR_STS[31:29] */
FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
@@ -184,6 +186,7 @@ REG32(I2CS_INTR_STS, 0x24)
FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
/* 14:0 shared with I2CD_INTR_STS[14:0] */
+ FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)
REG32(I2CS_CMD, 0x28)
FIELD(I2CS_CMD, W1_CTRL, 31, 1)
FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
--
2.30.2
On 6/28/22 00:27, Peter Delevoryas wrote:
> Signed-off-by: Peter Delevoryas <pdel@fb.com>
Some Intro would be welcome. Please move the patch after Klaus patches.
Thanks,
C.
> ---
> hw/i2c/aspeed_i2c.c | 133 ++++++++++++++++++++++++++++++++----
> include/hw/i2c/aspeed_i2c.h | 3 +
> 2 files changed, 124 insertions(+), 12 deletions(-)
>
> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
> index 8a8514586f..fc8b6b62cf 100644
> --- a/hw/i2c/aspeed_i2c.c
> +++ b/hw/i2c/aspeed_i2c.c
> @@ -78,6 +78,18 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
> }
> }
>
> +static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus)
> +{
> + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
> +
> + if (!bus->regs[R_I2CS_INTR_STS]) {
> + return;
> + }
> +
> + bus->controller->intr_status |= 1 << bus->id;
> + qemu_irq_raise(aic->bus_get_irq(bus));
> +}
> +
> static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
> unsigned size)
> {
> @@ -140,8 +152,17 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
> case A_I2CM_DMA_LEN_STS:
> case A_I2CC_DMA_ADDR:
> case A_I2CC_DMA_LEN:
> +
> + case A_I2CS_DEV_ADDR:
> + case A_I2CS_DMA_RX_ADDR:
> + case A_I2CS_DMA_LEN:
> + case A_I2CS_CMD:
> + case A_I2CS_INTR_CTRL:
> + case A_I2CS_DMA_LEN_STS:
> /* Value is already set, don't do anything. */
> break;
> + case A_I2CS_INTR_STS:
> + break;
> case A_I2CM_CMD:
> value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
> break;
> @@ -547,12 +568,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
>
> switch (offset) {
> case A_I2CC_FUN_CTRL:
> - if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
> - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
> - __func__);
> - break;
> - }
> - bus->regs[R_I2CC_FUN_CTRL] = value & 0x007dc3ff;
> + bus->regs[R_I2CC_FUN_CTRL] = value;
> break;
> case A_I2CC_AC_TIMING:
> bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff;
> @@ -580,6 +596,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> bus->controller->intr_status &= ~(1 << bus->id);
> qemu_irq_lower(aic->bus_get_irq(bus));
> }
> + aspeed_i2c_bus_raise_slave_interrupt(bus);
> break;
> }
> bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f);
> @@ -668,15 +685,53 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> case A_I2CC_DMA_LEN:
> /* RO */
> break;
> - case A_I2CS_DMA_LEN_STS:
> - case A_I2CS_DMA_TX_ADDR:
> - case A_I2CS_DMA_RX_ADDR:
> case A_I2CS_DEV_ADDR:
> + bus->regs[R_I2CS_DEV_ADDR] = value;
> + break;
> + case A_I2CS_DMA_RX_ADDR:
> + bus->regs[R_I2CS_DMA_RX_ADDR] = value;
> + break;
> + case A_I2CS_DMA_LEN:
> + assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0);
> + if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) {
> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN,
> + FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN));
> + } else {
> + bus->regs[R_I2CS_DMA_LEN] = value;
> + }
> + break;
> + case A_I2CS_CMD:
> + if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) {
> + bus->regs[R_I2CS_CMD] |= value;
> + } else {
> + bus->regs[R_I2CS_CMD] = value;
> + }
> + i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]);
> + break;
> case A_I2CS_INTR_CTRL:
> + bus->regs[R_I2CS_INTR_CTRL] = value;
> + break;
> +
> case A_I2CS_INTR_STS:
> - case A_I2CS_CMD:
> - case A_I2CS_DMA_LEN:
> - qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n",
> + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) {
> + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) &&
> + FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) {
> + bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000;
> + }
> + } else {
> + bus->regs[R_I2CS_INTR_STS] &= ~value;
> + }
> + if (!bus->regs[R_I2CS_INTR_STS]) {
> + bus->controller->intr_status &= ~(1 << bus->id);
> + qemu_irq_lower(aic->bus_get_irq(bus));
> + }
> + aspeed_i2c_bus_raise_interrupt(bus);
> + break;
> + case A_I2CS_DMA_LEN_STS:
> + bus->regs[R_I2CS_DMA_LEN_STS] = 0;
> + break;
> + case A_I2CS_DMA_TX_ADDR:
> + qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
> __func__);
> break;
> default:
> @@ -1037,6 +1092,39 @@ static const TypeInfo aspeed_i2c_info = {
> .abstract = true,
> };
>
> +static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
> + enum i2c_event event)
> +{
> + switch (event) {
> + case I2C_START_SEND_ASYNC:
> + if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Slave mode RX DMA is not enabled\n", __func__);
> + return -1;
> + }
> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
> + bus->regs[R_I2CC_DMA_ADDR] =
> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
> + bus->regs[R_I2CC_DMA_LEN] =
> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
> + i2c_ack(bus->bus);
> + break;
> + case I2C_FINISH:
> + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1);
> + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
> + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1);
> + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1);
> + aspeed_i2c_bus_raise_slave_interrupt(bus);
> + break;
> + default:
> + qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n",
> + __func__, event);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
> {
> BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
> @@ -1045,6 +1133,10 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
> uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
> uint32_t value;
>
> + if (aspeed_i2c_is_new_mode(bus->controller)) {
> + return aspeed_i2c_bus_new_slave_event(bus, event);
> + }
> +
> switch (event) {
> case I2C_START_SEND_ASYNC:
> value = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_byte_buf, TX_BUF);
> @@ -1073,6 +1165,19 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
> return 0;
> }
>
> +static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
> +{
> + assert(address_space_write(&bus->controller->dram_as,
> + bus->regs[R_I2CC_DMA_ADDR],
> + MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
> +
> + bus->regs[R_I2CC_DMA_ADDR]++;
> + bus->regs[R_I2CC_DMA_LEN]--;
> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
> + i2c_ack(bus->bus);
> +}
> +
> static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
> {
> BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
> @@ -1080,6 +1185,10 @@ static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
> uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
> uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
>
> + if (aspeed_i2c_is_new_mode(bus->controller)) {
> + return aspeed_i2c_bus_new_slave_send_async(bus, data);
> + }
> +
> SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
> SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
>
> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
> index ba148b2f6d..300a89b343 100644
> --- a/include/hw/i2c/aspeed_i2c.h
> +++ b/include/hw/i2c/aspeed_i2c.h
> @@ -174,6 +174,8 @@ REG32(I2CM_DMA_LEN, 0x1c)
> FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
> FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
> REG32(I2CS_INTR_CTRL, 0x20)
> + FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1)
> + FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1)
> REG32(I2CS_INTR_STS, 0x24)
> /* 31:29 shared with I2CD_INTR_STS[31:29] */
> FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
> @@ -184,6 +186,7 @@ REG32(I2CS_INTR_STS, 0x24)
> FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
> FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
> /* 14:0 shared with I2CD_INTR_STS[14:0] */
> + FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)
> REG32(I2CS_CMD, 0x28)
> FIELD(I2CS_CMD, W1_CTRL, 31, 1)
> FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
> On Jun 28, 2022, at 12:02 AM, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 6/28/22 00:27, Peter Delevoryas wrote:
>> Signed-off-by: Peter Delevoryas <pdel@fb.com>
>
> Some Intro would be welcome. Please move the patch after Klaus patches.
Yes, I’ll describe the state machine flow. That’s my bad. And I’ll
move it to the beginning with the other i2c patches.
>
> Thanks,
>
> C.
>
>
>
>> ---
>> hw/i2c/aspeed_i2c.c | 133 ++++++++++++++++++++++++++++++++----
>> include/hw/i2c/aspeed_i2c.h | 3 +
>> 2 files changed, 124 insertions(+), 12 deletions(-)
>> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
>> index 8a8514586f..fc8b6b62cf 100644
>> --- a/hw/i2c/aspeed_i2c.c
>> +++ b/hw/i2c/aspeed_i2c.c
>> @@ -78,6 +78,18 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
>> }
>> }
>> +static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus)
>> +{
>> + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
>> +
>> + if (!bus->regs[R_I2CS_INTR_STS]) {
>> + return;
>> + }
>> +
>> + bus->controller->intr_status |= 1 << bus->id;
>> + qemu_irq_raise(aic->bus_get_irq(bus));
>> +}
>> +
>> static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
>> unsigned size)
>> {
>> @@ -140,8 +152,17 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
>> case A_I2CM_DMA_LEN_STS:
>> case A_I2CC_DMA_ADDR:
>> case A_I2CC_DMA_LEN:
>> +
>> + case A_I2CS_DEV_ADDR:
>> + case A_I2CS_DMA_RX_ADDR:
>> + case A_I2CS_DMA_LEN:
>> + case A_I2CS_CMD:
>> + case A_I2CS_INTR_CTRL:
>> + case A_I2CS_DMA_LEN_STS:
>> /* Value is already set, don't do anything. */
>> break;
>> + case A_I2CS_INTR_STS:
>> + break;
>> case A_I2CM_CMD:
>> value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
>> break;
>> @@ -547,12 +568,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
>> switch (offset) {
>> case A_I2CC_FUN_CTRL:
>> - if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
>> - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
>> - __func__);
>> - break;
>> - }
>> - bus->regs[R_I2CC_FUN_CTRL] = value & 0x007dc3ff;
>> + bus->regs[R_I2CC_FUN_CTRL] = value;
>> break;
>> case A_I2CC_AC_TIMING:
>> bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff;
>> @@ -580,6 +596,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
>> bus->controller->intr_status &= ~(1 << bus->id);
>> qemu_irq_lower(aic->bus_get_irq(bus));
>> }
>> + aspeed_i2c_bus_raise_slave_interrupt(bus);
>> break;
>> }
>> bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f);
>> @@ -668,15 +685,53 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
>> case A_I2CC_DMA_LEN:
>> /* RO */
>> break;
>> - case A_I2CS_DMA_LEN_STS:
>> - case A_I2CS_DMA_TX_ADDR:
>> - case A_I2CS_DMA_RX_ADDR:
>> case A_I2CS_DEV_ADDR:
>> + bus->regs[R_I2CS_DEV_ADDR] = value;
>> + break;
>> + case A_I2CS_DMA_RX_ADDR:
>> + bus->regs[R_I2CS_DMA_RX_ADDR] = value;
>> + break;
>> + case A_I2CS_DMA_LEN:
>> + assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0);
>> + if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) {
>> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN,
>> + FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN));
>> + } else {
>> + bus->regs[R_I2CS_DMA_LEN] = value;
>> + }
>> + break;
>> + case A_I2CS_CMD:
>> + if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) {
>> + bus->regs[R_I2CS_CMD] |= value;
>> + } else {
>> + bus->regs[R_I2CS_CMD] = value;
>> + }
>> + i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]);
>> + break;
>> case A_I2CS_INTR_CTRL:
>> + bus->regs[R_I2CS_INTR_CTRL] = value;
>> + break;
>> +
>> case A_I2CS_INTR_STS:
>> - case A_I2CS_CMD:
>> - case A_I2CS_DMA_LEN:
>> - qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n",
>> + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) {
>> + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) &&
>> + FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) {
>> + bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000;
>> + }
>> + } else {
>> + bus->regs[R_I2CS_INTR_STS] &= ~value;
>> + }
>> + if (!bus->regs[R_I2CS_INTR_STS]) {
>> + bus->controller->intr_status &= ~(1 << bus->id);
>> + qemu_irq_lower(aic->bus_get_irq(bus));
>> + }
>> + aspeed_i2c_bus_raise_interrupt(bus);
>> + break;
>> + case A_I2CS_DMA_LEN_STS:
>> + bus->regs[R_I2CS_DMA_LEN_STS] = 0;
>> + break;
>> + case A_I2CS_DMA_TX_ADDR:
>> + qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
>> __func__);
>> break;
>> default:
>> @@ -1037,6 +1092,39 @@ static const TypeInfo aspeed_i2c_info = {
>> .abstract = true,
>> };
>> +static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
>> + enum i2c_event event)
>> +{
>> + switch (event) {
>> + case I2C_START_SEND_ASYNC:
>> + if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Slave mode RX DMA is not enabled\n", __func__);
>> + return -1;
>> + }
>> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
>> + bus->regs[R_I2CC_DMA_ADDR] =
>> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
>> + bus->regs[R_I2CC_DMA_LEN] =
>> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
>> + i2c_ack(bus->bus);
>> + break;
>> + case I2C_FINISH:
>> + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1);
>> + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
>> + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1);
>> + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1);
>> + aspeed_i2c_bus_raise_slave_interrupt(bus);
>> + break;
>> + default:
>> + qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n",
>> + __func__, event);
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
>> {
>> BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
>> @@ -1045,6 +1133,10 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
>> uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
>> uint32_t value;
>> + if (aspeed_i2c_is_new_mode(bus->controller)) {
>> + return aspeed_i2c_bus_new_slave_event(bus, event);
>> + }
>> +
>> switch (event) {
>> case I2C_START_SEND_ASYNC:
>> value = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_byte_buf, TX_BUF);
>> @@ -1073,6 +1165,19 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
>> return 0;
>> }
>> +static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
>> +{
>> + assert(address_space_write(&bus->controller->dram_as,
>> + bus->regs[R_I2CC_DMA_ADDR],
>> + MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
>> +
>> + bus->regs[R_I2CC_DMA_ADDR]++;
>> + bus->regs[R_I2CC_DMA_LEN]--;
>> + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
>> + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
>> + i2c_ack(bus->bus);
>> +}
>> +
>> static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
>> {
>> BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
>> @@ -1080,6 +1185,10 @@ static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
>> uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
>> uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
>> + if (aspeed_i2c_is_new_mode(bus->controller)) {
>> + return aspeed_i2c_bus_new_slave_send_async(bus, data);
>> + }
>> +
>> SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
>> SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
>> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
>> index ba148b2f6d..300a89b343 100644
>> --- a/include/hw/i2c/aspeed_i2c.h
>> +++ b/include/hw/i2c/aspeed_i2c.h
>> @@ -174,6 +174,8 @@ REG32(I2CM_DMA_LEN, 0x1c)
>> FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
>> FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
>> REG32(I2CS_INTR_CTRL, 0x20)
>> + FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1)
>> + FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1)
>> REG32(I2CS_INTR_STS, 0x24)
>> /* 31:29 shared with I2CD_INTR_STS[31:29] */
>> FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
>> @@ -184,6 +186,7 @@ REG32(I2CS_INTR_STS, 0x24)
>> FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
>> FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
>> /* 14:0 shared with I2CD_INTR_STS[14:0] */
>> + FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)
>> REG32(I2CS_CMD, 0x28)
>> FIELD(I2CS_CMD, W1_CTRL, 31, 1)
>> FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
>
© 2016 - 2026 Red Hat, Inc.