* [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders
@ 2024-11-07 19:54 Titus Rwantare
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
This patch series bundles the GPIO sensors previously sent for review:
https://lore.kernel.org/all/20230206194936.168843-1-titusr@google.com
and the GSZ board commit sent here:
https://lore.kernel.org/all/20241007171700.1594342-1-titusr@google.com/
The Quanta GSZ a current Google machine of the day. This machine will be used as a platform to enable features such as the PECI bmc interface, and Intel eSPI virtual wire interface in QEMU.
This patch series also contains a set of i2c GPIO expanders, with support for 4, 8, and 16 GPIO connections.
The devices are configured as GPIO inputs by default, but can have pins configured to be inputs with qmp commands.
These sensors and machine are maintained and used in CI daily within Google.
Titus Rwantare (6):
bitops.h: add deposit16 function
hw/gpio: add PCA953x i2c GPIO expanders
hw/gpio: add PCA9536 i2c gpio expander
hw/i2c: add canonical path to i2c event traces
hw/arm: imply I2C_DEVICES on NPCM7xx
hw/arm: add Quanta GSZ bmc machine
hw/arm/Kconfig | 1 +
hw/arm/npcm7xx_boards.c | 160 +++++++++++++
hw/gpio/Kconfig | 5 +
hw/gpio/meson.build | 1 +
hw/gpio/pca_i2c_gpio.c | 409 ++++++++++++++++++++++++++++++++
hw/gpio/trace-events | 5 +
hw/i2c/core.c | 8 +-
hw/i2c/trace-events | 2 +-
include/hw/gpio/pca_i2c_gpio.h | 70 ++++++
include/qemu/bitops.h | 26 ++
tests/qtest/meson.build | 1 +
tests/qtest/pca_i2c_gpio-test.c | 188 +++++++++++++++
12 files changed, 872 insertions(+), 4 deletions(-)
create mode 100644 hw/gpio/pca_i2c_gpio.c
create mode 100644 include/hw/gpio/pca_i2c_gpio.h
create mode 100644 tests/qtest/pca_i2c_gpio-test.c
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/6] bitops.h: add deposit16 function
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
2024-11-11 22:03 ` Miles Glenn
2024-11-13 15:46 ` Peter Maydell
2024-11-07 19:54 ` [PATCH 2/6] hw/gpio: add PCA953x i2c GPIO expanders Titus Rwantare
` (4 subsequent siblings)
5 siblings, 2 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
Makes it more explicit that 16 bit values are being used
Signed-off-by: Titus Rwantare <titusr@google.com>
---
include/qemu/bitops.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 2c0a2fe751..05179e3ded 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -459,6 +459,32 @@ static inline int64_t sextract64(uint64_t value, int start, int length)
return ((int64_t)(value << (64 - length - start))) >> (64 - length);
}
+/**
+ * deposit16:
+ * @value: initial value to insert bit field into
+ * @start: the lowest bit in the bit field (numbered from 0)
+ * @length: the length of the bit field
+ * @fieldval: the value to insert into the bit field
+ *
+ * Deposit @fieldval into the 16 bit @value at the bit field specified
+ * by the @start and @length parameters, and return the modified
+ * @value. Bits of @value outside the bit field are not modified.
+ * Bits of @fieldval above the least significant @length bits are
+ * ignored. The bit field must lie entirely within the 16 bit word.
+ * It is valid to request that all 16 bits are modified (ie @length
+ * 16 and @start 0).
+ *
+ * Returns: the modified @value.
+ */
+static inline uint16_t deposit16(uint16_t value, int start, int length,
+ uint16_t fieldval)
+{
+ uint16_t mask;
+ assert(start >= 0 && length > 0 && length <= 16 - start);
+ mask = (~0U >> (16 - length)) << start;
+ return (value & ~mask) | ((fieldval << start) & mask);
+}
+
/**
* deposit32:
* @value: initial value to insert bit field into
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/6] hw/gpio: add PCA953x i2c GPIO expanders
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
2024-11-07 19:54 ` [PATCH 3/6] hw/gpio: add PCA9536 i2c gpio expander Titus Rwantare
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
The PCA6416 is an i2c device with 16 GPIO pins, the PCA9538 has 8 pins.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/gpio/Kconfig | 5 +
hw/gpio/meson.build | 1 +
hw/gpio/pca_i2c_gpio.c | 391 ++++++++++++++++++++++++++++++++
hw/gpio/trace-events | 5 +
include/hw/gpio/pca_i2c_gpio.h | 68 ++++++
tests/qtest/meson.build | 1 +
tests/qtest/pca_i2c_gpio-test.c | 188 +++++++++++++++
7 files changed, 659 insertions(+)
create mode 100644 hw/gpio/pca_i2c_gpio.c
create mode 100644 include/hw/gpio/pca_i2c_gpio.h
create mode 100644 tests/qtest/pca_i2c_gpio-test.c
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
index c423e10f59..fde1155424 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -13,6 +13,11 @@ config GPIO_PWR
config SIFIVE_GPIO
bool
+config PCA_I2C_GPIO
+ bool
+ depends on I2C
+ default y if I2C_DEVICES
+
config STM32L4X5_GPIO
bool
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
index 74840619c0..51f3ba7fc5 100644
--- a/hw/gpio/meson.build
+++ b/hw/gpio/meson.build
@@ -18,3 +18,4 @@ system_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_gpio.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c'))
system_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))
system_ss.add(when: 'CONFIG_PCF8574', if_true: files('pcf8574.c'))
+system_ss.add(when: 'CONFIG_PCA_I2C_GPIO', if_true: files('pca_i2c_gpio.c'))
diff --git a/hw/gpio/pca_i2c_gpio.c b/hw/gpio/pca_i2c_gpio.c
new file mode 100644
index 0000000000..2486c620e3
--- /dev/null
+++ b/hw/gpio/pca_i2c_gpio.c
@@ -0,0 +1,391 @@
+/*
+ * NXP PCA I2C GPIO Expanders
+ *
+ * Low-voltage translating 16-bit I2C/SMBus GPIO expander with interrupt output,
+ * reset, and configuration registers
+ *
+ * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCA6416A.pdf
+ * https://www.ti.com/lit/ds/symlink/pca9538.pdf
+ *
+ * Copyright 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * To assert some input pins before boot, use the following in the board file of
+ * the machine:
+ * object_property_set_uint(Object *obj, const char *name,
+ * uint64_t value, Error **errp);
+ * specifying name as "gpio_config" and the value as a bitfield of the inputs
+ * e.g. for the pca6416, a value of 0xFFF0, configures pins 0-3 as outputs and
+ * 4-15 as inputs.
+ * Then using name "gpio_input" with value "0x0F00" would raise GPIOs 8-11.
+ *
+ * This value can also be set at runtime through qmp externally, or by
+ * writing to the config register using i2c. The guest driver should generally
+ * control the config register, but exposing it via qmp allows external testing.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/gpio/pca_i2c_gpio.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qapi/visitor.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "trace.h"
+
+/*
+ * compare new_output to curr_output and update irq to match new_output
+ *
+ * The Input port registers (registers 0 and 1) reflect the incoming logic
+ * levels of the pins, regardless of whether the pin is defined as an input or
+ * an output by the Configuration register.
+ */
+static void pca_i2c_update_irqs(PCAGPIOState *ps)
+{
+ PCAGPIOClass *pc = PCA_I2C_GPIO_GET_CLASS(ps);
+ uint16_t out_diff = ps->new_output ^ ps->curr_output;
+ uint16_t in_diff = ps->new_input ^ ps->curr_input;
+ uint16_t mask, pin_i;
+
+ if (in_diff || out_diff) {
+ for (int i = 0; i < pc->num_pins; i++) {
+ mask = BIT(i);
+ /* pin must be configured as an output to be set here */
+ if (out_diff & ~ps->config & mask) {
+ pin_i = mask & ps->new_output;
+ qemu_set_irq(ps->output[i], pin_i > 0);
+ ps->curr_output &= ~mask;
+ ps->curr_output |= pin_i;
+ }
+
+ if (in_diff & mask) {
+ ps->curr_input &= ~mask;
+ ps->curr_input |= mask & ps->new_input;
+ }
+ }
+ /* make diff = 0 */
+ ps->new_input = ps->curr_input;
+ }
+}
+
+static void pca_i2c_irq_handler(void *opaque, int n, int level)
+{
+ PCAGPIOState *ps = opaque;
+ PCAGPIOClass *pc = PCA_I2C_GPIO_GET_CLASS(opaque);
+ uint16_t mask = BIT(n);
+
+ g_assert(n < pc->num_pins);
+ g_assert(n >= 0);
+
+ ps->new_input &= ~mask;
+
+ if (level > 0) {
+ ps->new_input |= BIT(n);
+ }
+
+ pca_i2c_update_irqs(ps);
+}
+
+/* slave to master */
+static uint8_t _pca953x_recv(I2CSlave *i2c, uint32_t shift)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+ uint8_t data;
+
+ switch (ps->command) {
+ case PCA953x_INPUT_PORT:
+ data = extract16(ps->curr_input, shift, 8);
+ break;
+ /*
+ * i2c reads to the output registers reflect the values written
+ * NOT the actual values of the gpios
+ */
+ case PCA953x_OUTPUT_PORT:
+ data = extract16(ps->new_output, shift, 8);
+ break;
+
+ case PCA953x_POLARITY_INVERSION_PORT:
+ data = extract16(ps->polarity_inv, shift, 8);
+ break;
+
+ case PCA953x_CONFIGURATION_PORT:
+ data = extract16(ps->config, shift, 8);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: reading from unsupported register 0x%02x",
+ __func__, ps->command);
+ data = 0xFF;
+ break;
+ }
+
+ trace_pca_i2c_recv(DEVICE(ps)->canonical_path, ps->command, shift, data);
+ return data;
+}
+
+static uint8_t pca6416_recv(I2CSlave *i2c)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+ uint32_t shift = ps->command & 1 ? 8 : 0;
+
+ /* Transform command into 4 port equivalent */
+ ps->command = ps->command >> 1;
+
+ return _pca953x_recv(i2c, shift);
+}
+
+static uint8_t pca953x_recv(I2CSlave *i2c)
+{
+ return _pca953x_recv(i2c, 0);
+}
+
+/* master to slave */
+static int _pca953x_send(I2CSlave *i2c, uint32_t shift, uint8_t data)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+
+ if (ps->i2c_cmd) {
+ ps->command = data;
+ ps->i2c_cmd = false;
+ return 0;
+ }
+
+ trace_pca_i2c_send(DEVICE(ps)->canonical_path, ps->command, shift, data);
+
+ switch (ps->command) {
+ case PCA953x_INPUT_PORT:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: writing to read only reg: 0x%02x",
+ __func__, ps->command);
+ break;
+ case PCA953x_OUTPUT_PORT:
+ ps->new_output = deposit16(ps->new_output, shift, 8, data);
+ break;
+
+ case PCA953x_POLARITY_INVERSION_PORT:
+ ps->polarity_inv = deposit16(ps->polarity_inv, shift, 8, data);
+ break;
+
+ case PCA953x_CONFIGURATION_PORT:
+ ps->config = deposit16(ps->config, shift, 8, data);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: writing to unsupported register\n",
+ __func__);
+ return -1;
+ }
+
+ pca_i2c_update_irqs(ps);
+ return 0;
+}
+
+static int pca6416_send(I2CSlave *i2c, uint8_t data)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+ uint32_t shift = ps->command & 1 ? 8 : 0;
+
+ /* Transform command into 4 port equivalent */
+ ps->command = ps->command >> 1;
+
+ return _pca953x_send(i2c, shift, data);
+}
+
+static int pca953x_send(I2CSlave *i2c, uint8_t data)
+{
+ return _pca953x_send(i2c, 0, data);
+}
+
+static int pca_i2c_event(I2CSlave *i2c, enum i2c_event event)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ trace_pca_i2c_event(DEVICE(ps)->canonical_path, "START_RECV");
+ break;
+
+ case I2C_START_SEND:
+ trace_pca_i2c_event(DEVICE(ps)->canonical_path, "START_SEND");
+ ps->i2c_cmd = true;
+ break;
+
+ case I2C_FINISH:
+ trace_pca_i2c_event(DEVICE(ps)->canonical_path, "FINISH");
+ break;
+
+ case I2C_NACK:
+ trace_pca_i2c_event(DEVICE(ps)->canonical_path, "NACK");
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: unknown event 0x%x\n",
+ DEVICE(ps)->canonical_path, __func__, event);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void pca_i2c_config_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ visit_type_uint16(v, name, &ps->config, errp);
+}
+
+static void pca_i2c_config_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ if (!visit_type_uint16(v, name, &ps->config, errp)) {
+ return;
+ }
+ pca_i2c_update_irqs(ps);
+}
+
+static void pca_i2c_input_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ visit_type_uint16(v, name, &ps->curr_input, errp);
+}
+
+static void pca_i2c_input_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ if (!visit_type_uint16(v, name, &ps->new_input, errp)) {
+ return;
+ }
+ pca_i2c_update_irqs(ps);
+}
+
+static void pca_i2c_output_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ visit_type_uint16(v, name, &ps->curr_output, errp);
+}
+
+static void pca_i2c_output_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ if (!visit_type_uint16(v, name, &ps->new_output, errp)) {
+ return;
+ }
+ pca_i2c_update_irqs(ps);
+}
+
+static void pca_i2c_enter_reset(Object *obj, ResetType type)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+
+ ps->polarity_inv = 0;
+ ps->config = 0;
+ ps->new_input = 0;
+ ps->new_output = 0;
+ ps->command = 0;
+
+ pca_i2c_update_irqs(ps);
+}
+
+static const VMStateDescription vmstate_pca_i2c_gpio = {
+ .name = TYPE_PCA_I2C_GPIO,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent, PCAGPIOState),
+ VMSTATE_UINT16(polarity_inv, PCAGPIOState),
+ VMSTATE_UINT16(config, PCAGPIOState),
+ VMSTATE_UINT16(curr_input, PCAGPIOState),
+ VMSTATE_UINT16(curr_output, PCAGPIOState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void pca6416_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ PCAGPIOClass *pc = PCA_I2C_GPIO_CLASS(klass);
+
+ dc->desc = "PCA6416 16-bit I/O expander";
+ pc->num_pins = PCA6416_NUM_PINS;
+
+ k->recv = pca6416_recv;
+ k->send = pca6416_send;
+}
+
+static void pca9538_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ PCAGPIOClass *pc = PCA_I2C_GPIO_CLASS(klass);
+
+ dc->desc = "PCA9538 8-bit I/O expander";
+ pc->num_pins = PCA9538_NUM_PINS;
+
+ k->recv = pca953x_recv;
+ k->send = pca953x_send;
+}
+
+static void pca_i2c_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->vmsd = &vmstate_pca_i2c_gpio;
+ rc->phases.enter = pca_i2c_enter_reset;
+ k->event = pca_i2c_event;
+}
+
+static void pca_i2c_gpio_init(Object *obj)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(obj);
+ PCAGPIOClass *pc = PCA_I2C_GPIO_GET_CLASS(obj);
+ DeviceState *dev = DEVICE(obj);
+
+ object_property_add(obj, "gpio_input", "uint16",
+ pca_i2c_input_get,
+ pca_i2c_input_set, NULL, NULL);
+ object_property_add(obj, "gpio_output", "uint16",
+ pca_i2c_output_get,
+ pca_i2c_output_set, NULL, NULL);
+ object_property_add(obj, "gpio_config", "uint16",
+ pca_i2c_config_get,
+ pca_i2c_config_set, NULL, NULL);
+ qdev_init_gpio_in(dev, pca_i2c_irq_handler, pc->num_pins);
+ qdev_init_gpio_out(dev, ps->output, pc->num_pins);
+}
+
+static const TypeInfo pca_gpio_types[] = {
+ {
+ .name = TYPE_PCA_I2C_GPIO,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(PCAGPIOState),
+ .instance_init = pca_i2c_gpio_init,
+ .class_size = sizeof(PCAGPIOClass),
+ .class_init = pca_i2c_gpio_class_init,
+ .abstract = true,
+ },
+ {
+ .name = TYPE_PCA6416_GPIO,
+ .parent = TYPE_PCA_I2C_GPIO,
+ .class_init = pca6416_gpio_class_init,
+ },
+ {
+ .name = TYPE_PCA9538_GPIO,
+ .parent = TYPE_PCA_I2C_GPIO,
+ .class_init = pca9538_gpio_class_init,
+ },
+};
+
+DEFINE_TYPES(pca_gpio_types);
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
index b91cc7e9a4..722fbdd54e 100644
--- a/hw/gpio/trace-events
+++ b/hw/gpio/trace-events
@@ -41,3 +41,8 @@ stm32l4x5_gpio_read(char *gpio, uint64_t addr) "GPIO%s addr: 0x%" PRIx64 " "
stm32l4x5_gpio_write(char *gpio, uint64_t addr, uint64_t data) "GPIO%s addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
stm32l4x5_gpio_update_idr(char *gpio, uint32_t old_idr, uint32_t new_idr) "GPIO%s from: 0x%x to: 0x%x"
stm32l4x5_gpio_pins(char *gpio, uint16_t disconnected, uint16_t high) "GPIO%s disconnected pins: 0x%x levels: 0x%x"
+
+# pca_i2c_gpio.c
+pca_i2c_event(const char *id, const char *event) "%s: %s"
+pca_i2c_recv(const char *id, uint8_t cmd, uint32_t shift, uint8_t data) "%s cmd: 0x%" PRIx8 "shift: %" PRIi32 " data 0x%" PRIx8
+pca_i2c_send(const char *id, uint8_t cmd, uint32_t shift, uint8_t data) "%s cmd: 0x%" PRIx8 "shift: %" PRIi32 " data 0x%" PRIx8
diff --git a/include/hw/gpio/pca_i2c_gpio.h b/include/hw/gpio/pca_i2c_gpio.h
new file mode 100644
index 0000000000..61e5853c24
--- /dev/null
+++ b/include/hw/gpio/pca_i2c_gpio.h
@@ -0,0 +1,68 @@
+/*
+ * NXP PCA I2C GPIO Expanders
+ * Low-voltage translating 16-bit I2C/SMBus GPIO expander with interrupt output,
+ * reset, and configuration registers
+ *
+ * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCA6416A.pdf
+ * https://www.ti.com/lit/ds/symlink/pca9538.pdf
+ *
+ * Note: Polarity inversion emulation not implemented
+ *
+ * Copyright 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef PCA_I2C_GPIO_H
+#define PCA_I2C_GPIO_H
+
+#include "hw/i2c/i2c.h"
+#include "qom/object.h"
+
+#define PCA_I2C_MAX_PINS 16
+#define PCA6416_NUM_PINS 16
+#define PCA9538_NUM_PINS 8
+
+typedef struct PCAGPIOClass {
+ I2CSlaveClass parent;
+
+ uint8_t num_pins;
+} PCAGPIOClass;
+
+typedef struct PCAGPIOState {
+ I2CSlave parent;
+
+ uint16_t polarity_inv;
+ uint16_t config;
+
+ /* the values of the gpio pins are mirrored in these integers */
+ uint16_t curr_input;
+ uint16_t curr_output;
+ uint16_t new_input;
+ uint16_t new_output;
+
+ /*
+ * Note that these outputs need to be consumed by some other input
+ * to be useful, qemu ignores writes to disconnected gpio pins
+ */
+ qemu_irq output[PCA_I2C_MAX_PINS];
+
+ /* i2c transaction info */
+ uint8_t command;
+ bool i2c_cmd;
+
+} PCAGPIOState;
+
+#define TYPE_PCA_I2C_GPIO "pca_i2c_gpio"
+OBJECT_DECLARE_TYPE(PCAGPIOState, PCAGPIOClass, PCA_I2C_GPIO)
+
+#define PCA953x_INPUT_PORT 0x00 /* read */
+#define PCA953x_OUTPUT_PORT 0x01 /* read/write */
+#define PCA953x_POLARITY_INVERSION_PORT 0x02 /* read/write */
+#define PCA953x_CONFIGURATION_PORT 0x03 /* read/write */
+
+#define PCA_I2C_CONFIG_DEFAULT 0
+
+#define TYPE_PCA6416_GPIO "pca6416"
+#define TYPE_PCA9538_GPIO "pca9538"
+
+#endif
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index aa93e98418..8a02a06a06 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -291,6 +291,7 @@ qos_test_ss.add(
'ne2000-test.c',
'tulip-test.c',
'nvme-test.c',
+ 'pca_i2c_gpio-test.c',
'pca9552-test.c',
'pci-test.c',
'pcnet-test.c',
diff --git a/tests/qtest/pca_i2c_gpio-test.c b/tests/qtest/pca_i2c_gpio-test.c
new file mode 100644
index 0000000000..2bb4c6a664
--- /dev/null
+++ b/tests/qtest/pca_i2c_gpio-test.c
@@ -0,0 +1,188 @@
+/*
+ * QTest for PCA I2C GPIO expanders
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/gpio/pca_i2c_gpio.h"
+#include "libqtest-single.h"
+#include "libqos/i2c.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qnum.h"
+#include "qemu/bitops.h"
+
+
+#define PCA6416_INPUT_PORT_0 0x00 /* read */
+#define PCA6416_INPUT_PORT_1 0x01 /* read */
+#define PCA6416_OUTPUT_PORT_0 0x02 /* read/write */
+#define PCA6416_OUTPUT_PORT_1 0x03 /* read/write */
+#define PCA6416_POLARITY_INVERSION_PORT_0 0x04 /* read/write */
+#define PCA6416_POLARITY_INVERSION_PORT_1 0x05 /* read/write */
+#define PCA6416_CONFIGURATION_PORT_0 0x06 /* read/write */
+#define PCA6416_CONFIGURATION_PORT_1 0x07 /* read/write */
+
+
+#define TEST_ID "pca_i2c_gpio-test"
+#define PCA_CONFIG_BYTE 0x55
+#define PCA_CONFIG_BYTE_UPPER 0xAA
+#define PCA_CONFIG_WORD 0xAA55
+
+static uint16_t qmp_pca_gpio_get(const char *id, const char *property)
+{
+ QDict *response;
+ uint16_t ret;
+ response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
+ "'property': %s } }", id, property);
+ g_assert(qdict_haskey(response, "return"));
+ ret = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
+ qobject_unref(response);
+ return ret;
+}
+
+static void qmp_pca_gpio_set(const char *id, const char *property,
+ uint16_t value)
+{
+ QDict *response;
+
+ response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
+ "'property': %s, 'value': %u } }",
+ id, property, value);
+ g_assert(qdict_haskey(response, "return"));
+ qobject_unref(response);
+}
+
+static void test_set_input(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
+ uint8_t value;
+ uint16_t qmp_value;
+ /* configure pins to be inputs */
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_0, 0xFF);
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_1, 0xFF);
+
+ qmp_pca_gpio_set(TEST_ID, "gpio_input", 0xAAAA);
+ value = i2c_get8(i2cdev, PCA6416_INPUT_PORT_0);
+ g_assert_cmphex(value, ==, 0xAA);
+ value = i2c_get8(i2cdev, PCA6416_INPUT_PORT_1);
+ g_assert_cmphex(value, ==, 0xAA);
+
+ qmp_value = qmp_pca_gpio_get(TEST_ID, "gpio_input");
+ g_assert_cmphex(qmp_value, ==, 0xAAAA);
+}
+static void test_config(void *obj, void *data, QGuestAllocator *alloc)
+{
+
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
+ uint8_t value;
+ uint16_t qmp_value;
+ /* configure half the pins to be inputs */
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_0, PCA_CONFIG_BYTE);
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_1, PCA_CONFIG_BYTE_UPPER);
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_0);
+ g_assert_cmphex(value, ==, PCA_CONFIG_BYTE);
+
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_1);
+ g_assert_cmphex(value, ==, PCA_CONFIG_BYTE_UPPER);
+
+ /* the pins that match the config should be set, the rest are undef */
+ qmp_pca_gpio_set(TEST_ID, "gpio_input", 0xFFFF);
+ value = i2c_get8(i2cdev, PCA6416_INPUT_PORT_0);
+ g_assert_cmphex(value & PCA_CONFIG_BYTE, ==, 0x55);
+ value = i2c_get8(i2cdev, PCA6416_INPUT_PORT_1);
+ g_assert_cmphex(value & PCA_CONFIG_BYTE_UPPER, ==, 0xAA);
+ qmp_value = qmp_pca_gpio_get(TEST_ID, "gpio_input");
+ g_assert_cmphex(qmp_value & PCA_CONFIG_WORD, ==, 0xAA55);
+
+ /*
+ * i2c will return the value written to the output register, not the values
+ * of the output pins, so we check only the configured pins
+ */
+ qmp_pca_gpio_set(TEST_ID, "gpio_output", 0xFFFF);
+ value = i2c_get8(i2cdev, PCA6416_OUTPUT_PORT_0);
+ g_assert_cmphex(value & ~PCA_CONFIG_BYTE, ==, 0xAA);
+ value = i2c_get8(i2cdev, PCA6416_OUTPUT_PORT_1);
+ g_assert_cmphex(value & ~PCA_CONFIG_BYTE_UPPER, ==, 0x55);
+
+ qmp_value = qmp_pca_gpio_get(TEST_ID, "gpio_output");
+ g_assert_cmphex(qmp_value & ~PCA_CONFIG_WORD, ==, 0x55AA);
+}
+
+static void test_set_output(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
+ uint8_t value;
+ uint16_t qmp_value;
+ /* configure pins to be outputs */
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_0, 0);
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_1, 0);
+
+ qmp_pca_gpio_set(TEST_ID, "gpio_output", 0xBB55);
+ value = i2c_get8(i2cdev, PCA6416_OUTPUT_PORT_0);
+ g_assert_cmphex(value, ==, 0x55);
+ value = i2c_get8(i2cdev, PCA6416_OUTPUT_PORT_1);
+ g_assert_cmphex(value, ==, 0xBB);
+
+ qmp_value = qmp_pca_gpio_get(TEST_ID, "gpio_output");
+ g_assert_cmphex(qmp_value, ==, 0xBB55);
+}
+
+static void test_tx_rx(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
+ uint8_t value;
+
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_0, 0xFF);
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_1, 0xFF);
+ i2c_set8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_0, 0);
+ i2c_set8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_1, 0);
+
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_0);
+ g_assert_cmphex(value, ==, 0xFF);
+
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_1);
+ g_assert_cmphex(value, ==, 0xFF);
+
+ value = i2c_get8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_0);
+ g_assert_cmphex(value, ==, 0);
+
+ value = i2c_get8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_1);
+ g_assert_cmphex(value, ==, 0);
+
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_0, 0xAB);
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_0);
+ g_assert_cmphex(value, ==, 0xAB);
+
+ i2c_set8(i2cdev, PCA6416_CONFIGURATION_PORT_1, 0xBC);
+ value = i2c_get8(i2cdev, PCA6416_CONFIGURATION_PORT_1);
+ g_assert_cmphex(value, ==, 0xBC);
+
+ i2c_set8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_0, 0xAB);
+ value = i2c_get8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_0);
+ g_assert_cmphex(value, ==, 0xAB);
+
+ i2c_set8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_1, 0x7C);
+ value = i2c_get8(i2cdev, PCA6416_POLARITY_INVERSION_PORT_1);
+ g_assert_cmphex(value, ==, 0x7C);
+
+}
+
+static void pca_i2c_gpio_register_nodes(void)
+{
+ QOSGraphEdgeOptions opts = {
+ .extra_device_opts = "id=" TEST_ID ",address=0x78"
+ };
+ add_qi2c_address(&opts, &(QI2CAddress) { 0x78 });
+ g_test_set_nonfatal_assertions();
+
+ qos_node_create_driver("pca6416", i2c_device_create);
+ qos_node_consumes("pca6416", "i2c-bus", &opts);
+
+ qos_add_test("tx-rx", "pca6416", test_tx_rx, NULL);
+ qos_add_test("set_output_gpio", "pca6416", test_set_output, NULL);
+ qos_add_test("set_input_gpio", "pca6416", test_set_input, NULL);
+ qos_add_test("follow_gpio_config", "pca6416", test_config, NULL);
+}
+libqos_init(pca_i2c_gpio_register_nodes);
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/6] hw/gpio: add PCA9536 i2c gpio expander
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
2024-11-07 19:54 ` [PATCH 2/6] hw/gpio: add PCA953x i2c GPIO expanders Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
2024-11-07 19:54 ` [PATCH 4/6] hw/i2c: add canonical path to i2c event traces Titus Rwantare
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
This device has the same register layout as the pca9538, but 4 fewer
gpio pins. This commit lowers the number of pins initialised, and reuses
the pca9538 logic.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/gpio/pca_i2c_gpio.c | 18 ++++++++++++++++++
include/hw/gpio/pca_i2c_gpio.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/hw/gpio/pca_i2c_gpio.c b/hw/gpio/pca_i2c_gpio.c
index 2486c620e3..b911187e34 100644
--- a/hw/gpio/pca_i2c_gpio.c
+++ b/hw/gpio/pca_i2c_gpio.c
@@ -336,6 +336,19 @@ static void pca9538_gpio_class_init(ObjectClass *klass, void *data)
k->send = pca953x_send;
}
+static void pca9536_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ PCAGPIOClass *pc = PCA_I2C_GPIO_CLASS(klass);
+
+ dc->desc = "PCA9536 4-bit I/O expander";
+ pc->num_pins = PCA9536_NUM_PINS;
+
+ k->recv = pca953x_recv;
+ k->send = pca953x_send;
+}
+
static void pca_i2c_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -386,6 +399,11 @@ static const TypeInfo pca_gpio_types[] = {
.parent = TYPE_PCA_I2C_GPIO,
.class_init = pca9538_gpio_class_init,
},
+ {
+ .name = TYPE_PCA9536_GPIO,
+ .parent = TYPE_PCA_I2C_GPIO,
+ .class_init = pca9536_gpio_class_init,
+ },
};
DEFINE_TYPES(pca_gpio_types);
diff --git a/include/hw/gpio/pca_i2c_gpio.h b/include/hw/gpio/pca_i2c_gpio.h
index 61e5853c24..f325563dc7 100644
--- a/include/hw/gpio/pca_i2c_gpio.h
+++ b/include/hw/gpio/pca_i2c_gpio.h
@@ -21,6 +21,7 @@
#define PCA_I2C_MAX_PINS 16
#define PCA6416_NUM_PINS 16
#define PCA9538_NUM_PINS 8
+#define PCA9536_NUM_PINS 4
typedef struct PCAGPIOClass {
I2CSlaveClass parent;
@@ -64,5 +65,6 @@ OBJECT_DECLARE_TYPE(PCAGPIOState, PCAGPIOClass, PCA_I2C_GPIO)
#define TYPE_PCA6416_GPIO "pca6416"
#define TYPE_PCA9538_GPIO "pca9538"
+#define TYPE_PCA9536_GPIO "pca9536"
#endif
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/6] hw/i2c: add canonical path to i2c event traces
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
` (2 preceding siblings ...)
2024-11-07 19:54 ` [PATCH 3/6] hw/gpio: add PCA9536 i2c gpio expander Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
2024-11-08 14:23 ` Corey Minyard
2024-11-07 19:54 ` [PATCH 5/6] hw/arm: imply I2C_DEVICES on NPCM7xx Titus Rwantare
2024-11-07 19:54 ` [PATCH 6/6] hw/arm: add Quanta GSZ bmc machine Titus Rwantare
5 siblings, 1 reply; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/i2c/core.c | 8 +++++---
hw/i2c/trace-events | 2 +-
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 4cf30b2c86..d238311776 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -161,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address,
start condition. */
if (sc->event) {
- trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async",
+ trace_i2c_event(DEVICE(s)->canonical_path,
+ event == I2C_START_SEND ? "start" : "start_async",
s->address);
rv = sc->event(s, event);
if (rv && !bus->broadcast) {
@@ -244,7 +245,7 @@ void i2c_end_transfer(I2CBus *bus)
I2CSlave *s = node->elt;
sc = I2C_SLAVE_GET_CLASS(s);
if (sc->event) {
- trace_i2c_event("finish", s->address);
+ trace_i2c_event(DEVICE(s)->canonical_path, "finish", s->address);
sc->event(s, I2C_FINISH);
}
QLIST_REMOVE(node, next);
@@ -321,7 +322,8 @@ void i2c_nack(I2CBus *bus)
QLIST_FOREACH(node, &bus->current_devs, next) {
sc = I2C_SLAVE_GET_CLASS(node->elt);
if (sc->event) {
- trace_i2c_event("nack", node->elt->address);
+ trace_i2c_event(DEVICE(node->elt)->canonical_path,
+ "nack", node->elt->address);
sc->event(node->elt, I2C_NACK);
}
}
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index f708a7ace1..e5f2dc643e 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -9,7 +9,7 @@ bitbang_i2c_data(unsigned clk, unsigned dat, unsigned old_out, unsigned new_out)
# core.c
-i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
+i2c_event(const char *id, const char *event, uint8_t address) "%s: %s(addr:0x%02x)"
i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%02x"
i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] hw/arm: imply I2C_DEVICES on NPCM7xx
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
` (3 preceding siblings ...)
2024-11-07 19:54 ` [PATCH 4/6] hw/i2c: add canonical path to i2c event traces Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
2024-11-07 19:54 ` [PATCH 6/6] hw/arm: add Quanta GSZ bmc machine Titus Rwantare
5 siblings, 0 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/arm/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1b25e73578..30480dad7b 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -465,6 +465,7 @@ config NPCM7XX
bool
default y
depends on TCG && ARM
+ imply I2C_DEVICES
select A9MPCORE
select ADM1266
select ADM1272
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/6] hw/arm: add Quanta GSZ bmc machine
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
` (4 preceding siblings ...)
2024-11-07 19:54 ` [PATCH 5/6] hw/arm: imply I2C_DEVICES on NPCM7xx Titus Rwantare
@ 2024-11-07 19:54 ` Titus Rwantare
5 siblings, 0 replies; 10+ messages in thread
From: Titus Rwantare @ 2024-11-07 19:54 UTC (permalink / raw)
To: peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg,
Titus Rwantare
This patch adds the quanta-gsz-bmc target, a current Google machine of
the day. This machine will be used as a platform to enable features such
as the PECI bmc interface, and Intel eSPI virtual wire interface in
QEMU.
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/arm/npcm7xx_boards.c | 160 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 160 insertions(+)
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
index e229efb447..85c3f8e9a0 100644
--- a/hw/arm/npcm7xx_boards.c
+++ b/hw/arm/npcm7xx_boards.c
@@ -48,6 +48,8 @@
#define NPCM750_EVB_POWER_ON_STRAPS ( \
NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_J2EN)
#define QUANTA_GSJ_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT
+#define QUANTA_GSZ_POWER_ON_STRAPS ( \
+ NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_SFAB)
#define QUANTA_GBS_POWER_ON_STRAPS ( \
NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_SFAB)
#define KUDO_BMC_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT
@@ -269,6 +271,129 @@ static void quanta_gsj_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
}
+static void quanta_gsz_i2c_init(NPCM7xxState *soc)
+{
+ DeviceState *dev;
+ I2CSlave *i2c_mux;
+
+ /* i2c1 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1), TYPE_PCA9548,
+ 0x75);
+ /* pca6416@0x20 */
+ dev = DEVICE(i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 3),
+ "pca6416", 0x20));
+ object_property_set_uint(OBJECT(dev), "gpio_config", 0xF00, &error_abort);
+ object_property_set_uint(OBJECT(dev), "gpio_input", 0xF00, &error_abort);
+
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1),
+ TYPE_PCA9548, 0x77);
+
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), "raa229004", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 1), "raa229004", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "isl69260", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 3), "isl69260", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 4), "isl69260", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 5), "isl69260", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 6), "adm1272", 0x1f);
+
+ /* i2c2 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 2),
+ TYPE_PCA9548, 0x77);
+ /* - channel 0: tps546d24 @25
+ * - channel 1: delta,dps800 @69
+ */
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 1), "raa228000", 0x68);
+ /* - channel 2: delta,dps800 @68 */
+ /* max31725 is compatible with tmp105. */
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 4), "tmp105", 0x5c);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 5), "tmp105", 0x5c);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 6), "tmp105", 0x5c);
+
+ /* i2c3 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 3), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c4 */
+ /* mobo_fru_1 */
+ at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 4), 0x50, 8192);
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 4),
+ TYPE_PCA9548, 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), "max34451", 0x59);
+ /* mobo_fru_2 */
+ at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 2), 0x55, 32768);
+
+ dev = DEVICE(i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 3),
+ "pca6416", 0x20));
+ object_property_set_uint(OBJECT(dev), "gpio_config", 0x4000, &error_abort);
+ object_property_set_uint(OBJECT(dev), "gpio_input", 0x4000, &error_abort);
+
+ dev = DEVICE(i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 4),
+ "pca6416", 0x20));
+ object_property_set_uint(OBJECT(dev), "gpio_config", 0xFFFF, &error_abort);
+ object_property_set_uint(OBJECT(dev), "gpio_input", 0x0000, &error_abort);
+
+ /* pdb_fru */
+ at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 6), 0x55, 8192);
+
+ /* i2c5 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 5), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c6 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 6), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c7 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 7), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c8 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 8), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c9 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 9), TYPE_PCA9548,
+ 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c10 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 10),
+ TYPE_PCA9548, 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 1), "pca9538", 0x72);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+ /* i2c11 */
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 11),
+ TYPE_PCA9548, 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), "pca9538", 0x72);
+
+ /* i2c12 */
+
+ /* i2c13 */
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 13), "pca6416", 0x22);
+
+ /* i2c14 */
+ /* LEDs and PE Resets */
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 14), "pca6416", 0x20);
+
+ /* bmc_fru_1 */
+ at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 14), 0x55, 8192);
+
+ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 14),
+ TYPE_PCA9548, 0x77);
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), "max34451", 0x59);
+
+ /* max31725 is compatible with tmp105 */
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 4), "tmp105", 0x5c);
+
+ /* i2c15 */
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 15), TYPE_PCA9546, 0x75);
+}
+
static void quanta_gbs_i2c_init(NPCM7xxState *soc)
{
/*
@@ -392,6 +517,25 @@ static void quanta_gsj_init(MachineState *machine)
npcm7xx_load_kernel(machine, soc);
}
+static void quanta_gsz_init(MachineState *machine)
+{
+ NPCM7xxState *soc;
+
+ soc = npcm7xx_create_soc(machine, QUANTA_GSZ_POWER_ON_STRAPS);
+ npcm7xx_connect_dram(soc, machine->ram);
+ qdev_realize(DEVICE(soc), NULL, &error_fatal);
+
+ npcm7xx_load_bootrom(machine, soc);
+ npcm7xx_connect_flash(&soc->fiu[0], 0, "mx66u51235f",
+ drive_get(IF_MTD, 0, 0));
+ npcm7xx_connect_flash(&soc->fiu[1], 0, "mx66u51235f",
+ drive_get(IF_MTD, 3, 0));
+
+ quanta_gsz_i2c_init(soc);
+ sdhci_attach_drive(&soc->mmc.sdhci, 0);
+ npcm7xx_load_kernel(machine, soc);
+}
+
static void quanta_gbs_init(MachineState *machine)
{
NPCM7xxState *soc;
@@ -496,6 +640,18 @@ static void gsj_machine_class_init(ObjectClass *oc, void *data)
mc->default_ram_size = 512 * MiB;
};
+static void gsz_machine_class_init(ObjectClass *oc, void *data)
+{
+ NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
+
+ mc->desc = "Quanta GSZ (Cortex-A9)";
+ mc->init = quanta_gsz_init;
+ mc->default_ram_size = 1 * GiB;
+}
+
static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
@@ -548,6 +704,10 @@ static const TypeInfo npcm7xx_machine_types[] = {
.name = MACHINE_TYPE_NAME("quanta-gsj"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = gsj_machine_class_init,
+ }, {
+ .name = MACHINE_TYPE_NAME("quanta-gsz-bmc"),
+ .parent = TYPE_NPCM7XX_MACHINE,
+ .class_init = gsz_machine_class_init,
}, {
.name = MACHINE_TYPE_NAME("quanta-gbs-bmc"),
.parent = TYPE_NPCM7XX_MACHINE,
--
2.47.0.277.g8800431eea-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 4/6] hw/i2c: add canonical path to i2c event traces
2024-11-07 19:54 ` [PATCH 4/6] hw/i2c: add canonical path to i2c event traces Titus Rwantare
@ 2024-11-08 14:23 ` Corey Minyard
0 siblings, 0 replies; 10+ messages in thread
From: Corey Minyard @ 2024-11-08 14:23 UTC (permalink / raw)
To: Titus Rwantare
Cc: peter.maydell, minyard, clg, qemu-arm, qemu-devel, philmd,
venture, wuhaotsh, milesg
On Thu, Nov 07, 2024 at 07:54:51PM +0000, Titus Rwantare wrote:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> Signed-off-by: Titus Rwantare <titusr@google.com>
Acked-by: Corey Minyard <cminyard@mvista.com>
> ---
> hw/i2c/core.c | 8 +++++---
> hw/i2c/trace-events | 2 +-
> 2 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/hw/i2c/core.c b/hw/i2c/core.c
> index 4cf30b2c86..d238311776 100644
> --- a/hw/i2c/core.c
> +++ b/hw/i2c/core.c
> @@ -161,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address,
> start condition. */
>
> if (sc->event) {
> - trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async",
> + trace_i2c_event(DEVICE(s)->canonical_path,
> + event == I2C_START_SEND ? "start" : "start_async",
> s->address);
> rv = sc->event(s, event);
> if (rv && !bus->broadcast) {
> @@ -244,7 +245,7 @@ void i2c_end_transfer(I2CBus *bus)
> I2CSlave *s = node->elt;
> sc = I2C_SLAVE_GET_CLASS(s);
> if (sc->event) {
> - trace_i2c_event("finish", s->address);
> + trace_i2c_event(DEVICE(s)->canonical_path, "finish", s->address);
> sc->event(s, I2C_FINISH);
> }
> QLIST_REMOVE(node, next);
> @@ -321,7 +322,8 @@ void i2c_nack(I2CBus *bus)
> QLIST_FOREACH(node, &bus->current_devs, next) {
> sc = I2C_SLAVE_GET_CLASS(node->elt);
> if (sc->event) {
> - trace_i2c_event("nack", node->elt->address);
> + trace_i2c_event(DEVICE(node->elt)->canonical_path,
> + "nack", node->elt->address);
> sc->event(node->elt, I2C_NACK);
> }
> }
> diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
> index f708a7ace1..e5f2dc643e 100644
> --- a/hw/i2c/trace-events
> +++ b/hw/i2c/trace-events
> @@ -9,7 +9,7 @@ bitbang_i2c_data(unsigned clk, unsigned dat, unsigned old_out, unsigned new_out)
>
> # core.c
>
> -i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
> +i2c_event(const char *id, const char *event, uint8_t address) "%s: %s(addr:0x%02x)"
> i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
> i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%02x"
> i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
> --
> 2.47.0.277.g8800431eea-goog
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/6] bitops.h: add deposit16 function
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
@ 2024-11-11 22:03 ` Miles Glenn
2024-11-13 15:46 ` Peter Maydell
1 sibling, 0 replies; 10+ messages in thread
From: Miles Glenn @ 2024-11-11 22:03 UTC (permalink / raw)
To: Titus Rwantare, peter.maydell, minyard, clg
Cc: qemu-arm, qemu-devel, philmd, venture, wuhaotsh, milesg
Reviewed-by: Glenn Miles <milesg@linux.ibm.com>
On Thu, 2024-11-07 at 19:54 +0000, Titus Rwantare wrote:
> Makes it more explicit that 16 bit values are being used
>
> Signed-off-by: Titus Rwantare <titusr@google.com>
> ---
> include/qemu/bitops.h | 26 ++++++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
>
> diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
> index 2c0a2fe751..05179e3ded 100644
> --- a/include/qemu/bitops.h
> +++ b/include/qemu/bitops.h
> @@ -459,6 +459,32 @@ static inline int64_t sextract64(uint64_t value,
> int start, int length)
> return ((int64_t)(value << (64 - length - start))) >> (64 -
> length);
> }
>
> +/**
> + * deposit16:
> + * @value: initial value to insert bit field into
> + * @start: the lowest bit in the bit field (numbered from 0)
> + * @length: the length of the bit field
> + * @fieldval: the value to insert into the bit field
> + *
> + * Deposit @fieldval into the 16 bit @value at the bit field
> specified
> + * by the @start and @length parameters, and return the modified
> + * @value. Bits of @value outside the bit field are not modified.
> + * Bits of @fieldval above the least significant @length bits are
> + * ignored. The bit field must lie entirely within the 16 bit word.
> + * It is valid to request that all 16 bits are modified (ie @length
> + * 16 and @start 0).
> + *
> + * Returns: the modified @value.
> + */
> +static inline uint16_t deposit16(uint16_t value, int start, int
> length,
> + uint16_t fieldval)
> +{
> + uint16_t mask;
> + assert(start >= 0 && length > 0 && length <= 16 - start);
> + mask = (~0U >> (16 - length)) << start;
> + return (value & ~mask) | ((fieldval << start) & mask);
> +}
> +
> /**
> * deposit32:
> * @value: initial value to insert bit field into
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/6] bitops.h: add deposit16 function
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
2024-11-11 22:03 ` Miles Glenn
@ 2024-11-13 15:46 ` Peter Maydell
1 sibling, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2024-11-13 15:46 UTC (permalink / raw)
To: Titus Rwantare
Cc: minyard, clg, qemu-arm, qemu-devel, philmd, venture, wuhaotsh,
milesg
On Thu, 7 Nov 2024 at 19:54, Titus Rwantare <titusr@google.com> wrote:
>
> Makes it more explicit that 16 bit values are being used
>
> Signed-off-by: Titus Rwantare <titusr@google.com>
> ---
> include/qemu/bitops.h | 26 ++++++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
>
> diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
> index 2c0a2fe751..05179e3ded 100644
> --- a/include/qemu/bitops.h
> +++ b/include/qemu/bitops.h
> @@ -459,6 +459,32 @@ static inline int64_t sextract64(uint64_t value, int start, int length)
> return ((int64_t)(value << (64 - length - start))) >> (64 - length);
> }
>
> +/**
> + * deposit16:
> + * @value: initial value to insert bit field into
> + * @start: the lowest bit in the bit field (numbered from 0)
> + * @length: the length of the bit field
> + * @fieldval: the value to insert into the bit field
> + *
> + * Deposit @fieldval into the 16 bit @value at the bit field specified
> + * by the @start and @length parameters, and return the modified
> + * @value. Bits of @value outside the bit field are not modified.
> + * Bits of @fieldval above the least significant @length bits are
> + * ignored. The bit field must lie entirely within the 16 bit word.
> + * It is valid to request that all 16 bits are modified (ie @length
> + * 16 and @start 0).
> + *
> + * Returns: the modified @value.
> + */
Why do we need this rather than using deposit32()?
See also the comments in this thread
https://lore.kernel.org/qemu-devel/CAFEAcA9H=w29-8CQStYYNwEU=OEB=NzxpioaqGEgSpc4KnPOHQ@mail.gmail.com/
where a deposit8() was proposed.
thanks
-- PMM
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-11-13 15:47 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-07 19:54 [PATCH 0/6] Add Quanta GSZ BMC machine and PCA I2C GPIO expanders Titus Rwantare
2024-11-07 19:54 ` [PATCH 1/6] bitops.h: add deposit16 function Titus Rwantare
2024-11-11 22:03 ` Miles Glenn
2024-11-13 15:46 ` Peter Maydell
2024-11-07 19:54 ` [PATCH 2/6] hw/gpio: add PCA953x i2c GPIO expanders Titus Rwantare
2024-11-07 19:54 ` [PATCH 3/6] hw/gpio: add PCA9536 i2c gpio expander Titus Rwantare
2024-11-07 19:54 ` [PATCH 4/6] hw/i2c: add canonical path to i2c event traces Titus Rwantare
2024-11-08 14:23 ` Corey Minyard
2024-11-07 19:54 ` [PATCH 5/6] hw/arm: imply I2C_DEVICES on NPCM7xx Titus Rwantare
2024-11-07 19:54 ` [PATCH 6/6] hw/arm: add Quanta GSZ bmc machine Titus Rwantare
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).