[PATCH v7 6/8] aspeed/soc: Correct GPIO irq 130 for AST2700

2024-10-01 Thread Jamin Lin via
The register set of GPIO have a significant change since AST2700.
Each GPIO pin has their own individual control register and users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on in the
same one control register.

AST2700 does not have GPIO18_XXX registers for GPIO 1.8v, removes
ASPEED_DEV_GPIO_1_8V. It is enough to only have ASPEED_DEV_GPIO
device in AST2700.

The AST2700 GPIO controller interrupt is connected to GICINT130_INTC at
bit 18. Therefore, correct GPIO irq 130.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/arm/aspeed_ast27x0.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..99135edc1e 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -87,8 +87,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +123,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
-- 
2.34.1




[PATCH v7 5/8] hw/gpio/aspeed: Add AST2700 support

2024-10-01 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller with maximum 212
control pins, which are 27 groups. (H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs, one register is used for setting
one function for one set which are 32 pins and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register.
In other words, users are able to set one GPIO pin’s direction,
interrupt enable, input mask and so on in the same one register.

Currently, aspeed_gpio_read and aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce new aspeed_gpio_2700_read and aspeed_gpio_2700_write callback
functions and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 380 ++
 1 file changed, 380 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 16c18ea2f7..a5b3f454e8 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -970,6 +1002,316 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extr

[PATCH v7 4/8] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-10-01 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in reg_value. However, if the extracted
bit is clear then the value of the corresponding bit in reg_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). reg_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the
reg_value, using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending == 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending == 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
Suggested-by: Andrew Jeffery 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 8725606aec..16c18ea2f7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
   FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
-/* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+/* interrupt status */
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+/* pending is either 1 or 0 for a 1-bit field */
+pending = extract32(set->int_status, pin_idx, 1);
+
+assert(s->pending >= pending);
+
+/* No change to s->pending if pending is 0 */
+s->pending -= pending;
+
+/*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v7 7/8] aspeed/soc: Support GPIO for AST2700

2024-10-01 Thread Jamin Lin via
Add GPIO model for AST2700 GPIO support. The GPIO controller registers base
address is start at 0x14C0_B000 and its address space is 0x1000.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/arm/aspeed_ast27x0.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 99135edc1e..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -372,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -657,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v7 3/8] hw/gpio/aspeed: Support different memory region ops

2024-10-01 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing read and write callbacks
to be used when I/O is performed on the GPIO region.

Besides, in the previous design of ASPEED SOCs, one register is used for
setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 564459ad4f..8725606aec 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1046,7 +1046,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1143,6 +1144,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1155,6 +1157,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1167,6 +1170,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1179,6 +1183,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v7 8/8] tests/qtest:ast2700-gpio-test: Add GPIO test case for AST2700

2024-10-01 Thread Jamin Lin via
Add GPIO test cases to test output and input pins from A0 to D7 for AST2700.

Signed-off-by: Jamin Lin 
---
 tests/qtest/ast2700-gpio-test.c | 95 +
 tests/qtest/meson.build |  3 ++
 2 files changed, 98 insertions(+)
 create mode 100644 tests/qtest/ast2700-gpio-test.c

diff --git a/tests/qtest/ast2700-gpio-test.c b/tests/qtest/ast2700-gpio-test.c
new file mode 100644
index 00..9275845564
--- /dev/null
+++ b/tests/qtest/ast2700-gpio-test.c
@@ -0,0 +1,95 @@
+/*
+ * QTest testcase for the ASPEED AST2700 GPIO Controller.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "qapi/qmp/qdict.h"
+#include "libqtest-single.h"
+
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
+static void test_output_pins(const char *machine, const uint32_t base)
+{
+QTestState *s = qtest_init(machine);
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+offset = base + (pin * 4);
+
+/* output direction and output hi */
+qtest_writel(s, offset, 0x0003);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0003);
+
+/* output direction and output low */
+qtest_writel(s, offset, 0x0002);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0002);
+pin++;
+}
+}
+
+qtest_quit(s);
+}
+
+static void test_input_pins(const char *machine, const uint32_t base)
+{
+QTestState *s = qtest_init(machine);
+char name[16];
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+sprintf(name, "gpio%c%d", c, i);
+offset = base + (pin * 4);
+/* input direction */
+qtest_writel(s, offset, 0);
+
+/* set input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x2000);
+
+/* clear input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0);
+pin++;
+}
+}
+
+qtest_quit(s);
+}
+
+static void test_2700_input_pins(void)
+{
+test_input_pins("-machine ast2700-evb",
+AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+static void test_2700_output_pins(void)
+{
+test_output_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+int main(int argc, char **argv)
+{
+g_test_init(&argc, &argv, NULL);
+
+qtest_add_func("/ast2700/gpio/input_pins", test_2700_input_pins);
+qtest_add_func("/ast2700/gpio/output_pins", test_2700_output_pins);
+
+return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 310865e49c..e1b62d34d8 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -209,6 +209,8 @@ qtests_aspeed = \
   ['aspeed_hace-test',
'aspeed_smc-test',
'aspeed_gpio-test']
+qtests_aspeed64 = \
+  ['ast2700-gpio-test']
 
 qtests_stm32l4x5 = \
   ['stm32l4x5_exti-test',
@@ -247,6 +249,7 @@ qtests_aarch64 = \
   (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 
'bcm2835-i2c-test'] : []) +  \
   (config_all_accel.has_key('CONFIG_TCG') and  
  \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : 
[]) + \
+  (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
   ['arm-cpu-features',
'numa-test',
'boot-serial-test',
-- 
2.34.1




[PATCH v7 0/8] Support GPIO for AST2700

2024-10-01 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestions
v3: Remove nested conditionals and adds reviewer suggestions
v4: Add test cases to test GPIO for AST2700 and update commit messages
v5: Fix aspeed_gpio-test test failed if arch is arm
v6: Add to test aspeed_gpio-test for aarch64
v7: Move GPIO testcase for AST2700 to ast2700-gpio-test.c

Jamin Lin (8):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Correct GPIO irq 130 for AST2700
  aspeed/soc: Support GPIO for AST2700
  tests/qtest:ast2700-gpio-test: Add GPIO test case for AST2700

 hw/arm/aspeed_ast27x0.c |  18 +-
 hw/gpio/aspeed_gpio.c   | 427 ++--
 include/hw/gpio/aspeed_gpio.h   |   4 +-
 tests/qtest/ast2700-gpio-test.c |  95 +++
 tests/qtest/meson.build |   3 +
 5 files changed, 528 insertions(+), 19 deletions(-)
 create mode 100644 tests/qtest/ast2700-gpio-test.c

-- 
2.34.1




[PATCH v7 1/8] hw/gpio/aspeed: Fix coding style

2024-10-01 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 6 +++---
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..00fb72a509 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -629,7 +630,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr 
offset, uint32_t size)
 static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
 uint64_t data, uint32_t size)
 {
-
 AspeedGPIOState *s = ASPEED_GPIO(opaque);
 AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
 const GPIOSetProperties *props;
@@ -963,7 +963,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH v7 2/8] hw/gpio/aspeed: Support to set the different memory size

2024-10-01 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs, a GPIO controller owns 4KB of
register space for AST2700, AST2500, AST2400 and AST1030; owns 2KB of
register space for AST2600 1.8v and owns 2KB of register space for
AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 00fb72a509..564459ad4f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1130,6 +1130,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1142,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1154,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1166,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1178,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v6 7/8] aspeed/soc: Support GPIO for AST2700

2024-09-30 Thread Jamin Lin via
Add GPIO model for AST2700 GPIO support. The GPIO controller registers base
address is start at 0x14C0_B000 and its address space is 0x1000.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 99135edc1e..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -372,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -657,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v6 4/8] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-09-30 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in reg_value. However, if the extracted
bit is clear then the value of the corresponding bit in reg_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). reg_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the
reg_value, using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending == 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending == 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
Suggested-by: Andrew Jeffery 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 8725606aec..16c18ea2f7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
   FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
-/* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+/* interrupt status */
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+/* pending is either 1 or 0 for a 1-bit field */
+pending = extract32(set->int_status, pin_idx, 1);
+
+assert(s->pending >= pending);
+
+/* No change to s->pending if pending is 0 */
+s->pending -= pending;
+
+/*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v6 0/8] Support GPIO for AST2700

2024-09-30 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestions
v3: remove nested conditionals and adds reviewer suggestions
v4: add test cases to test GPIO for AST2700 and update commit messages
v5: fix aspeed_gpio-test test failed if arch is arm
v6: add to test aspeed_gpio-test for aarch64

Jamin Lin (8):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Correct GPIO irq 130 for AST2700
  aspeed/soc: Support GPIO for AST2700
  hw/gpio/aspeed: Add test case for AST2700

 hw/arm/aspeed_ast27x0.c|  18 +-
 hw/gpio/aspeed_gpio.c  | 427 +++--
 include/hw/gpio/aspeed_gpio.h  |   4 +-
 tests/qtest/aspeed_gpio-test.c |  77 +-
 tests/qtest/meson.build|   3 +
 5 files changed, 506 insertions(+), 23 deletions(-)

-- 
2.34.1




[PATCH v6 5/8] hw/gpio/aspeed: Add AST2700 support

2024-09-30 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller with maximum 212
control pins, which are 27 groups. (H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs, one register is used for setting
one function for one set which are 32 pins and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register.
In other words, users are able to set one GPIO pin’s direction,
interrupt enable, input mask and so on in the same one register.

Currently, aspeed_gpio_read and aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce new aspeed_gpio_2700_read and aspeed_gpio_2700_write callback
functions and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 380 ++
 1 file changed, 380 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 16c18ea2f7..a5b3f454e8 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -970,6 +1002,316 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extr

[PATCH v6 8/8] hw/gpio/aspeed: Add test case for AST2700

2024-09-30 Thread Jamin Lin via
Add test case to test GPIO output and input pins from A0 to D7 for AST2700.

Signed-off-by: Jamin Lin 
---
 tests/qtest/aspeed_gpio-test.c | 77 --
 tests/qtest/meson.build|  3 ++
 2 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c
index d38f51d719..03b3b1c2b2 100644
--- a/tests/qtest/aspeed_gpio-test.c
+++ b/tests/qtest/aspeed_gpio-test.c
@@ -33,6 +33,10 @@
 #define GPIO_ABCD_DATA_VALUE 0x000
 #define GPIO_ABCD_DIRECTION  0x004
 
+/* AST2700 */
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
 static void test_set_colocated_pins(const void *data)
 {
 QTestState *s = (QTestState *)data;
@@ -72,17 +76,82 @@ static void test_set_input_pins(const void *data)
 g_assert_cmphex(value, ==, 0x);
 }
 
+static void test_2700_output_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+
+/* output direction and output hi */
+qtest_writel(s, offset, 0x0003);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0003);
+
+/* output direction and output low */
+qtest_writel(s, offset, 0x0002);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0002);
+pin++;
+}
+}
+}
+
+static void test_2700_input_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+char name[16];
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+sprintf(name, "gpio%c%d", c, i);
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+/* input direction */
+qtest_writel(s, offset, 0);
+
+/* set input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x2000);
+
+/* clear input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0);
+pin++;
+}
+}
+}
+
+
 int main(int argc, char **argv)
 {
+const char *arch = qtest_get_arch();
 QTestState *s;
 int r;
 
 g_test_init(&argc, &argv, NULL);
 
-s = qtest_init("-machine ast2600-evb");
-qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s,
-test_set_colocated_pins);
-qtest_add_data_func("/ast2600/gpio/set_input_pins", s, 
test_set_input_pins);
+if (strcmp(arch, "aarch64") == 0) {
+s = qtest_init("-machine ast2700-evb");
+qtest_add_data_func("/ast2700/gpio/input_pins",
+s, test_2700_input_pins);
+qtest_add_data_func("/ast2700/gpio/out_pins", s, 
test_2700_output_pins);
+} else {
+s = qtest_init("-machine ast2600-evb");
+qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s,
+test_set_colocated_pins);
+qtest_add_data_func("/ast2600/gpio/set_input_pins", s,
+test_set_input_pins);
+}
+
 r = g_test_run();
 qtest_quit(s);
 
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 310865e49c..292980e3ad 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -209,6 +209,8 @@ qtests_aspeed = \
   ['aspeed_hace-test',
'aspeed_smc-test',
'aspeed_gpio-test']
+qtests_aspeed64 = \
+  ['aspeed_gpio-test']
 
 qtests_stm32l4x5 = \
   ['stm32l4x5_exti-test',
@@ -247,6 +249,7 @@ qtests_aarch64 = \
   (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 
'bcm2835-i2c-test'] : []) +  \
   (config_all_accel.has_key('CONFIG_TCG') and  
  \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : 
[]) + \
+  (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
   ['arm-cpu-features',
'numa-test',
'boot-serial-test',
-- 
2.34.1




[PATCH v6 3/8] hw/gpio/aspeed: Support different memory region ops

2024-09-30 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing read and write callbacks
to be used when I/O is performed on the GPIO region.

Besides, in the previous design of ASPEED SOCs, one register is used for
setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 564459ad4f..8725606aec 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1046,7 +1046,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1143,6 +1144,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1155,6 +1157,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1167,6 +1170,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1179,6 +1183,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v6 2/8] hw/gpio/aspeed: Support to set the different memory size

2024-09-30 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs, a GPIO controller owns 4KB of
register space for AST2700, AST2500, AST2400 and AST1030; owns 2KB of
register space for AST2600 1.8v and owns 2KB of register space for
AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 00fb72a509..564459ad4f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1130,6 +1130,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1142,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1154,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1166,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1178,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v6 6/8] aspeed/soc: Correct GPIO irq 130 for AST2700

2024-09-30 Thread Jamin Lin via
The register set of GPIO have a significant change since AST2700.
Each GPIO pin has their own individual control register and users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on in the
same one control register.

AST2700 does not have GPIO18_XXX registers for GPIO 1.8v, removes
ASPEED_DEV_GPIO_1_8V. It is enough to only have ASPEED_DEV_GPIO
device in AST2700.

The AST2700 GPIO controller interrupt is connected to GICINT130_INTC at
bit 18. Therefore, correct GPIO irq 130.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..99135edc1e 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -87,8 +87,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +123,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
-- 
2.34.1




[PATCH v6 1/8] hw/gpio/aspeed: Fix coding style

2024-09-30 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 6 +++---
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..00fb72a509 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -629,7 +630,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr 
offset, uint32_t size)
 static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
 uint64_t data, uint32_t size)
 {
-
 AspeedGPIOState *s = ASPEED_GPIO(opaque);
 AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
 const GPIOSetProperties *props;
@@ -963,7 +963,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




RE: [PATCH v3 0/6] Support GPIO for AST2700

2024-09-29 Thread Jamin Lin via
Hi Konstantin

> Subject: Re: [PATCH v3 0/6] Support GPIO for AST2700
> 
> On Fri, Sep 27, 2024 at 06:29:22AM GMT, Jamin Lin wrote:
> > > Also, your emails have an invalid "From" field set to
> > > "qemu-devel@nongnu.org" when retrieved with the b4 command.
> 
> This is almost certainly done by the mailman list running on nongnu.org. It's 
> a
> very patch-hostile setting, so I'm surprised it's turned on at all.
> 
> > > I have been fixing them for a while. Could you please tell us how
> > > you send the patchsets ?
> > >
> > >
> > Command to send my patches as below.
> > git send-email -cc jamin_...@aspeedtech.com -cc
> > troy_...@aspeedtech.com -cc yunlin.t...@aspeedtech.com --to-cmd
> > "./scripts/get_maintainer.pl ../v3-patch/*.patch" ../v3-patch/*.patch
> > --no-smtp-auth
> 
> I suggest you generate your patches with --force-in-body-from (or set
> format.forceInBodyFrom in your .git/config for that repository).

Thanks for suggestion.

Will use this "--force-in-body-from" command to generate my patches.
Will send v6 patch for AST2700 GPIO and test this issue with my new patch 
format.

Jamin

> 
> -K


[PATCH v5 3/7] hw/gpio/aspeed: Support different memory region ops

2024-09-27 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing read and write callbacks
to be used when I/O is performed on the GPIO region.

Besides, in the previous design of ASPEED SOCs, one register is used for
setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 564459ad4f..8725606aec 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1046,7 +1046,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1143,6 +1144,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1155,6 +1157,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1167,6 +1170,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1179,6 +1183,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v5 4/7] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-09-27 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in reg_value. However, if the extracted
bit is clear then the value of the corresponding bit in reg_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). reg_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the
reg_value, using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending == 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending == 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
Suggested-by: Andrew Jeffery 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 8725606aec..16c18ea2f7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
   FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
-/* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+/* interrupt status */
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+/* pending is either 1 or 0 for a 1-bit field */
+pending = extract32(set->int_status, pin_idx, 1);
+
+assert(s->pending >= pending);
+
+/* No change to s->pending if pending is 0 */
+s->pending -= pending;
+
+/*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v5 2/7] hw/gpio/aspeed: Support to set the different memory size

2024-09-27 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs, a GPIO controller owns 4KB of
register space for AST2700, AST2500, AST2400 and AST1030; owns 2KB of
register space for AST2600 1.8v and owns 2KB of register space for
AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 00fb72a509..564459ad4f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1130,6 +1130,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1142,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1154,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1166,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1178,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v5 6/7] aspeed/soc: Support GPIO for AST2700 and correct irq 130

2024-09-27 Thread Jamin Lin via
The register set of GPIO have a significant change since AST2700.
Each GPIO pin has their own individual control register and users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on in the
same one control register.

AST2700 does not have GPIO18_XXX registers for GPIO 1.8v, removes
ASPEED_DEV_GPIO_1_8V. It is enough to only have ASPEED_DEV_GPIO
device in AST2700.

Add GPIO model for AST2700 GPIO support. The GPIO controller registers base
address is start at 0x14C0_B000 and its address space is 0x1000.

The AST2700 GPIO controller interrupt is connected to GICINT130_INTC at
bit 18. Therefore, correct GPIO irq 130.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
@@ -373,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -658,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v5 7/7] hw/gpio/aspeed: Add test case for AST2700

2024-09-27 Thread Jamin Lin via
Add test case to test GPIO output and input pins from A0 to D7 for AST2700.

Signed-off-by: Jamin Lin 
---
 tests/qtest/aspeed_gpio-test.c | 68 ++
 1 file changed, 68 insertions(+)

diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c
index d38f51d719..9d978b70e0 100644
--- a/tests/qtest/aspeed_gpio-test.c
+++ b/tests/qtest/aspeed_gpio-test.c
@@ -33,6 +33,10 @@
 #define GPIO_ABCD_DATA_VALUE 0x000
 #define GPIO_ABCD_DIRECTION  0x004
 
+/* AST2700 */
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
 static void test_set_colocated_pins(const void *data)
 {
 QTestState *s = (QTestState *)data;
@@ -72,8 +76,64 @@ static void test_set_input_pins(const void *data)
 g_assert_cmphex(value, ==, 0x);
 }
 
+static void test_2700_output_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+
+/* output direction and output hi */
+qtest_writel(s, offset, 0x0003);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0003);
+
+/* output direction and output low */
+qtest_writel(s, offset, 0x0002);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0002);
+pin++;
+}
+}
+}
+
+static void test_2700_input_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+char name[16];
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+sprintf(name, "gpio%c%d", c, i);
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+/* input direction */
+qtest_writel(s, offset, 0);
+
+/* set input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x2000);
+
+/* clear input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0);
+pin++;
+}
+}
+}
+
+
 int main(int argc, char **argv)
 {
+const char *arch = qtest_get_arch();
 QTestState *s;
 int r;
 
@@ -83,6 +143,14 @@ int main(int argc, char **argv)
 qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s,
 test_set_colocated_pins);
 qtest_add_data_func("/ast2600/gpio/set_input_pins", s, 
test_set_input_pins);
+
+if (strcmp(arch, "aarch64") == 0) {
+s = qtest_init("-machine ast2700-evb");
+qtest_add_data_func("/ast2700/gpio/input_pins",
+s, test_2700_input_pins);
+qtest_add_data_func("/ast2700/gpio/out_pins", s, 
test_2700_output_pins);
+}
+
 r = g_test_run();
 qtest_quit(s);
 
-- 
2.34.1




[PATCH v5 5/7] hw/gpio/aspeed: Add AST2700 support

2024-09-27 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller with maximum 212
control pins, which are 27 groups. (H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs, one register is used for setting
one function for one set which are 32 pins and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register.
In other words, users are able to set one GPIO pin’s direction,
interrupt enable, input mask and so on in the same one register.

Currently, aspeed_gpio_read and aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce new aspeed_gpio_2700_read and aspeed_gpio_2700_write callback
functions and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 380 ++
 1 file changed, 380 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 16c18ea2f7..a5b3f454e8 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -970,6 +1002,316 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extr

[PATCH v5 0/7] Support GPIO for AST2700

2024-09-27 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestions
v3: remove nested conditionals and adds reviewer suggestions
v4: add test cases to test GPIO for AST2700 and update commit messages
v5: fix aspeed_gpio-test test failed if arch is arm

Jamin Lin (7):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Support GPIO for AST2700 and correct irq 130
  hw/gpio/aspeed: Add test case for AST2700

 hw/arm/aspeed_ast27x0.c|  18 +-
 hw/gpio/aspeed_gpio.c  | 427 +++--
 include/hw/gpio/aspeed_gpio.h  |   4 +-
 tests/qtest/aspeed_gpio-test.c |  68 ++
 4 files changed, 498 insertions(+), 19 deletions(-)

-- 
2.34.1




[PATCH v5 1/7] hw/gpio/aspeed: Fix coding style

2024-09-27 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 6 +++---
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..00fb72a509 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -629,7 +630,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr 
offset, uint32_t size)
 static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
 uint64_t data, uint32_t size)
 {
-
 AspeedGPIOState *s = ASPEED_GPIO(opaque);
 AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
 const GPIOSetProperties *props;
@@ -963,7 +963,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH v4 3/7] hw/gpio/aspeed: Support different memory region ops

2024-09-27 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing read and write callbacks
to be used when I/O is performed on the GPIO region.

Besides, in the previous design of ASPEED SOCs, one register is used for
setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 564459ad4f..8725606aec 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1046,7 +1046,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1143,6 +1144,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1155,6 +1157,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1167,6 +1170,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1179,6 +1183,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v4 0/7] Support GPIO for AST2700

2024-09-27 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestions
v3: remove nested conditionals and adds reviewer suggestions
v4: add test cases to test GPIO for AST2700 and update commit messages

Jamin Lin (7):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Support GPIO for AST2700 and correct irq 130
  hw/gpio/aspeed: Add test case for AST2700

 hw/arm/aspeed_ast27x0.c|  18 +-
 hw/gpio/aspeed_gpio.c  | 427 +++--
 include/hw/gpio/aspeed_gpio.h  |   4 +-
 tests/qtest/aspeed_gpio-test.c |  64 +
 4 files changed, 494 insertions(+), 19 deletions(-)

-- 
2.34.1




[PATCH v4 6/7] aspeed/soc: Support GPIO for AST2700 and correct irq 130

2024-09-27 Thread Jamin Lin via
The register set of GPIO have a significant change since AST2700.
Each GPIO pin has their own individual control register and users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on in the
same one control register.

AST2700 does not have GPIO18_XXX registers for GPIO 1.8v, removes
ASPEED_DEV_GPIO_1_8V. It is enough to only have ASPEED_DEV_GPIO
device in AST2700.

Add GPIO model for AST2700 GPIO support. The GPIO controller registers base
address is start at 0x14C0_B000 and its address space is 0x1000.

The AST2700 GPIO controller interrupt is connected to GICINT130_INTC at
bit 18. Therefore, correct GPIO irq 130.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
@@ -373,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -658,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v4 2/7] hw/gpio/aspeed: Support to set the different memory size

2024-09-27 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs, a GPIO controller owns 4KB of
register space for AST2700, AST2500, AST2400 and AST1030; owns 2KB of
register space for AST2600 1.8v and owns 2KB of register space for
AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 00fb72a509..564459ad4f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1130,6 +1130,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1142,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1154,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1166,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1178,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v4 7/7] hw/gpio/aspeed: Add test case for AST2700

2024-09-27 Thread Jamin Lin via
Add test case to test GPIO output and input pins from A0 to D7 for AST2700.

Signed-off-by: Jamin Lin 
---
 tests/qtest/aspeed_gpio-test.c | 64 ++
 1 file changed, 64 insertions(+)

diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c
index d38f51d719..8ae42a8da5 100644
--- a/tests/qtest/aspeed_gpio-test.c
+++ b/tests/qtest/aspeed_gpio-test.c
@@ -33,6 +33,10 @@
 #define GPIO_ABCD_DATA_VALUE 0x000
 #define GPIO_ABCD_DIRECTION  0x004
 
+/* AST2700 */
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
 static void test_set_colocated_pins(const void *data)
 {
 QTestState *s = (QTestState *)data;
@@ -72,6 +76,61 @@ static void test_set_input_pins(const void *data)
 g_assert_cmphex(value, ==, 0x);
 }
 
+static void test_2700_output_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+
+/* output direction and output hi */
+qtest_writel(s, offset, 0x0003);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0003);
+
+/* output direction and output low */
+qtest_writel(s, offset, 0x0002);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x0002);
+pin++;
+}
+}
+}
+
+static void test_2700_input_pins(const void *data)
+{
+QTestState *s = (QTestState *)data;
+char name[16];
+uint32_t offset = 0;
+uint32_t value = 0;
+uint32_t pin = 0;
+
+for (char c = 'A'; c <= 'D'; c++) {
+for (int i = 0; i < 8; i++) {
+sprintf(name, "gpio%c%d", c, i);
+offset = AST2700_GPIO_BASE + GPIOA0_CONTROL + (pin * 4);
+/* input direction */
+qtest_writel(s, offset, 0);
+
+/* set input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0x2000);
+
+/* clear input */
+qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+value = qtest_readl(s, offset);
+g_assert_cmphex(value, ==, 0);
+pin++;
+}
+}
+}
+
+
 int main(int argc, char **argv)
 {
 QTestState *s;
@@ -83,6 +142,11 @@ int main(int argc, char **argv)
 qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s,
 test_set_colocated_pins);
 qtest_add_data_func("/ast2600/gpio/set_input_pins", s, 
test_set_input_pins);
+
+s = qtest_init("-machine ast2700-evb");
+qtest_add_data_func("/ast2700/gpio/input_pins", s, test_2700_input_pins);
+qtest_add_data_func("/ast2700/gpio/out_pins", s, test_2700_output_pins);
+
 r = g_test_run();
 qtest_quit(s);
 
-- 
2.34.1




[PATCH v4 5/7] hw/gpio/aspeed: Add AST2700 support

2024-09-27 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller with maximum 212
control pins, which are 27 groups. (H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs, one register is used for setting
one function for one set which are 32 pins and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register.
In other words, users are able to set one GPIO pin’s direction,
interrupt enable, input mask and so on in the same one register.

Currently, aspeed_gpio_read and aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce new aspeed_gpio_2700_read and aspeed_gpio_2700_write callback
functions and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 380 ++
 1 file changed, 380 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 16c18ea2f7..a5b3f454e8 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -970,6 +1002,316 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extr

[PATCH v4 4/7] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-09-27 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in reg_value. However, if the extracted
bit is clear then the value of the corresponding bit in reg_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). reg_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the
reg_value, using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending == 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending == 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
Suggested-by: Andrew Jeffery 
Reviewed-by: Andrew Jeffery 
---
 hw/gpio/aspeed_gpio.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 8725606aec..16c18ea2f7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
   FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
-/* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+/* interrupt status */
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+/* pending is either 1 or 0 for a 1-bit field */
+pending = extract32(set->int_status, pin_idx, 1);
+
+assert(s->pending >= pending);
+
+/* No change to s->pending if pending is 0 */
+s->pending -= pending;
+
+/*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v4 1/7] hw/gpio/aspeed: Fix coding style

2024-09-27 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/gpio/aspeed_gpio.c | 6 +++---
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..00fb72a509 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -629,7 +630,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr 
offset, uint32_t size)
 static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
 uint64_t data, uint32_t size)
 {
-
 AspeedGPIOState *s = ASPEED_GPIO(opaque);
 AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
 const GPIOSetProperties *props;
@@ -963,7 +963,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH v3 6/6] aspeed/soc: Support GPIO for AST2700

2024-09-26 Thread Jamin Lin via
Add GPIO model for AST2700 GPIO support.
The GPIO controller registers base address is start at
0x14C0_B000 and its address space is 0x1000.

The AST2700 GPIO controller interrupt is connected to
GICINT130_INTC at bit 18.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
@@ -373,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -658,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v3 2/6] hw/gpio/aspeed: Support to set the different memory size

2024-09-26 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
a GPIO controller owns 4KB of register space for AST2700,
AST2500, AST2400 and AST1030; owns 2KB of register space
for AST2600 1.8v and owns 2KB of register space for AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 00fb72a509..564459ad4f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1130,6 +1130,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1142,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1154,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1166,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1178,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v3 5/6] hw/gpio/aspeed: Add AST2700 support

2024-09-26 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller
with maximum 212 control pins, which are 27 groups.
(H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs,
one register is used for setting one function for one set which are 32 pins
and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register. In other words, users 
are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in the same one register.

Currently, aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.
Introduce new aspeed_gpio_2700_read/aspeed_gpio_2700_write callback functions
and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 380 ++
 1 file changed, 380 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 16c18ea2f7..a5b3f454e8 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -970,6 +1002,316 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extract32(set->input_mask, pin_idx, 1));

[PATCH v3 1/6] hw/gpio/aspeed: Fix coding style

2024-09-26 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 6 +++---
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..00fb72a509 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -629,7 +630,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr 
offset, uint32_t size)
 static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
 uint64_t data, uint32_t size)
 {
-
 AspeedGPIOState *s = ASPEED_GPIO(opaque);
 AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
 const GPIOSetProperties *props;
@@ -963,7 +963,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH v3 0/6] Support GPIO for AST2700

2024-09-26 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestions
v3: remove nested conditionals and adds reviewer suggestions

Jamin Lin (6):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Support GPIO for AST2700

 hw/arm/aspeed_ast27x0.c   |  18 +-
 hw/gpio/aspeed_gpio.c | 427 --
 include/hw/gpio/aspeed_gpio.h |   4 +-
 3 files changed, 430 insertions(+), 19 deletions(-)

-- 
2.34.1




[PATCH v3 3/6] hw/gpio/aspeed: Support different memory region ops

2024-09-26 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing
read and write callbacks to be used when I/O is performed
on the GPIO region.

Besides, in the previous design of ASPEED SOCs,
one register is used for setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 564459ad4f..8725606aec 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1046,7 +1046,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1143,6 +1144,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1155,6 +1157,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1167,6 +1170,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1179,6 +1183,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v3 4/6] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-09-26 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in group_value. However, if the extracted
bit is clear then the value of the corresponding bit in group_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). group_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the group,
using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending == 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending == 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 8725606aec..16c18ea2f7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
   FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
-/* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+/* interrupt status */
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+/* pending is either 1 or 0 for a 1-bit field */
+pending = extract32(set->int_status, pin_idx, 1);
+
+assert(s->pending >= pending);
+
+/* No change to s->pending if pending is 0 */
+s->pending -= pending;
+
+/*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v2 5/6] hw/gpio/aspeed: Add AST2700 support

2024-09-24 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller
with maximum 212 control pins, which are 27 groups.
(H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs,
one register is used for setting one function for one set which are 32 pins
and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register. In other words, users 
are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in the same one register.

Currently, aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.
Introduce new aspeed_gpio_2700_read/aspeed_gpio_2700_write callback functions
and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 375 ++
 1 file changed, 375 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 58ae63e3c1..e09e34ff2d 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -965,6 +997,311 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extract32(set->input_mask, pin_idx, 1));
+

[PATCH v2 2/6] hw/gpio/aspeed: Support to set the different memory size

2024-09-24 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
a GPIO controller owns 4KB of register space for AST2700,
AST2500, AST2400 and AST1030; owns 2KB of register space
for AST2600 1.8v and owns 2KB of register space for AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index a5886ffa43..4b8004649b 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1048,7 +1048,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+  TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1142,6 +1143,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1153,6 +1155,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1164,6 +1167,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1175,6 +1179,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v2 6/6] aspeed/soc: Support GPIO for AST2700

2024-09-24 Thread Jamin Lin via
Add GPIO model for AST2700 GPIO support.
The GPIO controller registers base address is start at
0x14C0_B000 and its address space is 0x1000.

The AST2700 GPIO controller interrupt is connected to
GICINT130_INTC at bit 18.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
@@ -373,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -658,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v2 4/6] hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode

2024-09-24 Thread Jamin Lin via
The interrupt status field is W1C, where a set bit on read indicates an
interrupt is pending. If the bit extracted from data is set it should
clear the corresponding bit in group_value. However, if the extracted
bit is clear then the value of the corresponding bit in group_value
should be unchanged.

SHARED_FIELD_EX32() extracts the interrupt status bit from the write
(data). group_value is set to the set's interrupt status, which means
that for any pin with an interrupt pending, the corresponding bit is
set. The deposit32() call updates the bit at pin_idx in the group,
using the value extracted from the write (data).

The result is that if multiple interrupt status bits
were pending and the write was acknowledging specific one bit,
then the all interrupt status bits will be cleared.
However, it is index mode and should only clear the corresponding bit.

For example, say we have an interrupt pending for GPIOA0, where the
following statements are true:

   set->int_status == 0b01
   s->pending == 1

Before it is acknowledged, an interrupt becomes pending for GPIOA1:

   set->int_status == 0b11
   s->pending == 2

A write is issued to acknowledge the interrupt for GPIOA0. This causes
the following sequence:

   reg_value == 0b11
   pending == 2
   s->pending = 0
   set->int_status == 0b00

It should only clear bit 0 in index mode and the correct result
should be as following.

   set->int_status == 0b11
   s->pending == 2

   pending == 1
   s->pending = 1
   set->int_status == 0b10

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 6e6ab48b56..58ae63e3c1 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -642,7 +642,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
 uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
 uint32_t reg_value = 0;
-uint32_t cleared;
+uint32_t pending = 0;
 
 set = &s->sets[set_idx];
 props = &agc->props[set_idx];
@@ -705,15 +705,16 @@ static void aspeed_gpio_write_index_mode(void *opaque, 
hwaddr offset,
 set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
   reg_value);
 /* set interrupt status */
-reg_value = set->int_status;
-reg_value = deposit32(reg_value, pin_idx, 1,
-  FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
-cleared = ctpop32(reg_value & set->int_status);
-if (s->pending && cleared) {
-assert(s->pending >= cleared);
-s->pending -= cleared;
+if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+pending = extract32(set->int_status, pin_idx, 1);
+if (pending) {
+if (s->pending) {
+assert(s->pending >= pending);
+s->pending -= pending;
+}
+set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
+}
 }
-set->int_status &= ~reg_value;
 break;
 case gpio_reg_idx_debounce:
 reg_value = set->debounce_1;
-- 
2.34.1




[PATCH v2 3/6] hw/gpio/aspeed: Support different memory region ops

2024-09-24 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing
read and write callbacks to be used when I/O is performed
on the GPIO region.

Besides, in the previous design of ASPEED SOCs,
one register is used for setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 4b8004649b..6e6ab48b56 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
   TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1132,6 +1132,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1144,6 +1145,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1156,6 +1158,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1168,6 +1171,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1180,6 +1184,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v2 1/6] hw/gpio/aspeed: Fix coding style

2024-09-24 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 5 +++--
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..a5886ffa43 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
@@ -963,7 +964,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
-/** Setup functions **/
+/* Setup functions */
 static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
 [0] = {0x,  0x,  {"A", "B", "C", "D"} },
 [1] = {0x,  0x,  {"E", "F", "G", "H"} },
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH v2 0/6] Support GPIO for AST2700

2024-09-24 Thread Jamin Lin via
v1: Support GPIO for AST2700
v2: Fix clear incorrect interrupt status and adds reviewer suggestion

Jamin Lin (6):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index
mode
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Support GPIO for AST2700

 hw/arm/aspeed_ast27x0.c   |  18 +-
 hw/gpio/aspeed_gpio.c | 413 --
 include/hw/gpio/aspeed_gpio.h |   4 +-
 3 files changed, 418 insertions(+), 17 deletions(-)

-- 
2.34.1




[PATCH 5/5] aspeed/soc: Support GPIO for AST2700

2024-09-23 Thread Jamin Lin via
Add GPIO model for AST2700 GPIO support.
The GPIO controller registers base address is start at
0x14C0_B000 and its address space is 0x1000.

The AST2700 GPIO controller interrupt is connected to
GICINT130_INTC at bit 18.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 18 +++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11657..dca660eb6b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
 [ASPEED_DEV_I2C]   =  0x14C0F000,
+[ASPEED_DEV_GPIO]  =  0x14C0B000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
 [ASPEED_DEV_ADC]   = 130,
 [ASPEED_DEV_XDMA]  = 5,
 [ASPEED_DEV_EMMC]  = 15,
-[ASPEED_DEV_GPIO]  = 11,
-[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_GPIO]  = 130,
 [ASPEED_DEV_RTC]   = 13,
 [ASPEED_DEV_TIMER1]= 16,
 [ASPEED_DEV_TIMER2]= 17,
@@ -124,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
 static const int aspeed_soc_ast2700_gic130_intcmap[] = {
 [ASPEED_DEV_I2C]= 0,
 [ASPEED_DEV_ADC]= 16,
-[ASPEED_DEV_GPIO_1_8V]  = 18,
+[ASPEED_DEV_GPIO]   = 18,
 };
 
 /* GICINT 131 */
@@ -373,6 +373,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
 object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+object_initialize_child(obj, "gpio", &s->gpio, typename);
 }
 
 /*
@@ -658,6 +661,15 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
 }
 
+/* GPIO */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+sc->memmap[ASPEED_DEV_GPIO]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH 1/5] hw/gpio/aspeed: Fix coding style

2024-09-23 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 3 ++-
 include/hw/gpio/aspeed_gpio.h | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 71756664dd..901b576144 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -340,7 +340,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, 
uint32_t set_idx,
 value &= ~pin_mask;
 }
 
-aspeed_gpio_update(s, &s->sets[set_idx], value, 
~s->sets[set_idx].direction);
+aspeed_gpio_update(s, &s->sets[set_idx], value,
+   ~s->sets[set_idx].direction);
 }
 
 /*
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae318..39febda9ea 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -88,7 +88,7 @@ struct AspeedGPIOState {
 qemu_irq irq;
 qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
 
-/* Parallel GPIO Registers */
+/* Parallel GPIO Registers */
 uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
 struct GPIOSets {
 uint32_t data_value; /* Reflects pin values */
-- 
2.34.1




[PATCH 0/5] Support GPIO for AST2700

2024-09-23 Thread Jamin Lin via
v1: support GPIO for AST2700

Jamin Lin (5):
  hw/gpio/aspeed: Fix coding style
  hw/gpio/aspeed: Support to set the different memory size
  hw/gpio/aspeed: Support different memory region ops
  hw/gpio/aspeed: Add AST2700 support
  aspeed/soc: Support GPIO for AST2700

 hw/arm/aspeed_ast27x0.c   |  18 +-
 hw/gpio/aspeed_gpio.c | 390 +-
 include/hw/gpio/aspeed_gpio.h |   4 +-
 3 files changed, 405 insertions(+), 7 deletions(-)

-- 
2.34.1




[PATCH 3/5] hw/gpio/aspeed: Support different memory region ops

2024-09-23 Thread Jamin Lin via
It set "aspeed_gpio_ops" struct which containing
read and write callbacks to be used when I/O is performed
on the GPIO region.

Besides, in the previous design of ASPEED SOCs,
one register is used for setting one function for 32 GPIO pins.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change in AST2700.
Each GPIO pin has their own control register. In other words, users are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in one register. The aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.

Introduce a new "const MemoryRegionOps *" attribute in AspeedGPIOClass and
use it in aspeed_gpio_realize function.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 94a5f3ee03..f23ffae34d 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1047,7 +1047,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
-memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
+memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
 TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
@@ -1132,6 +1132,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1144,6 +1145,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1156,6 +1158,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1168,6 +1171,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
 agc->mem_size = 0x800;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1180,6 +1184,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
 agc->mem_size = 0x1000;
+agc->reg_ops = &aspeed_gpio_ops;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 8cd2ff5496..e1e6c54333 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -77,6 +77,7 @@ struct AspeedGPIOClass {
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
 uint64_t mem_size;
+const MemoryRegionOps *reg_ops;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH 4/5] hw/gpio/aspeed: Add AST2700 support

2024-09-23 Thread Jamin Lin via
AST2700 integrates two set of Parallel GPIO Controller
with maximum 212 control pins, which are 27 groups.
(H, exclude pin: H7 H6 H5 H4)

In the previous design of ASPEED SOCs,
one register is used for setting one function for one set which are 32 pins
and 4 groups.
ex: GPIO000 is used for setting data value for GPIO A, B, C and D in AST2600.
ex: GPIO004 is used for setting direction for GPIO A, B, C and D in AST2600.

However, the register set have a significant change since AST2700.
Each GPIO pin has their own individual control register. In other words, users 
are able to
set one GPIO pin’s direction, interrupt enable, input mask and so on
in the same one register.

Currently, aspeed_gpio_read/aspeed_gpio_write callback functions
are not compatible AST2700.
Introduce new aspeed_gpio_2700_read/aspeed_gpio_2700_write callback functions
and aspeed_gpio_2700_ops memory region operation for AST2700.
Introduce a new ast2700 class to support AST2700.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 373 ++
 1 file changed, 373 insertions(+)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index f23ffae34d..e3d5556dc1 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
 FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
 FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
 
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register*/
+REG32(GPIO_A0_CONTROL, 0x180)
+SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
 uint32_t falling_edge = 0, rising_edge = 0;
@@ -964,6 +996,309 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, 
const char *name,
 aspeed_gpio_set_pin_level(s, set_idx, pin, level);
 }
 
+static uint64_t aspeed_gpio_read_control_reg(AspeedGPIOState *s, uint32_t pin)
+{
+AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+GPIOSets *set;
+uint64_t value = 0;
+uint32_t set_idx;
+uint32_t pin_idx;
+
+set_idx = pin / ASPEED_GPIOS_PER_SET;
+pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+if (set_idx >= agc->nr_gpio_sets) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+  __func__, set_idx);
+return 0;
+}
+
+set = &s->sets[set_idx];
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+  extract32(set->data_read, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+  extract32(set->direction, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+  extract32(set->int_enable, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+  extract32(set->int_sens_0, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+  extract32(set->int_sens_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+  extract32(set->int_sens_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+  extract32(set->reset_tol, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+  extract32(set->debounce_1, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+  extract32(set->debounce_2, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+  extract32(set->input_mask, pin_idx, 1));
+value = SHARED_FIELD_DP32(value, GPIO_C

[PATCH 2/5] hw/gpio/aspeed: Support to set the different memory size

2024-09-23 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
a GPIO controller owns 4KB of register space for AST2700,
AST2500, AST2400 and AST1030; owns 2KB of register space
for AST2600 1.8v and owns 2KB of register space for AST2600 3.3v.

It set the memory region size 2KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the GPIO controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
---
 hw/gpio/aspeed_gpio.c | 7 ++-
 include/hw/gpio/aspeed_gpio.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 901b576144..94a5f3ee03 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -1048,7 +1048,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error 
**errp)
 }
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
-TYPE_ASPEED_GPIO, 0x800);
+TYPE_ASPEED_GPIO, agc->mem_size);
 
 sysbus_init_mmio(sbd, &s->iomem);
 }
@@ -1131,6 +1131,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1142,6 +1143,7 @@ static void aspeed_gpio_2500_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 8;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1153,6 +1155,7 @@ static void 
aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 7;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1164,6 +1167,7 @@ static void 
aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
 agc->nr_gpio_sets = 2;
 agc->reg_table = aspeed_1_8v_gpios;
 agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+agc->mem_size = 0x800;
 }
 
 static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1175,6 +1179,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass 
*klass, void *data)
 agc->nr_gpio_sets = 6;
 agc->reg_table = aspeed_3_3v_gpios;
 agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+agc->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_gpio_info = {
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 39febda9ea..8cd2ff5496 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,7 @@ struct AspeedGPIOClass {
 uint32_t nr_gpio_sets;
 const AspeedGPIOReg *reg_table;
 unsigned reg_table_count;
+uint64_t mem_size;
 };
 
 struct AspeedGPIOState {
-- 
2.34.1




[PATCH v3 11/11] machine_aspeed.py: Update to test I2C for AST2700

2024-09-03 Thread Jamin Lin via
Update test case to test lm75 temperature sensor.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 tests/avocado/machine_aspeed.py | 16 
 1 file changed, 16 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index c0b01e8f1f..4e144bde91 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -433,9 +433,25 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self):
  f'loader,addr=0x43000,cpu-num={i}')
 
 self.vm.add_args('-smp', str(num_cpu))
+self.vm.add_args('-device',
+ 
'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
 self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
 self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
+
 self.ssh_connect('root', '0penBmc', False)
+self.ssh_command('dmesg -c > /dev/null')
+
+self.ssh_command_output_contains(
+'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device '
+'&& dmesg -c',
+'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d');
+
+self.ssh_command_output_contains(
+'cat /sys/class/hwmon/hwmon20/temp1_input', '0')
+self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+property='temperature', value=18000)
+self.ssh_command_output_contains(
+'cat /sys/class/hwmon/hwmon20/temp1_input', '18000')
 
 class AST2x00MachineMMC(QemuSystemTest):
 
-- 
2.34.1




[PATCH v3 08/11] aspeed/soc: Introduce a new API to get the device irq

2024-09-03 Thread Jamin Lin via
Currently, users can set the INTC mapping table with
enumerated device id and device irq to get the INTC orgate
input pins. However, some devices use the continuous source numbers in the
same INTC orgate. To reduce the enumerated device id definition,
create a new API to get the INTC orgate input pin
if users only provide the device id with its bus number index.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4257b5e8af..a5eb78524f 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -193,6 +193,27 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState 
*s, int dev)
 return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
 }
 
+static qemu_irq aspeed_soc_ast2700_get_irq_index(AspeedSoCState *s, int dev,
+ int index)
+{
+Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
+AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+int i;
+
+for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+return qdev_get_gpio_in(DEVICE(&a->intc.orgates[i]),
+aspeed_soc_ast2700_gic_intcmap[i].ptr[dev] + index);
+}
+}
+
+/*
+ * Invalid orgate index, device irq should be 128 to 136.
+ */
+g_assert_not_reached();
+}
+
 static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
 unsigned int size)
 {
-- 
2.34.1




[PATCH v3 09/11] aspeed/soc: Support I2C for AST2700

2024-09-03 Thread Jamin Lin via
Add I2C model for AST2700 I2C support.
The I2C controller registers base address is start at
0x14C0_F000 and its address space is 0x2000.

The AST2700 I2C controller has one source INTC per bus.
I2C buses interrupt are connected to GICINT130_INTC
from bit 0 to bit 15.
I2C bus 0 is connected to GICINT130_INTC at bit 0.
I2C bus 15 is connected to GICINT130_INTC at bit 15.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index a5eb78524f..761ee11657 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -61,6 +61,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_DIST]  =  0x1220,
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
+[ASPEED_DEV_I2C]   =  0x14C0F000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -369,6 +370,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
 object_initialize_child(obj, "adc", &s->adc, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+object_initialize_child(obj, "i2c", &s->i2c, typename);
 }
 
 /*
@@ -452,6 +456,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
 AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
 g_autofree char *sram_name = NULL;
+qemu_irq irq;
 
 /* Default boot region (SPI memory or ROMs) */
 memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -634,6 +639,25 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
 
+/* I2C */
+object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+/*
+ * The AST2700 I2C controller has one source INTC per bus.
+ * I2C buses interrupt are connected to GICINT130_INTC
+ * from bit 0 to bit 15.
+ * I2C bus 0 is connected to GICINT130_INTC at bit 0.
+ * I2C bus 15 is connected to GICINT130_INTC at bit 15.
+ */
+irq = aspeed_soc_ast2700_get_irq_index(s, ASPEED_DEV_I2C, i);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+}
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v3 07/11] hw/i2c/aspeed: Add support for 64 bit addresses

2024-09-03 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
and the base address of dram is "0x4 " which
is 64bits address.

The AST2700 support the maximum DRAM size is 8 GB.
The DRAM physical address range is from "0x4__" to
"0x5__".

The DRAM offset range is from "0x0__" to
"0x1__" and it is enough to use bits [33:0]
saving the dram offset.

Therefore, save the high part physical address bit[1:0]
of Tx/Rx buffer address as dma_dram_offset bit[33:32].
It does not need to decrease the dram physical
high part address for DMA operation.
(high part physical address bit[7:0] – 4)

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index c1ff80b1cf..44c3c39233 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -743,6 +743,14 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
   __func__);
 break;
 
+/*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0__ to
+ * 0x1__ and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
 case A_I2CM_DMA_TX_ADDR_HI:
 if (!aic->has_dma64) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
@@ -752,6 +760,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_TX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CM_DMA_RX_ADDR_HI:
 if (!aic->has_dma64) {
@@ -762,6 +772,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CS_DMA_TX_ADDR_HI:
 qemu_log_mask(LOG_UNIMP,
@@ -777,6 +789,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CS_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
-- 
2.34.1




[PATCH v3 01/11] hw/i2c/aspeed: Support discontinuous register memory region of I2C bus

2024-09-03 Thread Jamin Lin via
It only support continuous register memory region for all I2C bus.
However, the register address of all I2c bus are discontinuous
for AST2700.

Ex: the register address of I2C bus for ast2700 as following.
0x100 - 0x17F: Device 0
0x200 - 0x27F: Device 1
0x300 - 0x37F: Device 2
0x400 - 0x47F: Device 3
0x500 - 0x57F: Device 4
0x600 - 0x67F: Device 5
0x700 - 0x77F: Device 6
0x800 - 0x87F: Device 7
0x900 - 0x97F: Device 8
0xA00 - 0xA7F: Device 9
0xB00 - 0xB7F: Device 10
0xC00 - 0xC7F: Device 11
0xD00 - 0xD7F: Device 12
0xE00 - 0xE7F: Device 13
0xF00 – 0xF7F: Device 14
0x1000 – 0x107F: Device 15

Introduce a new class attribute to make user set each I2C bus gap size.
Update formula to create all I2C bus register memory regions.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b52a99896c..9c222a02fe 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1012,6 +1012,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1034,7 +1035,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 
-memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
 &s->busses[i].mr);
 }
 
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index fad5e9259a..02ede85906 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -275,6 +275,7 @@ struct AspeedI2CClass {
 
 uint8_t num_busses;
 uint8_t reg_size;
+uint32_t reg_gap_size;
 uint8_t gap;
 qemu_irq (*bus_get_irq)(AspeedI2CBus *);
 
-- 
2.34.1




[PATCH v3 02/11] hw/i2c/aspeed: Introduce a new bus pool buffer attribute in AspeedI2Cbus

2024-09-03 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
each I2C bus has their own pool buffer since AST2500.
Only AST2400 utilized a pool buffer share to all I2C bus.
Besides, using a share pool buffer only support
pool buffer memory regions are continuous for all I2C bus.

To make this model more readable and support discontinuous
bus pool buffer memory regions, changes to introduce
a new bus pool buffer attribute in AspeedI2Cbus and
new memops. So, it does not need to calculate
the pool buffer offset for different I2C bus.

Introduce a new has_share_pool class attribute in AspeedI2CClass and
use it to create either a share pool buffer or bus pool buffers
in aspeed_i2c_realize. Update each pull buffer size to 0x10 for AST2500
and 0x20 for AST2600 and AST1030.

Incrementing the version of aspeed_i2c_bus_vmstate to 6.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 131 +++-
 include/hw/i2c/aspeed_i2c.h |   4 ++
 2 files changed, 117 insertions(+), 18 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 9c222a02fe..d3d49340ea 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -941,12 +941,48 @@ static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
 },
 };
 
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+AspeedI2CBus *s = opaque;
+uint64_t ret = 0;
+int i;
+
+for (i = 0; i < size; i++) {
+ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+}
+
+return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+  uint64_t value, unsigned size)
+{
+AspeedI2CBus *s = opaque;
+int i;
+
+for (i = 0; i < size; i++) {
+s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+}
+}
+
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+.read = aspeed_i2c_bus_pool_read,
+.write = aspeed_i2c_bus_pool_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 4,
+},
+};
+
 static const VMStateDescription aspeed_i2c_bus_vmstate = {
 .name = TYPE_ASPEED_I2C,
-.version_id = 5,
-.minimum_version_id = 5,
+.version_id = 6,
+.minimum_version_id = 6,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -996,7 +1032,21 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x140 ... 0x17F: Device 5
  *   0x180 ... 0x1BF: Device 6
  *   0x1C0 ... 0x1FF: Device 7
- *   0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
+ *   0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ *   0x210 ... 0x21F: Device 2 buffer
+ *   0x220 ... 0x22F: Device 3 buffer
+ *   0x230 ... 0x23F: Device 4 buffer
+ *   0x240 ... 0x24F: Device 5 buffer
+ *   0x250 ... 0x25F: Device 6 buffer
+ *   0x260 ... 0x26F: Device 7 buffer
+ *   0x270 ... 0x27F: Device 8 buffer
+ *   0x280 ... 0x28F: Device 9 buffer
+ *   0x290 ... 0x29F: Device 10 buffer
+ *   0x2A0 ... 0x2AF: Device 11 buffer
+ *   0x2B0 ... 0x2BF: Device 12 buffer
+ *   0x2C0 ... 0x2CF: Device 13 buffer
+ *   0x2D0 ... 0x2DF: Device 14 buffer
+ *   0x2E0 ... 0x2FF: Reserved
  *   0x300 ... 0x33F: Device 8
  *   0x340 ... 0x37F: Device 9
  *   0x380 ... 0x3BF: Device 10
@@ -1005,6 +1055,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x440 ... 0x47F: Device 13
  *   0x480 ... 0x4BF: Device 14
  *   0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ *   0x000 ... 0x07F: Global Register
+ *   0x080 ... 0x0FF: Device 1
+ *   0x100 ... 0x17F: Device 2
+ *   0x180 ... 0x1FF: Device 3
+ *   0x200 ... 0x27F: Device 4
+ *   0x280 ... 0x2FF: Device 5
+ *   0x300 ... 0x37F: Device 6
+ *   0x380 ... 0x3FF: Device 7
+ *   0x400 ... 0x47F: Device 8
+ *   0x480 ... 0x4FF: Device 9
+ *   0x500 ... 0x57F: Device 10
+ *   0x580 ... 0x5FF: Device 11
+ *   0x600 ... 0x67F: Device 12
+ *   0x680 ... 0x6FF: Device 13
+ *   0x700 ... 0x77F: Device 14
+ *   0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ *   0x800 ... 0x87F: Device 16
+ *   0xC00 ... 0xC1F: Device 1 buffer
+ *   0xC20 ... 0xC3F: Device 2 buffer
+ *   0xC40 ... 0xC5F: Device 3 buffer
+ *   0xC60 ... 0xC7F: Device 4 buffer
+ *   0xC80 ... 0xC9F: Device 5 buffer
+ *   0xCA0 ... 0xCBF: Device 6 buffer
+ *   0xCC0 ... 0xCDF: Device 7 buffer
+ *   0xCE0 ... 0xCFF: Device 8 buffer
+ *   0xD00 ... 0xD1F: Device 9 buffer
+ *   0xD20 ... 0xD3F: Device 10 buffer
+ *   0xD40 ... 0xD5F: Device 11 buffer
+ *   0xD60 ... 0xD7F: Device 12 buffer
+ *   0xD80 ... 0xD9F: Device 13 buffer
+ *   0xDA0 ... 0xDBF: Device 14 buffer
+ *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)

[PATCH v3 06/11] hw/i2c/aspeed: Add support for Tx/Rx buffer 64 bit addresses

2024-09-03 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
and the base address of dram is "0x4 " which
is 64bits address.

It has "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
and "Master DMA Mode Rx Buffer Base Address[39:32](0x64)"
registers to save the high part physical address of Tx/Rx
buffer address for master mode.

It has "Slave DMA Mode Tx Buffer Base Address[39:32](0x68)" and
"Slave DMA Mode Rx Buffer Base Address[39:32](0x6C)" registers
to save the high part physical address of Tx/Rx buffer address
for slave mode.

Ex: Tx buffer address for master mode [39:0]
The "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
bits [7:0] which corresponds the bits [39:32] of the 64 bits address of
the Tx buffer address.
The "Master DMA Mode Tx Buffer Base Address(0x30)" bits [31:0]
which corresponds the bits [31:0] of the 64 bits address
of the Tx buffer address.

Introduce a new has_dma64 class attribute and new registers for the
new mode to support DMA 64 bits dram address.
Update new mode register number to 28.

The aspeed_i2c_bus_vmstate is changed again and
version is not increased because it was done earlier in the same series.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 48 +
 include/hw/i2c/aspeed_i2c.h | 12 +-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 819a875839..c1ff80b1cf 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -140,6 +140,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
 unsigned size)
 {
+AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
 
 switch (offset) {
@@ -170,6 +171,16 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_CMD:
 value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
 break;
+case A_I2CM_DMA_TX_ADDR_HI:
+case A_I2CM_DMA_RX_ADDR_HI:
+case A_I2CS_DMA_TX_ADDR_HI:
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+__func__);
+value = -1;
+}
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR,
   "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -731,6 +742,42 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
   __func__);
 break;
+
+case A_I2CM_DMA_TX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_TX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CM_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CS_DMA_TX_ADDR_HI:
+qemu_log_mask(LOG_UNIMP,
+  "%s: Slave mode DMA TX Addr high is not implemented\n",
+  __func__);
+break;
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CS_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
   __func__, offset);
@@ -1554,6 +1601,7 @@ static void aspeed_2700_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
 aic->has_dma = true;
 aic->mem_size = 0x2000;
+aic->has_dma64 = true;
 }
 
 static const TypeInfo aspeed_2700_i2c_info = {
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 4f23dc10c3..2c4c81bd20 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -38,7 +38,7 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, 
ASPEED_I2C)
 #define ASPEED_I2C_SHARE_POOL_SIZE 0x800
 #define 

[PATCH v3 10/11] aspeed: Add tmp105 in i2c bus 0 for AST2700

2024-09-03 Thread Jamin Lin via
ASPEED SDK add lm75 in i2c bus 0 for AST2700.
LM75 is compatible with TMP105 driver.

Introduce a new i2c init function and
add tmp105 device model in i2c bus 0.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/arm/aspeed.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index fd5603f7aa..3d13b16768 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1650,6 +1650,15 @@ static void 
aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
 }
 
 #ifdef TARGET_AARCH64
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+AspeedSoCState *soc = bmc->soc;
+
+/* LM75 is compatible with TMP105 driver */
+i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+TYPE_TMP105, 0x4d);
+}
+
 static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 {
 MachineClass *mc = MACHINE_CLASS(oc);
@@ -1664,6 +1673,7 @@ static void 
aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 amc->num_cs= 2;
 amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
 amc->uart_default = ASPEED_DEV_UART12;
+amc->i2c_init  = ast2700_evb_i2c_init;
 mc->default_ram_size = 1 * GiB;
 aspeed_machine_class_init_cpus_defaults(mc);
 }
-- 
2.34.1




[PATCH v3 03/11] hw/i2c/aspeed: Support discontinuous poll buffer memory region of I2C bus

2024-09-03 Thread Jamin Lin via
It only support continuous pool buffer memory region for all I2C bus.
However, the pool buffer address of all I2c bus are discontinuous
for AST2700.

Ex: the pool buffer address of I2C bus for ast2700 as following.
0x1A0 - 0x1BF: Device 0 buffer
0x2A0 - 0x2BF: Device 1 buffer
0x3A0 - 0x3BF: Device 2 buffer
0x4A0 - 0x4BF: Device 3 buffer
0x5A0 - 0x5BF: Device 4 buffer
0x6A0 - 0x6BF: Device 5 buffer
0x7A0 - 0x7BF: Device 6 buffer
0x8A0 - 0x8BF: Device 7 buffer
0x9A0 - 0x9BF: Device 8 buffer
0xAA0 - 0xABF: Device 9 buffer
0xBA0 - 0xBBF: Device 10 buffer
0xCA0 - 0xCBF: Device 11 buffer
0xDA0 - 0xDBF: Device 12 buffer
0xEA0 - 0xEBF: Device 13 buffer
0xFA0 – 0xFBF: Device 14 buffer
0x10A0 – 0x10BF: Device 15 buffer

Introduce a new class attribute to make user set each I2C bus
pool buffer gap size. Update formula to create all I2C bus
pool buffer memory regions.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index d3d49340ea..abcb1d5330 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1098,6 +1098,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
 uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1133,7 +1134,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 } else {
 for (i = 0; i < aic->num_busses; i++) {
 memory_region_add_subregion(&s->iomem,
-aic->pool_base + (aic->pool_size * i),
+aic->pool_base + (pool_offset * i),
 &s->busses[i].mr_pool);
 }
 }
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 8e62ec64f8..b42c4dc584 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -284,6 +284,7 @@ struct AspeedI2CClass {
 
 uint64_t pool_size;
 hwaddr pool_base;
+uint32_t pool_gap_size;
 uint8_t *(*bus_pool_base)(AspeedI2CBus *);
 bool check_sram;
 bool has_dma;
-- 
2.34.1




[PATCH v3 00/11] support I2C for AST2700

2024-09-03 Thread Jamin Lin via
v1:
- support I2C for AST2700

v2:
- fix review issues and add reviewer suggestion
- update avocado test case for AST2700 I2C
- support i2c bus pool

v3:
- update commit messages and commit title
- update API to get the device irq

Jamin Lin (11):
  hw/i2c/aspeed: Support discontinuous register memory region of I2C bus
  hw/i2c/aspeed: Introduce a new bus pool buffer attribute in
AspeedI2Cbus
  hw/i2c/aspeed: Support discontinuous poll buffer memory region of I2C
bus
  hw/i2c/aspeed: Introduce a new dma_dram_offset attribute in
AspeedI2Cbus
  hw/i2c/aspeed: Add AST2700 support
  hw/i2c/aspeed: Add support for Tx/Rx buffer 64 bit addresses
  hw/i2c/aspeed: Add support for 64 bit addresses
  aspeed/soc: Introduce a new API to get the device irq
  aspeed/soc: Support I2C for AST2700
  aspeed: Add tmp105 in i2c bus 0 for AST2700
  machine_aspeed.py: Update to test I2C for AST2700

 hw/arm/aspeed.c |  10 ++
 hw/arm/aspeed_ast27x0.c |  45 +
 hw/i2c/aspeed_i2c.c | 310 
 include/hw/i2c/aspeed_i2c.h |  28 ++-
 tests/avocado/machine_aspeed.py |  16 ++
 5 files changed, 362 insertions(+), 47 deletions(-)

-- 
2.34.1




[PATCH v3 04/11] hw/i2c/aspeed: Introduce a new dma_dram_offset attribute in AspeedI2Cbus

2024-09-03 Thread Jamin Lin via
The "Current DMA Operating Address Status(0x50)" register of
I2C new mode has been removed in AST2700.
This register is used for debugging and it is a read only register.

To support AST2700 DMA mode, introduce a new
dma_dram_offset class attribute in AspeedI2Cbus to save the
current DMA operating address.

ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

Set the dma_dram_offset data type to uint64_t for
64 bits dram address DMA support.

Both "DMA Mode Buffer Address Register(I2CD24 old mode)" and
"DMA Operating Address Status (I2CC50 new mode)" are used for showing the
low part dram offset bits [31:0], so change to read/write both register bits 
[31:0] in
bus register read/write functions.

The aspeed_i2c_bus_vmstate is changed again and version is not increased
because it was done earlier in the same series.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 51 +++--
 include/hw/i2c/aspeed_i2c.h |  9 +--
 2 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index abcb1d5330..2dea3a42a0 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 if (!aic->has_dma) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
 value = -1;
+break;
 }
+
+value = extract64(bus->dma_dram_offset, 0, 32);
 break;
 case A_I2CD_DMA_LEN:
 if (!aic->has_dma) {
@@ -150,9 +153,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_DMA_TX_ADDR:
 case A_I2CM_DMA_RX_ADDR:
 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:
@@ -161,6 +162,9 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CS_DMA_LEN_STS:
 /* Value is already set, don't do anything. */
 break;
+case A_I2CC_DMA_ADDR:
+value = extract64(bus->dma_dram_offset, 0, 32);
+break;
 case A_I2CS_INTR_STS:
 break;
 case A_I2CM_CMD:
@@ -210,18 +214,18 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t 
*data)
 {
 MemTxResult result;
 AspeedI2CState *s = bus->controller;
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
 
-result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+result = address_space_read(&s->dram_as, bus->dma_dram_offset,
 MEMTXATTRS_UNSPECIFIED, data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM read failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return -1;
 }
 
-bus->regs[reg_dma_addr]++;
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 return 0;
 }
@@ -291,7 +295,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
 uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
 RX_SIZE) + 1;
 
@@ -323,14 +326,17 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 data = i2c_recv(bus->bus);
 trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
   bus->regs[reg_dma_len], data);
-result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+result = address_space_write(&s->dram_as, bus->dma_dram_offset,
  MEMTXATTRS_UNSPECIFIED, &data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM write failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return;
 }
-bus->regs[reg_dma_addr]++;
+
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 /* In new mode, keep track of how many bytes we RXed */
 if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +642,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
   

[PATCH v3 05/11] hw/i2c/aspeed: Add AST2700 support

2024-09-03 Thread Jamin Lin via
Introduce a new ast2700 class to support AST2700.
The I2C bus register memory regions and
I2C bus pool buffer memory regions are discontinuous
and they do not back compatible AST2600.

Add a new ast2700 i2c class init function to match the
address of I2C bus register and pool buffer from the datasheet.

An I2C controller registers owns 8KB address space.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 62 +
 include/hw/i2c/aspeed_i2c.h |  1 +
 2 files changed, 63 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 2dea3a42a0..819a875839 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1102,6 +1102,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0xDA0 ... 0xDBF: Device 14 buffer
  *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
  *   0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ *   0x000 ... 0x0FF: Global Register
+ *   0x100 ... 0x17F: Device 0
+ *   0x1A0 ... 0x1BF: Device 0 buffer
+ *   0x200 ... 0x27F: Device 1
+ *   0x2A0 ... 0x2BF: Device 1 buffer
+ *   0x300 ... 0x37F: Device 2
+ *   0x3A0 ... 0x3BF: Device 2 buffer
+ *   0x400 ... 0x47F: Device 3
+ *   0x4A0 ... 0x4BF: Device 3 buffer
+ *   0x500 ... 0x57F: Device 4
+ *   0x5A0 ... 0x5BF: Device 4 buffer
+ *   0x600 ... 0x67F: Device 5
+ *   0x6A0 ... 0x6BF: Device 5 buffer
+ *   0x700 ... 0x77F: Device 6
+ *   0x7A0 ... 0x7BF: Device 6 buffer
+ *   0x800 ... 0x87F: Device 7
+ *   0x8A0 ... 0x8BF: Device 7 buffer
+ *   0x900 ... 0x97F: Device 8
+ *   0x9A0 ... 0x9BF: Device 8 buffer
+ *   0xA00 ... 0xA7F: Device 9
+ *   0xAA0 ... 0xABF: Device 9 buffer
+ *   0xB00 ... 0xB7F: Device 10
+ *   0xBA0 ... 0xBBF: Device 10 buffer
+ *   0xC00 ... 0xC7F: Device 11
+ *   0xCA0 ... 0xCBF: Device 11 buffer
+ *   0xD00 ... 0xD7F: Device 12
+ *   0xDA0 ... 0xDBF: Device 12 buffer
+ *   0xE00 ... 0xE7F: Device 13
+ *   0xEA0 ... 0xEBF: Device 13 buffer
+ *   0xF00 ... 0xF7F: Device 14
+ *   0xFA0 ... 0xFBF: Device 14 buffer
+ *   0x1000 ... 0x107F: Device 15
+ *   0x10A0 ... 0x10BF: Device 15 buffer
  */
 static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
 {
@@ -1501,6 +1536,32 @@ static const TypeInfo aspeed_1030_i2c_info = {
 .class_init = aspeed_1030_i2c_class_init,
 };
 
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+dc->desc = "ASPEED 2700 I2C Controller";
+
+aic->num_busses = 16;
+aic->reg_size = 0x80;
+aic->reg_gap_size = 0x80;
+aic->gap = -1; /* no gap */
+aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+aic->pool_size = 0x20;
+aic->pool_gap_size = 0xe0;
+aic->pool_base = 0x1a0;
+aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+aic->has_dma = true;
+aic->mem_size = 0x2000;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+.name = TYPE_ASPEED_2700_I2C,
+.parent = TYPE_ASPEED_I2C,
+.class_init = aspeed_2700_i2c_class_init,
+};
+
 static void aspeed_i2c_register_types(void)
 {
 type_register_static(&aspeed_i2c_bus_info);
@@ -1510,6 +1571,7 @@ static void aspeed_i2c_register_types(void)
 type_register_static(&aspeed_2500_i2c_info);
 type_register_static(&aspeed_2600_i2c_info);
 type_register_static(&aspeed_1030_i2c_info);
+type_register_static(&aspeed_2700_i2c_info);
 }
 
 type_init(aspeed_i2c_register_types)
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index bdaea3207d..4f23dc10c3 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -31,6 +31,7 @@
 #define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
 #define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
 #define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030"
+#define TYPE_ASPEED_2700_I2C TYPE_ASPEED_I2C "-ast2700"
 OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 
 #define ASPEED_I2C_NR_BUSSES 16
-- 
2.34.1




[PATCH v2 00/11] support I2C for AST2700

2024-08-07 Thread Jamin Lin via
v1:
- support I2C for AST2700

v2:
- fix review issues and add reviewer suggestion
- update avocado test case for AST2700 I2C
- support i2c bus pool

A. pool_gap_size and reg_gap_size need to be discussion.
B. aspeed_soc_ast2700_get_irq, aspeed_soc_ast2700_get_intc_orgate
 and sc->get_irq function pointer need to be discussion.

Jamin Lin (11):
  hw/i2c/aspeed: support discontinuous register memory region of I2C bus
  hw/i2c/aspeed: introduce a new bus pool buffer attribute in
AspeedI2Cbus
  hw/i2c/aspeed: support discontinuous poll buffer memory region of I2C
bus
  hw/i2c/aspeed: introduce a new dma_dram_offset attribute in
AspeedI2Cbus
  hw/i2c/aspeed: Add AST2700 support
  hw/i2c/aspeed: support Tx/Rx buffer 64 bits address
  hw/i2c/aspeed: support high part dram offset for DMA 64 bits
  aspeed/soc: introduce a new API to get the INTC orgate information
  aspeed/soc: support I2C for AST2700
  aspeed: add tmp105 in i2c bus 0 for AST2700
  machine_aspeed.py: update to test I2C for AST2700

 hw/arm/aspeed.c |  10 ++
 hw/arm/aspeed_ast27x0.c |  53 ++
 hw/i2c/aspeed_i2c.c | 310 
 include/hw/i2c/aspeed_i2c.h |  28 ++-
 tests/avocado/machine_aspeed.py |  16 ++
 5 files changed, 370 insertions(+), 47 deletions(-)

-- 
2.34.1




[PATCH v2 10/11] aspeed: add tmp105 in i2c bus 0 for AST2700

2024-08-07 Thread Jamin Lin via
ASPEED SDK add lm75 in i2c bus 0 for AST2700.
LM75 is compatible with TMP105 driver.

Introduce a new i2c init function and
add tmp105 device model in i2c bus 0.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/arm/aspeed.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index fd5603f7aa..3d13b16768 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1650,6 +1650,15 @@ static void 
aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
 }
 
 #ifdef TARGET_AARCH64
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+AspeedSoCState *soc = bmc->soc;
+
+/* LM75 is compatible with TMP105 driver */
+i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+TYPE_TMP105, 0x4d);
+}
+
 static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 {
 MachineClass *mc = MACHINE_CLASS(oc);
@@ -1664,6 +1673,7 @@ static void 
aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 amc->num_cs= 2;
 amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
 amc->uart_default = ASPEED_DEV_UART12;
+amc->i2c_init  = ast2700_evb_i2c_init;
 mc->default_ram_size = 1 * GiB;
 aspeed_machine_class_init_cpus_defaults(mc);
 }
-- 
2.34.1




[PATCH v2 09/11] aspeed/soc: support I2C for AST2700

2024-08-07 Thread Jamin Lin via
Add I2C model for AST2700 I2C support.
The I2C controller registers base address is start at
0x14C0_F000 and its address space is 0x2000.

The AST2700 I2C controller has one source INTC per bus.
I2C buses interrupt are connected to GICINT130_INTC
from bit 0 to bit 15.
I2C bus 0 is connected to GICINT130_INTC at bit 0.
I2C bus 15 is connected to GICINT130_INTC at bit 15.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 0bbd66110b..e84141c13b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -61,6 +61,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_DIST]  =  0x1220,
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
+[ASPEED_DEV_I2C]   =  0x14C0F000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -374,6 +375,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
 object_initialize_child(obj, "adc", &s->adc, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+object_initialize_child(obj, "i2c", &s->i2c, typename);
 }
 
 /*
@@ -457,6 +461,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
 AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
 g_autofree char *sram_name = NULL;
+qemu_irq irq;
+struct gic_intc_orgate_info orgate_info;
 
 /* Default boot region (SPI memory or ROMs) */
 memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -639,6 +645,27 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
 
+/* I2C */
+object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+aspeed_soc_ast2700_get_intc_orgate(s, ASPEED_DEV_I2C, &orgate_info);
+for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+/*
+ * The AST2700 I2C controller has one source INTC per bus.
+ * I2C buses interrupt are connected to GICINT130_INTC
+ * from bit 0 to bit 15.
+ * I2C bus 0 is connected to GICINT130_INTC at bit 0.
+ * I2C bus 15 is connected to GICINT130_INTC at bit 15.
+ */
+irq = qdev_get_gpio_in(DEVICE(&a->intc.orgates[orgate_info.index]),
+   orgate_info.int_num + i);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+}
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v2 08/11] aspeed/soc: introduce a new API to get the INTC orgate information

2024-08-07 Thread Jamin Lin via
Currently, users can set the intc mapping table with
enumerated device id and device irq to get the INTC orgate
input pins. However, some devices use the continuous bits number in the
same orgate. To reduce the enumerated device id definition,
create a new API to get the INTC orgate index and source bit number
if users only provide the start bus number of device.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4257b5e8af..0bbd66110b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -164,6 +164,11 @@ struct gic_intc_irq_info {
 const int *ptr;
 };
 
+struct gic_intc_orgate_info {
+int index;
+int int_num;
+};
+
 static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
 {128,  aspeed_soc_ast2700_gic128_intcmap},
 {129,  NULL},
@@ -193,6 +198,27 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState 
*s, int dev)
 return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
 }
 
+static void aspeed_soc_ast2700_get_intc_orgate(AspeedSoCState *s, int dev,
+struct gic_intc_orgate_info *orgate_info)
+{
+AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+int i;
+
+for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+orgate_info->index = i;
+orgate_info->int_num = aspeed_soc_ast2700_gic_intcmap[i].ptr[dev];
+return;
+}
+}
+
+/*
+ * Invalid orgate index, device irq should be 128 to 136.
+ */
+g_assert_not_reached();
+}
+
 static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
 unsigned int size)
 {
-- 
2.34.1




[PATCH v2 06/11] hw/i2c/aspeed: support Tx/Rx buffer 64 bits address

2024-08-07 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

It have "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
and "Master DMA Mode Rx Buffer Base Address[39:32](0x64)"
to save the high part physical address of Tx/Rx buffer address
for master mode.

It have "Slave DMA Mode Tx Buffer Base Address[39:32](0x68)" and
"Slave DMA Mode Rx Buffer Base Address[39:32](0x6C)" to
save the high part physical address of Tx/Rx buffer address
for slave mode.

Ex: Tx buffer address for master mode [39:0]
The "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
bits [7:0] which corresponds the bits [39:32] of the 64 bits address of
the Tx buffer address.
The "Master DMA Mode Tx Buffer Base Address(0x30)" bits [31:0]
which corresponds the bits [31:0] of the 64 bits address
of the Tx buffer address.

Introduce a new has_dma64 class attribute and new registers of
new mode to support DMA 64 bits dram address.
Update new mode register number to 28.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 48 +
 include/hw/i2c/aspeed_i2c.h | 12 +-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 819a875839..c1ff80b1cf 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -140,6 +140,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
 unsigned size)
 {
+AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
 
 switch (offset) {
@@ -170,6 +171,16 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_CMD:
 value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
 break;
+case A_I2CM_DMA_TX_ADDR_HI:
+case A_I2CM_DMA_RX_ADDR_HI:
+case A_I2CS_DMA_TX_ADDR_HI:
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+__func__);
+value = -1;
+}
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR,
   "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -731,6 +742,42 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
   __func__);
 break;
+
+case A_I2CM_DMA_TX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_TX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CM_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CS_DMA_TX_ADDR_HI:
+qemu_log_mask(LOG_UNIMP,
+  "%s: Slave mode DMA TX Addr high is not implemented\n",
+  __func__);
+break;
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CS_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
   __func__, offset);
@@ -1554,6 +1601,7 @@ static void aspeed_2700_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
 aic->has_dma = true;
 aic->mem_size = 0x2000;
+aic->has_dma64 = true;
 }
 
 static const TypeInfo aspeed_2700_i2c_info = {
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 4f23dc10c3..2c4c81bd20 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -38,7 +38,7 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, 
ASPEED_I2C)
 #define ASPEED_I2C_SHARE_POOL_SIZE 0x800
 #define ASPEED_I2C_BUS_POOL_SIZE 0x20
 #define ASPEED_I2C_OLD_NUM_REG 11
-#define ASPEED_I2C_NEW_NUM_REG 22
+#define ASPEE

[PATCH v2 04/11] hw/i2c/aspeed: introduce a new dma_dram_offset attribute in AspeedI2Cbus

2024-08-07 Thread Jamin Lin via
The "Current DMA Operating Address Status(0x50)" register of
I2C new mode has been removed in AST2700.
This register is used for debugging and it is a read only register.

To support AST2700 DMA mode, introduce a new
dma_dram_offset class attribute in AspeedI2Cbus to save the
current DMA operating address.

ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

Set the dma_dram_offset data type to uint64_t for
64 bits dram address DMA support.

Both "DMA Mode Buffer Address Register(I2CD24 old mode)" and
"DMA Operating Address Status (I2CC50 new mode)" are used for showing the
low part dram offset bits [31:0], so change to read/write both register bits 
[31:0] in
bus register read/write functions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 51 +++--
 include/hw/i2c/aspeed_i2c.h |  9 +--
 2 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index abcb1d5330..2dea3a42a0 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 if (!aic->has_dma) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
 value = -1;
+break;
 }
+
+value = extract64(bus->dma_dram_offset, 0, 32);
 break;
 case A_I2CD_DMA_LEN:
 if (!aic->has_dma) {
@@ -150,9 +153,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_DMA_TX_ADDR:
 case A_I2CM_DMA_RX_ADDR:
 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:
@@ -161,6 +162,9 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CS_DMA_LEN_STS:
 /* Value is already set, don't do anything. */
 break;
+case A_I2CC_DMA_ADDR:
+value = extract64(bus->dma_dram_offset, 0, 32);
+break;
 case A_I2CS_INTR_STS:
 break;
 case A_I2CM_CMD:
@@ -210,18 +214,18 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t 
*data)
 {
 MemTxResult result;
 AspeedI2CState *s = bus->controller;
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
 
-result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+result = address_space_read(&s->dram_as, bus->dma_dram_offset,
 MEMTXATTRS_UNSPECIFIED, data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM read failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return -1;
 }
 
-bus->regs[reg_dma_addr]++;
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 return 0;
 }
@@ -291,7 +295,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
 uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
 RX_SIZE) + 1;
 
@@ -323,14 +326,17 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 data = i2c_recv(bus->bus);
 trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
   bus->regs[reg_dma_len], data);
-result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+result = address_space_write(&s->dram_as, bus->dma_dram_offset,
  MEMTXATTRS_UNSPECIFIED, &data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM write failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return;
 }
-bus->regs[reg_dma_addr]++;
+
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 /* In new mode, keep track of how many bytes we RXed */
 if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +642,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_DMA_TX_ADDR:
 bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
  

[PATCH v2 11/11] machine_aspeed.py: update to test I2C for AST2700

2024-08-07 Thread Jamin Lin via
Update test case to test lm75 temperature sensor.

Signed-off-by: Jamin Lin 
---
 tests/avocado/machine_aspeed.py | 16 
 1 file changed, 16 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index f8e263d37e..6935f5f57c 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -435,9 +435,25 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self):
  f'loader,addr=0x43000,cpu-num={i}')
 
 self.vm.add_args('-smp', str(num_cpu))
+self.vm.add_args('-device',
+ 
'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
 self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
 self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
+
 self.ssh_connect('root', '0penBmc', False)
+self.ssh_command('dmesg -c > /dev/null')
+
+self.ssh_command_output_contains(
+'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device '
+'&& dmesg -c',
+'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d');
+
+self.ssh_command_output_contains(
+'cat /sys/class/hwmon/hwmon20/temp1_input', '0')
+self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+property='temperature', value=18000)
+self.ssh_command_output_contains(
+'cat /sys/class/hwmon/hwmon20/temp1_input', '18000')
 
 class AST2x00MachineMMC(QemuSystemTest):
 
-- 
2.34.1




[PATCH v2 07/11] hw/i2c/aspeed: support high part dram offset for DMA 64 bits

2024-08-07 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

The AST2700 support the maximum DRAM size is 8 GB.
The DRAM physical address range is from "0x4__" to
"0x5__".

The DRAM offset range is from "0x0__" to
"0x1__" and it is enough to use bits [33:0]
saving the dram offset.

Therefore, save the high part physical address bit[1:0]
of Tx/Rx buffer address as dma_dram_offset bit[33:32].
It does not need to decrease the dram physical
high part address for DMA operation.
(high part physical address bit[7:0] – 4)

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index c1ff80b1cf..44c3c39233 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -743,6 +743,14 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
   __func__);
 break;
 
+/*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0__ to
+ * 0x1__ and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
 case A_I2CM_DMA_TX_ADDR_HI:
 if (!aic->has_dma64) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
@@ -752,6 +760,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_TX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CM_DMA_RX_ADDR_HI:
 if (!aic->has_dma64) {
@@ -762,6 +772,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CS_DMA_TX_ADDR_HI:
 qemu_log_mask(LOG_UNIMP,
@@ -777,6 +789,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CS_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
-- 
2.34.1




[PATCH v2 01/11] hw/i2c/aspeed: support discontinuous register memory region of I2C bus

2024-08-07 Thread Jamin Lin via
It only support continuous register memory region for all I2C bus.
However, the register address of all I2c bus are discontinuous
for AST2700.

Ex: the register address of I2C bus for ast2700 as following.
0x100 - 0x17F: Device 0
0x200 - 0x27F: Device 1
0x300 - 0x37F: Device 2
0x400 - 0x47F: Device 3
0x500 - 0x57F: Device 4
0x600 - 0x67F: Device 5
0x700 - 0x77F: Device 6
0x800 - 0x87F: Device 7
0x900 - 0x97F: Device 8
0xA00 - 0xA7F: Device 9
0xB00 - 0xB7F: Device 10
0xC00 - 0xC7F: Device 11
0xD00 - 0xD7F: Device 12
0xE00 - 0xE7F: Device 13
0xF00 – 0xF7F: Device 14
0x1000 – 0x107F: Device 15

Introduce a new class attribute to make user set each I2C bus gap size.
Update formula to create all I2C bus register memory regions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b52a99896c..9c222a02fe 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1012,6 +1012,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1034,7 +1035,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 
-memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
 &s->busses[i].mr);
 }
 
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index fad5e9259a..02ede85906 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -275,6 +275,7 @@ struct AspeedI2CClass {
 
 uint8_t num_busses;
 uint8_t reg_size;
+uint32_t reg_gap_size;
 uint8_t gap;
 qemu_irq (*bus_get_irq)(AspeedI2CBus *);
 
-- 
2.34.1




[PATCH v2 02/11] hw/i2c/aspeed: introduce a new bus pool buffer attribute in AspeedI2Cbus

2024-08-07 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
each I2C bus has their own pool buffer since AST2500.
Only AST2400 utilized a pool buffer share to all I2C bus.
Besides, using a share pool buffer only support
pool buffer memory regions are continuous for all I2C bus.

To make this model more readable and support discontinuous
bus pool buffer memory regions, changes to introduce
a new bus pool buffer attribute in AspeedI2Cbus and
new memops. So, it does not need to calculate
the pool buffer offset for different I2C bus.

Introduce a new has_share_pool class attribute in AspeedI2CClass and
use it to create either a share pool buffer or bus pool buffers
in aspeed_i2c_realize. Update each pull buffer size to 0x10 for AST2500
and 0x20 for AST2600 and AST1030.

Incrementing the version of aspeed_i2c_bus_vmstate to 6.

Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/i2c/aspeed_i2c.c | 131 +++-
 include/hw/i2c/aspeed_i2c.h |   4 ++
 2 files changed, 117 insertions(+), 18 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 9c222a02fe..d3d49340ea 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -941,12 +941,48 @@ static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
 },
 };
 
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+AspeedI2CBus *s = opaque;
+uint64_t ret = 0;
+int i;
+
+for (i = 0; i < size; i++) {
+ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+}
+
+return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+  uint64_t value, unsigned size)
+{
+AspeedI2CBus *s = opaque;
+int i;
+
+for (i = 0; i < size; i++) {
+s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+}
+}
+
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+.read = aspeed_i2c_bus_pool_read,
+.write = aspeed_i2c_bus_pool_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 4,
+},
+};
+
 static const VMStateDescription aspeed_i2c_bus_vmstate = {
 .name = TYPE_ASPEED_I2C,
-.version_id = 5,
-.minimum_version_id = 5,
+.version_id = 6,
+.minimum_version_id = 6,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -996,7 +1032,21 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x140 ... 0x17F: Device 5
  *   0x180 ... 0x1BF: Device 6
  *   0x1C0 ... 0x1FF: Device 7
- *   0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
+ *   0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ *   0x210 ... 0x21F: Device 2 buffer
+ *   0x220 ... 0x22F: Device 3 buffer
+ *   0x230 ... 0x23F: Device 4 buffer
+ *   0x240 ... 0x24F: Device 5 buffer
+ *   0x250 ... 0x25F: Device 6 buffer
+ *   0x260 ... 0x26F: Device 7 buffer
+ *   0x270 ... 0x27F: Device 8 buffer
+ *   0x280 ... 0x28F: Device 9 buffer
+ *   0x290 ... 0x29F: Device 10 buffer
+ *   0x2A0 ... 0x2AF: Device 11 buffer
+ *   0x2B0 ... 0x2BF: Device 12 buffer
+ *   0x2C0 ... 0x2CF: Device 13 buffer
+ *   0x2D0 ... 0x2DF: Device 14 buffer
+ *   0x2E0 ... 0x2FF: Reserved
  *   0x300 ... 0x33F: Device 8
  *   0x340 ... 0x37F: Device 9
  *   0x380 ... 0x3BF: Device 10
@@ -1005,6 +1055,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x440 ... 0x47F: Device 13
  *   0x480 ... 0x4BF: Device 14
  *   0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ *   0x000 ... 0x07F: Global Register
+ *   0x080 ... 0x0FF: Device 1
+ *   0x100 ... 0x17F: Device 2
+ *   0x180 ... 0x1FF: Device 3
+ *   0x200 ... 0x27F: Device 4
+ *   0x280 ... 0x2FF: Device 5
+ *   0x300 ... 0x37F: Device 6
+ *   0x380 ... 0x3FF: Device 7
+ *   0x400 ... 0x47F: Device 8
+ *   0x480 ... 0x4FF: Device 9
+ *   0x500 ... 0x57F: Device 10
+ *   0x580 ... 0x5FF: Device 11
+ *   0x600 ... 0x67F: Device 12
+ *   0x680 ... 0x6FF: Device 13
+ *   0x700 ... 0x77F: Device 14
+ *   0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ *   0x800 ... 0x87F: Device 16
+ *   0xC00 ... 0xC1F: Device 1 buffer
+ *   0xC20 ... 0xC3F: Device 2 buffer
+ *   0xC40 ... 0xC5F: Device 3 buffer
+ *   0xC60 ... 0xC7F: Device 4 buffer
+ *   0xC80 ... 0xC9F: Device 5 buffer
+ *   0xCA0 ... 0xCBF: Device 6 buffer
+ *   0xCC0 ... 0xCDF: Device 7 buffer
+ *   0xCE0 ... 0xCFF: Device 8 buffer
+ *   0xD00 ... 0xD1F: Device 9 buffer
+ *   0xD20 ... 0xD3F: Device 10 buffer
+ *   0xD40 ... 0xD5F: Device 11 buffer
+ *   0xD60 ... 0xD7F: Device 12 buffer
+ *   0xD80 ... 0xD9F: Device 13 buffer
+ *   0xDA0 ... 0xDBF: Device 14 buffer
+ *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)

[PATCH v2 05/11] hw/i2c/aspeed: Add AST2700 support

2024-08-07 Thread Jamin Lin via
Introduce a new ast2700 class to support AST2700.
The I2C bus register memory regions and
I2C bus pool buffer memory regions are discontinuous
and they do not back compatible AST2600.

Add a new ast2700 i2c class init function to match the
address of I2C bus register and pool buffer from the datasheet.

An I2C controller registers owns 8KB address space.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 62 +
 include/hw/i2c/aspeed_i2c.h |  1 +
 2 files changed, 63 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 2dea3a42a0..819a875839 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1102,6 +1102,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0xDA0 ... 0xDBF: Device 14 buffer
  *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
  *   0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ *   0x000 ... 0x0FF: Global Register
+ *   0x100 ... 0x17F: Device 0
+ *   0x1A0 ... 0x1BF: Device 0 buffer
+ *   0x200 ... 0x27F: Device 1
+ *   0x2A0 ... 0x2BF: Device 1 buffer
+ *   0x300 ... 0x37F: Device 2
+ *   0x3A0 ... 0x3BF: Device 2 buffer
+ *   0x400 ... 0x47F: Device 3
+ *   0x4A0 ... 0x4BF: Device 3 buffer
+ *   0x500 ... 0x57F: Device 4
+ *   0x5A0 ... 0x5BF: Device 4 buffer
+ *   0x600 ... 0x67F: Device 5
+ *   0x6A0 ... 0x6BF: Device 5 buffer
+ *   0x700 ... 0x77F: Device 6
+ *   0x7A0 ... 0x7BF: Device 6 buffer
+ *   0x800 ... 0x87F: Device 7
+ *   0x8A0 ... 0x8BF: Device 7 buffer
+ *   0x900 ... 0x97F: Device 8
+ *   0x9A0 ... 0x9BF: Device 8 buffer
+ *   0xA00 ... 0xA7F: Device 9
+ *   0xAA0 ... 0xABF: Device 9 buffer
+ *   0xB00 ... 0xB7F: Device 10
+ *   0xBA0 ... 0xBBF: Device 10 buffer
+ *   0xC00 ... 0xC7F: Device 11
+ *   0xCA0 ... 0xCBF: Device 11 buffer
+ *   0xD00 ... 0xD7F: Device 12
+ *   0xDA0 ... 0xDBF: Device 12 buffer
+ *   0xE00 ... 0xE7F: Device 13
+ *   0xEA0 ... 0xEBF: Device 13 buffer
+ *   0xF00 ... 0xF7F: Device 14
+ *   0xFA0 ... 0xFBF: Device 14 buffer
+ *   0x1000 ... 0x107F: Device 15
+ *   0x10A0 ... 0x10BF: Device 15 buffer
  */
 static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
 {
@@ -1501,6 +1536,32 @@ static const TypeInfo aspeed_1030_i2c_info = {
 .class_init = aspeed_1030_i2c_class_init,
 };
 
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+dc->desc = "ASPEED 2700 I2C Controller";
+
+aic->num_busses = 16;
+aic->reg_size = 0x80;
+aic->reg_gap_size = 0x80;
+aic->gap = -1; /* no gap */
+aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+aic->pool_size = 0x20;
+aic->pool_gap_size = 0xe0;
+aic->pool_base = 0x1a0;
+aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+aic->has_dma = true;
+aic->mem_size = 0x2000;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+.name = TYPE_ASPEED_2700_I2C,
+.parent = TYPE_ASPEED_I2C,
+.class_init = aspeed_2700_i2c_class_init,
+};
+
 static void aspeed_i2c_register_types(void)
 {
 type_register_static(&aspeed_i2c_bus_info);
@@ -1510,6 +1571,7 @@ static void aspeed_i2c_register_types(void)
 type_register_static(&aspeed_2500_i2c_info);
 type_register_static(&aspeed_2600_i2c_info);
 type_register_static(&aspeed_1030_i2c_info);
+type_register_static(&aspeed_2700_i2c_info);
 }
 
 type_init(aspeed_i2c_register_types)
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index bdaea3207d..4f23dc10c3 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -31,6 +31,7 @@
 #define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
 #define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
 #define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030"
+#define TYPE_ASPEED_2700_I2C TYPE_ASPEED_I2C "-ast2700"
 OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 
 #define ASPEED_I2C_NR_BUSSES 16
-- 
2.34.1




[PATCH v2 03/11] hw/i2c/aspeed: support discontinuous poll buffer memory region of I2C bus

2024-08-07 Thread Jamin Lin via
It only support continuous pool buffer memory region for all I2C bus.
However, the pool buffer address of all I2c bus are discontinuous
for AST2700.

Ex: the pool buffer address of I2C bus for ast2700 as following.
0x1A0 - 0x1BF: Device 0 buffer
0x2A0 - 0x2BF: Device 1 buffer
0x3A0 - 0x3BF: Device 2 buffer
0x4A0 - 0x4BF: Device 3 buffer
0x5A0 - 0x5BF: Device 4 buffer
0x6A0 - 0x6BF: Device 5 buffer
0x7A0 - 0x7BF: Device 6 buffer
0x8A0 - 0x8BF: Device 7 buffer
0x9A0 - 0x9BF: Device 8 buffer
0xAA0 - 0xABF: Device 9 buffer
0xBA0 - 0xBBF: Device 10 buffer
0xCA0 - 0xCBF: Device 11 buffer
0xDA0 - 0xDBF: Device 12 buffer
0xEA0 - 0xEBF: Device 13 buffer
0xFA0 – 0xFBF: Device 14 buffer
0x10A0 – 0x10BF: Device 15 buffer

Introduce a new class attribute to make user set each I2C bus
pool buffer gap size. Update formula to create all I2C bus
pool buffer memory regions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index d3d49340ea..abcb1d5330 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1098,6 +1098,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
 uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1133,7 +1134,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 } else {
 for (i = 0; i < aic->num_busses; i++) {
 memory_region_add_subregion(&s->iomem,
-aic->pool_base + (aic->pool_size * i),
+aic->pool_base + (pool_offset * i),
 &s->busses[i].mr_pool);
 }
 }
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 8e62ec64f8..b42c4dc584 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -284,6 +284,7 @@ struct AspeedI2CClass {
 
 uint64_t pool_size;
 hwaddr pool_base;
+uint32_t pool_gap_size;
 uint8_t *(*bus_pool_base)(AspeedI2CBus *);
 bool check_sram;
 bool has_dma;
-- 
2.34.1




[PATCH v1 14/15] aspeed: fix coding style

2024-07-17 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Test command:
./scripts/checkpatch.pl --no-tree -f hw/arm/aspeed.c

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed.c | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 53a4f665d0..f8766ea462 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -265,7 +265,8 @@ static void write_boot_rom(BlockBackend *blk, hwaddr addr, 
size_t rom_size,
 g_autofree void *storage = NULL;
 int64_t size;
 
-/* The block backend size should have already been 'validated' by
+/*
+ * The block backend size should have already been 'validated' by
  * the creation of the m25p80 object.
  */
 size = blk_getlength(blk);
@@ -463,8 +464,10 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc)
 DeviceState *dev;
 uint8_t *eeprom_buf = g_malloc0(32 * 1024);
 
-/* The palmetto platform expects a ds3231 RTC but a ds1338 is
- * enough to provide basic RTC features. Alarms will be missing */
+/*
+ * The palmetto platform expects a ds3231 RTC but a ds1338 is
+ * enough to provide basic RTC features. Alarms will be missing
+ */
 i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "ds1338", 0x68);
 
 smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50,
@@ -555,8 +558,10 @@ static void romulus_bmc_i2c_init(AspeedMachineState *bmc)
 {
 AspeedSoCState *soc = bmc->soc;
 
-/* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
- * good enough */
+/*
+ * The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough
+ */
 i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32);
 }
 
@@ -664,8 +669,10 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState 
*bmc)
 i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), TYPE_TMP105,
  0x4a);
 
-/* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
- * good enough */
+/*
+ * The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough
+ */
 i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32);
 
 smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 11), 0x51,
-- 
2.34.1




[PATCH v1 12/15] aspeed/soc: introduce a new API to get the INTC orgate information

2024-07-17 Thread Jamin Lin via
Currently, users can set the intc mapping table with
enumerated device id and device irq to get the INTC orgate
input pins. However, some devices use the continuous bits number in the
same orgate. To reduce the enumerated device id definition,
create a new API to get the INTC orgate index and source bit number
if users only provide the start bus number of device.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4257b5e8af..0bbd66110b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -164,6 +164,11 @@ struct gic_intc_irq_info {
 const int *ptr;
 };
 
+struct gic_intc_orgate_info {
+int index;
+int int_num;
+};
+
 static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
 {128,  aspeed_soc_ast2700_gic128_intcmap},
 {129,  NULL},
@@ -193,6 +198,27 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState 
*s, int dev)
 return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
 }
 
+static void aspeed_soc_ast2700_get_intc_orgate(AspeedSoCState *s, int dev,
+struct gic_intc_orgate_info *orgate_info)
+{
+AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+int i;
+
+for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+orgate_info->index = i;
+orgate_info->int_num = aspeed_soc_ast2700_gic_intcmap[i].ptr[dev];
+return;
+}
+}
+
+/*
+ * Invalid orgate index, device irq should be 128 to 136.
+ */
+g_assert_not_reached();
+}
+
 static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
 unsigned int size)
 {
-- 
2.34.1




[PATCH v1 06/15] hw/i2c/aspeed: introduce a new bus pool buffer attribute in AspeedI2Cbus

2024-07-17 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
each I2C bus has their own pool buffer since AST2500.
Only AST2400 utilized a pool buffer share to all I2C bus.
Besides, using a share pool buffer only support
pool buffer memory regions are continuous for all I2C bus.

To make this model more readable and support discontinuous
bus pool buffer memory regions, changes to introduce
a new bus pool buffer attribute in AspeedI2Cbus and
new memops. So, it does not need to calculate
the pool buffer offset for different I2C bus.

Introduce a new has_share_pool class attribute in AspeedI2CClass and
use it to create either a share pool buffer or bus pool buffers
in aspeed_i2c_realize. Update each pull buffer size to 0x10 for AST2500
and 0x20 for AST2600 and AST1030.

Incrementing the version of aspeed_i2c_bus_vmstate to 6.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 131 +++-
 include/hw/i2c/aspeed_i2c.h |   4 ++
 2 files changed, 117 insertions(+), 18 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 9c222a02fe..d3d49340ea 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -941,12 +941,48 @@ static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
 },
 };
 
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+AspeedI2CBus *s = opaque;
+uint64_t ret = 0;
+int i;
+
+for (i = 0; i < size; i++) {
+ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+}
+
+return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+  uint64_t value, unsigned size)
+{
+AspeedI2CBus *s = opaque;
+int i;
+
+for (i = 0; i < size; i++) {
+s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+}
+}
+
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+.read = aspeed_i2c_bus_pool_read,
+.write = aspeed_i2c_bus_pool_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 4,
+},
+};
+
 static const VMStateDescription aspeed_i2c_bus_vmstate = {
 .name = TYPE_ASPEED_I2C,
-.version_id = 5,
-.minimum_version_id = 5,
+.version_id = 6,
+.minimum_version_id = 6,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -996,7 +1032,21 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x140 ... 0x17F: Device 5
  *   0x180 ... 0x1BF: Device 6
  *   0x1C0 ... 0x1FF: Device 7
- *   0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
+ *   0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ *   0x210 ... 0x21F: Device 2 buffer
+ *   0x220 ... 0x22F: Device 3 buffer
+ *   0x230 ... 0x23F: Device 4 buffer
+ *   0x240 ... 0x24F: Device 5 buffer
+ *   0x250 ... 0x25F: Device 6 buffer
+ *   0x260 ... 0x26F: Device 7 buffer
+ *   0x270 ... 0x27F: Device 8 buffer
+ *   0x280 ... 0x28F: Device 9 buffer
+ *   0x290 ... 0x29F: Device 10 buffer
+ *   0x2A0 ... 0x2AF: Device 11 buffer
+ *   0x2B0 ... 0x2BF: Device 12 buffer
+ *   0x2C0 ... 0x2CF: Device 13 buffer
+ *   0x2D0 ... 0x2DF: Device 14 buffer
+ *   0x2E0 ... 0x2FF: Reserved
  *   0x300 ... 0x33F: Device 8
  *   0x340 ... 0x37F: Device 9
  *   0x380 ... 0x3BF: Device 10
@@ -1005,6 +1055,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x440 ... 0x47F: Device 13
  *   0x480 ... 0x4BF: Device 14
  *   0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ *   0x000 ... 0x07F: Global Register
+ *   0x080 ... 0x0FF: Device 1
+ *   0x100 ... 0x17F: Device 2
+ *   0x180 ... 0x1FF: Device 3
+ *   0x200 ... 0x27F: Device 4
+ *   0x280 ... 0x2FF: Device 5
+ *   0x300 ... 0x37F: Device 6
+ *   0x380 ... 0x3FF: Device 7
+ *   0x400 ... 0x47F: Device 8
+ *   0x480 ... 0x4FF: Device 9
+ *   0x500 ... 0x57F: Device 10
+ *   0x580 ... 0x5FF: Device 11
+ *   0x600 ... 0x67F: Device 12
+ *   0x680 ... 0x6FF: Device 13
+ *   0x700 ... 0x77F: Device 14
+ *   0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ *   0x800 ... 0x87F: Device 16
+ *   0xC00 ... 0xC1F: Device 1 buffer
+ *   0xC20 ... 0xC3F: Device 2 buffer
+ *   0xC40 ... 0xC5F: Device 3 buffer
+ *   0xC60 ... 0xC7F: Device 4 buffer
+ *   0xC80 ... 0xC9F: Device 5 buffer
+ *   0xCA0 ... 0xCBF: Device 6 buffer
+ *   0xCC0 ... 0xCDF: Device 7 buffer
+ *   0xCE0 ... 0xCFF: Device 8 buffer
+ *   0xD00 ... 0xD1F: Device 9 buffer
+ *   0xD20 ... 0xD3F: Device 10 buffer
+ *   0xD40 ... 0xD5F: Device 11 buffer
+ *   0xD60 ... 0xD7F: Device 12 buffer
+ *   0xD80 ... 0xD9F: Device 13 buffer
+ *   0xDA0 ... 0xDBF: Device 14 buffer
+ *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
+ *   0xDE0 ... 0xDFF: Device 1

[PATCH v1 07/15] hw/i2c/aspeed: support discontinuous poll buffer memory region of I2C bus

2024-07-17 Thread Jamin Lin via
It only support continuous pool buffer memory region for all I2C bus.
However, the pool buffer address of all I2c bus are discontinuous
for AST2700.

Ex: the pool buffer address of I2C bus for ast2700 as following.
0x1A0 - 0x1BF: Device 0 buffer
0x2A0 - 0x2BF: Device 1 buffer
0x3A0 - 0x3BF: Device 2 buffer
0x4A0 - 0x4BF: Device 3 buffer
0x5A0 - 0x5BF: Device 4 buffer
0x6A0 - 0x6BF: Device 5 buffer
0x7A0 - 0x7BF: Device 6 buffer
0x8A0 - 0x8BF: Device 7 buffer
0x9A0 - 0x9BF: Device 8 buffer
0xAA0 - 0xABF: Device 9 buffer
0xBA0 - 0xBBF: Device 10 buffer
0xCA0 - 0xCBF: Device 11 buffer
0xDA0 - 0xDBF: Device 12 buffer
0xEA0 - 0xEBF: Device 13 buffer
0xFA0 – 0xFBF: Device 14 buffer
0x10A0 – 0x10BF: Device 15 buffer

Introduce a new class attribute to make user set each I2C bus
pool buffer gap size. Update formula to create all I2C bus
pool buffer memory regions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index d3d49340ea..abcb1d5330 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1098,6 +1098,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
 uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1133,7 +1134,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 } else {
 for (i = 0; i < aic->num_busses; i++) {
 memory_region_add_subregion(&s->iomem,
-aic->pool_base + (aic->pool_size * i),
+aic->pool_base + (pool_offset * i),
 &s->busses[i].mr_pool);
 }
 }
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 8e62ec64f8..b42c4dc584 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -284,6 +284,7 @@ struct AspeedI2CClass {
 
 uint64_t pool_size;
 hwaddr pool_base;
+uint32_t pool_gap_size;
 uint8_t *(*bus_pool_base)(AspeedI2CBus *);
 bool check_sram;
 bool has_dma;
-- 
2.34.1




[PATCH v1 08/15] hw/i2c/aspeed: introduce a new dma_dram_offset attribute in AspeedI2Cbus

2024-07-17 Thread Jamin Lin via
The "Current DMA Operating Address Status(0x50)" register of
I2C new mode has been removed in AST2700.
This register is used for debugging and it is a read only register.

To support AST2700 DMA mode, introduce a new
dma_dram_offset class attribute in AspeedI2Cbus to save the
current DMA operating address.

ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

Set the dma_dram_offset data type to uint64_t for
64 bits dram address DMA support.

Both "DMA Mode Buffer Address Register(I2CD24 old mode)" and
"DMA Operating Address Status (I2CC50 new mode)" are used for showing the
low part dram offset bits [31:0], so change to read/write both register bits 
[31:0] in
bus register read/write functions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 50 +++--
 include/hw/i2c/aspeed_i2c.h |  9 +--
 2 files changed, 32 insertions(+), 27 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index abcb1d5330..c0d3ac3867 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 if (!aic->has_dma) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
 value = -1;
+break;
 }
+
+value = extract64(bus->dma_dram_offset, 0, 32);
 break;
 case A_I2CD_DMA_LEN:
 if (!aic->has_dma) {
@@ -150,9 +153,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_DMA_TX_ADDR:
 case A_I2CM_DMA_RX_ADDR:
 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:
@@ -161,6 +162,9 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CS_DMA_LEN_STS:
 /* Value is already set, don't do anything. */
 break;
+case A_I2CC_DMA_ADDR:
+value = extract64(bus->dma_dram_offset, 0, 32);
+break;
 case A_I2CS_INTR_STS:
 break;
 case A_I2CM_CMD:
@@ -210,18 +214,18 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t 
*data)
 {
 MemTxResult result;
 AspeedI2CState *s = bus->controller;
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
 
-result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+result = address_space_read(&s->dram_as, bus->dma_dram_offset,
 MEMTXATTRS_UNSPECIFIED, data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM read failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return -1;
 }
 
-bus->regs[reg_dma_addr]++;
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 return 0;
 }
@@ -291,7 +295,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
 uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
 uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
-uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
 int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
 RX_SIZE) + 1;
 
@@ -323,14 +326,17 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
 data = i2c_recv(bus->bus);
 trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
   bus->regs[reg_dma_len], data);
-result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+result = address_space_write(&s->dram_as, bus->dma_dram_offset,
  MEMTXATTRS_UNSPECIFIED, &data, 1);
 if (result != MEMTX_OK) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
-  __func__, bus->regs[reg_dma_addr]);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM write failed @%" PRIx64 "\n",
+  __func__, bus->dma_dram_offset);
 return;
 }
-bus->regs[reg_dma_addr]++;
+
+bus->dma_dram_offset++;
 bus->regs[reg_dma_len]--;
 /* In new mode, keep track of how many bytes we RXed */
 if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +642,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_DMA_TX_ADDR:
 bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
  

[PATCH v1 10/15] hw/i2c/aspeed: support Tx/Rx buffer 64 bits address

2024-07-17 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

It have "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
and "Master DMA Mode Rx Buffer Base Address[39:32](0x64)"
to save the high part physical address of Tx/Rx buffer address
for master mode.

It have "Slave DMA Mode Tx Buffer Base Address[39:32](0x68)" and
"Slave DMA Mode Rx Buffer Base Address[39:32](0x6C)" to
save the high part physical address of Tx/Rx buffer address
for slave mode.

Ex: Tx buffer address for master mode [39:0]
The "Master DMA Mode Tx Buffer Base Address[39:32](0x60)"
bits [7:0] which corresponds the bits [39:32] of the 64 bits address of
the Tx buffer address.
The "Master DMA Mode Tx Buffer Base Address(0x30)" bits [31:0]
which corresponds the bits [31:0] of the 64 bits address
of the Tx buffer address.

Introduce a new has_dma64 class attribute and new registers of
new mode to support DMA 64 bits dram address.
Update new mode register number to 28.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 48 +
 include/hw/i2c/aspeed_i2c.h | 12 +-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 29d400ac93..b48f250e08 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -140,6 +140,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, 
hwaddr offset,
 static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
 unsigned size)
 {
+AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
 
 switch (offset) {
@@ -170,6 +171,16 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, 
hwaddr offset,
 case A_I2CM_CMD:
 value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
 break;
+case A_I2CM_DMA_TX_ADDR_HI:
+case A_I2CM_DMA_RX_ADDR_HI:
+case A_I2CS_DMA_TX_ADDR_HI:
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+__func__);
+value = -1;
+}
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR,
   "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -731,6 +742,42 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
   __func__);
 break;
+
+case A_I2CM_DMA_TX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_TX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CM_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CM_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
+case A_I2CS_DMA_TX_ADDR_HI:
+qemu_log_mask(LOG_UNIMP,
+  "%s: Slave mode DMA TX Addr high is not implemented\n",
+  __func__);
+break;
+case A_I2CS_DMA_RX_ADDR_HI:
+if (!aic->has_dma64) {
+qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+  __func__);
+break;
+}
+bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+  I2CS_DMA_RX_ADDR_HI,
+  ADDR_HI);
+break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
   __func__, offset);
@@ -1553,6 +1600,7 @@ static void aspeed_2700_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
 aic->has_dma = true;
 aic->mem_size = 0x1;
+aic->has_dma64 = true;
 }
 
 static const TypeInfo aspeed_2700_i2c_info = {
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 4f23dc10c3..2c4c81bd20 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -38,7 +38,7 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, 
ASPEED_I2C)
 #define ASPEED_I2C_SHARE_POOL_SIZE 0x800
 #define ASPEED_I2C_BUS_POOL_SIZE 0x20
 #define ASPEED_I2C_OLD_NUM_REG 11
-#define ASPEED_I2C_NEW_NUM_REG 22
+#define ASPEED_I2C_NEW_NUM_REG 28
 
 #defin

[PATCH v1 11/15] hw/i2c/aspeed: support high part dram offset for DMA 64 bits

2024-07-17 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

The AST2700 support the maximum DRAM size is 8 GB.
The DRAM physical address range is from "0x4__" to
"0x5__".

The DRAM offset range is from "0x0__" to
"0x1__" and it is enough to use bits [33:0]
saving the dram offset.

Therefore, save the high part physical address bit[1:0]
of Tx/Rx buffer address as dma_dram_offset bit[33:32].
It does not need to decrease the dram physical
high part address for DMA operation.
(high part physical address bit[7:0] – 4)

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b48f250e08..e28deadcfc 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -743,6 +743,14 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
   __func__);
 break;
 
+/*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0__ to
+ * 0x1__ and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
 case A_I2CM_DMA_TX_ADDR_HI:
 if (!aic->has_dma64) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
@@ -752,6 +760,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_TX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CM_DMA_RX_ADDR_HI:
 if (!aic->has_dma64) {
@@ -762,6 +772,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CM_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 case A_I2CS_DMA_TX_ADDR_HI:
 qemu_log_mask(LOG_UNIMP,
@@ -777,6 +789,8 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, 
hwaddr offset,
 bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
   I2CS_DMA_RX_ADDR_HI,
   ADDR_HI);
+bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
 break;
 default:
 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
-- 
2.34.1




[PATCH v1 13/15] aspeed/soc: support I2C for AST2700

2024-07-17 Thread Jamin Lin via
Add I2C model for AST2700 I2C support.
The I2C controller registers base address is start at
0x14C0_F000 and its address space is 0x2000.

The AST2700 I2C controller has one source INTC per bus.
I2C buses interrupt are connected to GICINT130_INTC
from bit 0 to bit 15.
I2C bus 0 is connected to GICINT130_INTC at bit 0.
I2C bus 15 is connected to GICINT130_INTC at bit 15.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 0bbd66110b..e84141c13b 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -61,6 +61,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_GIC_DIST]  =  0x1220,
 [ASPEED_GIC_REDIST]=  0x1228,
 [ASPEED_DEV_ADC]   =  0x14C0,
+[ASPEED_DEV_I2C]   =  0x14C0F000,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -374,6 +375,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 
 snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
 object_initialize_child(obj, "adc", &s->adc, typename);
+
+snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+object_initialize_child(obj, "i2c", &s->i2c, typename);
 }
 
 /*
@@ -457,6 +461,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
 AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
 g_autofree char *sram_name = NULL;
+qemu_irq irq;
+struct gic_intc_orgate_info orgate_info;
 
 /* Default boot region (SPI memory or ROMs) */
 memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -639,6 +645,27 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
 
+/* I2C */
+object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+aspeed_soc_ast2700_get_intc_orgate(s, ASPEED_DEV_I2C, &orgate_info);
+for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+/*
+ * The AST2700 I2C controller has one source INTC per bus.
+ * I2C buses interrupt are connected to GICINT130_INTC
+ * from bit 0 to bit 15.
+ * I2C bus 0 is connected to GICINT130_INTC at bit 0.
+ * I2C bus 15 is connected to GICINT130_INTC at bit 15.
+ */
+irq = qdev_get_gpio_in(DEVICE(&a->intc.orgates[orgate_info.index]),
+   orgate_info.int_num + i);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+}
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v1 15/15] aspeed: add tmp105 in i2c bus 0 for AST2700

2024-07-17 Thread Jamin Lin via
ASPEED SDK add lm75 in i2c bus 0 for AST2700.
LM75 is compatible with TMP105 driver.

Introduce a new i2c init function and
add tmp105 device model in i2c bus 0.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index f8766ea462..ed98758708 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1604,6 +1604,15 @@ static void 
aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
 }
 
 #ifdef TARGET_AARCH64
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+AspeedSoCState *soc = bmc->soc;
+
+/* LM75 is compatible with TMP105 driver */
+i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+TYPE_TMP105, 0x4d);
+}
+
 static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 {
 MachineClass *mc = MACHINE_CLASS(oc);
@@ -1618,6 +1627,7 @@ static void 
aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
 amc->num_cs= 2;
 amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
 amc->uart_default = ASPEED_DEV_UART12;
+amc->i2c_init  = ast2700_evb_i2c_init;
 mc->default_ram_size = 1 * GiB;
 aspeed_machine_class_init_cpus_defaults(mc);
 }
-- 
2.34.1




[PATCH v1 05/15] hw/i2c/aspeed: rename the I2C class pool attribute to share_pool

2024-07-17 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
each I2C bus has their own pool buffer since AST2500.

Only AST2400 utilized a pool buffer share to all I2C bus.
And firmware required to set the offset of pool buffer
by writing "Function Control Register(I2CD 00)"

To make this model more readable, will change to introduce
a new bus pool buffer attribute in AspeedI2Cbus.
So, it does not need to calculate the pool buffer offset
for different I2C bus.

This patch rename the I2C class pool attribute to share_pool.
It make user more understand share pool and bus pool
are different.

Incrementing the version of aspeed_i2c_vmstate to 3.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 39 -
 include/hw/i2c/aspeed_i2c.h |  4 ++--
 2 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 462ad78a13..9c222a02fe 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -906,7 +906,7 @@ static const MemoryRegionOps aspeed_i2c_ctrl_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset,
+static uint64_t aspeed_i2c_share_pool_read(void *opaque, hwaddr offset,
  unsigned size)
 {
 AspeedI2CState *s = opaque;
@@ -914,26 +914,26 @@ static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr 
offset,
 int i;
 
 for (i = 0; i < size; i++) {
-ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+ret |= (uint64_t) s->share_pool[offset + i] << (8 * i);
 }
 
 return ret;
 }
 
-static void aspeed_i2c_pool_write(void *opaque, hwaddr offset,
+static void aspeed_i2c_share_pool_write(void *opaque, hwaddr offset,
   uint64_t value, unsigned size)
 {
 AspeedI2CState *s = opaque;
 int i;
 
 for (i = 0; i < size; i++) {
-s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+s->share_pool[offset + i] = (value >> (8 * i)) & 0xFF;
 }
 }
 
-static const MemoryRegionOps aspeed_i2c_pool_ops = {
-.read = aspeed_i2c_pool_read,
-.write = aspeed_i2c_pool_write,
+static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
+.read = aspeed_i2c_share_pool_read,
+.write = aspeed_i2c_share_pool_write,
 .endianness = DEVICE_LITTLE_ENDIAN,
 .valid = {
 .min_access_size = 1,
@@ -953,14 +953,15 @@ static const VMStateDescription aspeed_i2c_bus_vmstate = {
 
 static const VMStateDescription aspeed_i2c_vmstate = {
 .name = TYPE_ASPEED_I2C,
-.version_id = 2,
-.minimum_version_id = 2,
+.version_id = 3,
+.minimum_version_id = 3,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32(intr_status, AspeedI2CState),
 VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
  ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
  AspeedI2CBus),
-VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE),
+VMSTATE_UINT8_ARRAY(share_pool, AspeedI2CState,
+ASPEED_I2C_SHARE_POOL_SIZE),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -995,7 +996,7 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x140 ... 0x17F: Device 5
  *   0x180 ... 0x1BF: Device 6
  *   0x1C0 ... 0x1FF: Device 7
- *   0x200 ... 0x2FF: Buffer Pool  (unused in linux driver)
+ *   0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
  *   0x300 ... 0x33F: Device 8
  *   0x340 ... 0x37F: Device 9
  *   0x380 ... 0x3BF: Device 10
@@ -1003,7 +1004,7 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0x400 ... 0x43F: Device 12
  *   0x440 ... 0x47F: Device 13
  *   0x480 ... 0x4BF: Device 14
- *   0x800 ... 0xFFF: Buffer Pool  (unused in linux driver)
+ *   0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
  */
 static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
 {
@@ -1038,8 +1039,9 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 &s->busses[i].mr);
 }
 
-memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s,
-  "aspeed.i2c-pool", aic->pool_size);
+memory_region_init_io(&s->pool_iomem, OBJECT(s),
+  &aspeed_i2c_share_pool_ops, s,
+  "aspeed.i2c-share-pool", aic->pool_size);
 memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem);
 
 if (aic->has_dma) {
@@ -1267,8 +1269,9 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus 
*bus)
 static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
 {
 uint8_t *pool_page =
-&bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
-POOL_PAGE_SEL) * 0x100];
+&bus->controller->share_pool[ARRAY_FIELD_EX32(bus->regs,
+  I2CD_FUN_CTRL,
+  

[PATCH v1 09/15] hw/i2c/aspeed: Add AST2700 support

2024-07-17 Thread Jamin Lin via
Introduce a new ast2700 class to support AST2700.
The I2C bus register memory regions and
I2C bus pool buffer memory regions are discontinuous
and they do not back compatible AST2600.

Add a new ast2700 i2c class init function to match the
address of I2C bus register and pool buffer from the datasheet.

An I2C controller registers owns 8KB address space.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 62 +
 include/hw/i2c/aspeed_i2c.h |  1 +
 2 files changed, 63 insertions(+)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index c0d3ac3867..29d400ac93 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1101,6 +1101,41 @@ static void aspeed_i2c_instance_init(Object *obj)
  *   0xDA0 ... 0xDBF: Device 14 buffer
  *   0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
  *   0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ *   0x000 ... 0x0FF: Global Register
+ *   0x100 ... 0x17F: Device 0
+ *   0x1A0 ... 0x1BF: Device 0 buffer
+ *   0x200 ... 0x27F: Device 1
+ *   0x2A0 ... 0x2BF: Device 1 buffer
+ *   0x300 ... 0x37F: Device 2
+ *   0x3A0 ... 0x3BF: Device 2 buffer
+ *   0x400 ... 0x47F: Device 3
+ *   0x4A0 ... 0x4BF: Device 3 buffer
+ *   0x500 ... 0x57F: Device 4
+ *   0x5A0 ... 0x5BF: Device 4 buffer
+ *   0x600 ... 0x67F: Device 5
+ *   0x6A0 ... 0x6BF: Device 5 buffer
+ *   0x700 ... 0x77F: Device 6
+ *   0x7A0 ... 0x7BF: Device 6 buffer
+ *   0x800 ... 0x87F: Device 7
+ *   0x8A0 ... 0x8BF: Device 7 buffer
+ *   0x900 ... 0x97F: Device 8
+ *   0x9A0 ... 0x9BF: Device 8 buffer
+ *   0xA00 ... 0xA7F: Device 9
+ *   0xAA0 ... 0xABF: Device 9 buffer
+ *   0xB00 ... 0xB7F: Device 10
+ *   0xBA0 ... 0xBBF: Device 10 buffer
+ *   0xC00 ... 0xC7F: Device 11
+ *   0xCA0 ... 0xCBF: Device 11 buffer
+ *   0xD00 ... 0xD7F: Device 12
+ *   0xDA0 ... 0xDBF: Device 12 buffer
+ *   0xE00 ... 0xE7F: Device 13
+ *   0xEA0 ... 0xEBF: Device 13 buffer
+ *   0xF00 ... 0xF7F: Device 14
+ *   0xFA0 ... 0xFBF: Device 14 buffer
+ *   0x1000 ... 0x107F: Device 15
+ *   0x10A0 ... 0x10BF: Device 15 buffer
  */
 static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
 {
@@ -1500,6 +1535,32 @@ static const TypeInfo aspeed_1030_i2c_info = {
 .class_init = aspeed_1030_i2c_class_init,
 };
 
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+dc->desc = "ASPEED 2700 I2C Controller";
+
+aic->num_busses = 16;
+aic->reg_size = 0x80;
+aic->reg_gap_size = 0x80;
+aic->gap = -1; /* no gap */
+aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+aic->pool_size = 0x20;
+aic->pool_gap_size = 0xe0;
+aic->pool_base = 0x1a0;
+aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+aic->has_dma = true;
+aic->mem_size = 0x1;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+.name = TYPE_ASPEED_2700_I2C,
+.parent = TYPE_ASPEED_I2C,
+.class_init = aspeed_2700_i2c_class_init,
+};
+
 static void aspeed_i2c_register_types(void)
 {
 type_register_static(&aspeed_i2c_bus_info);
@@ -1509,6 +1570,7 @@ static void aspeed_i2c_register_types(void)
 type_register_static(&aspeed_2500_i2c_info);
 type_register_static(&aspeed_2600_i2c_info);
 type_register_static(&aspeed_1030_i2c_info);
+type_register_static(&aspeed_2700_i2c_info);
 }
 
 type_init(aspeed_i2c_register_types)
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index bdaea3207d..4f23dc10c3 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -31,6 +31,7 @@
 #define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
 #define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
 #define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030"
+#define TYPE_ASPEED_2700_I2C TYPE_ASPEED_I2C "-ast2700"
 OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 
 #define ASPEED_I2C_NR_BUSSES 16
-- 
2.34.1




[PATCH v1 01/15] aspeed/adc: Add AST2700 support

2024-07-17 Thread Jamin Lin via
AST2700 and AST2600 ADC controllers are identical.
Introduce ast2700 class and set 2 engines.

Signed-off-by: Jamin Lin 
---
 hw/adc/aspeed_adc.c | 16 
 include/hw/adc/aspeed_adc.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c
index 68bdbc73b0..48328ef891 100644
--- a/hw/adc/aspeed_adc.c
+++ b/hw/adc/aspeed_adc.c
@@ -398,6 +398,15 @@ static void aspeed_1030_adc_class_init(ObjectClass *klass, 
void *data)
 aac->nr_engines = 2;
 }
 
+static void aspeed_2700_adc_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
+
+dc->desc = "ASPEED 2700 ADC Controller";
+aac->nr_engines = 2;
+}
+
 static const TypeInfo aspeed_adc_info = {
 .name = TYPE_ASPEED_ADC,
 .parent = TYPE_SYS_BUS_DEVICE,
@@ -430,6 +439,12 @@ static const TypeInfo aspeed_1030_adc_info = {
 .class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */
 };
 
+static const TypeInfo aspeed_2700_adc_info = {
+.name = TYPE_ASPEED_2700_ADC,
+.parent = TYPE_ASPEED_ADC,
+.class_init = aspeed_2700_adc_class_init,
+};
+
 static void aspeed_adc_register_types(void)
 {
 type_register_static(&aspeed_adc_engine_info);
@@ -438,6 +453,7 @@ static void aspeed_adc_register_types(void)
 type_register_static(&aspeed_2500_adc_info);
 type_register_static(&aspeed_2600_adc_info);
 type_register_static(&aspeed_1030_adc_info);
+type_register_static(&aspeed_2700_adc_info);
 }
 
 type_init(aspeed_adc_register_types);
diff --git a/include/hw/adc/aspeed_adc.h b/include/hw/adc/aspeed_adc.h
index ff1d06ea91..f502f197ac 100644
--- a/include/hw/adc/aspeed_adc.h
+++ b/include/hw/adc/aspeed_adc.h
@@ -18,6 +18,7 @@
 #define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500"
 #define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600"
 #define TYPE_ASPEED_1030_ADC TYPE_ASPEED_ADC "-ast1030"
+#define TYPE_ASPEED_2700_ADC TYPE_ASPEED_ADC "-ast2700"
 OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC)
 
 #define TYPE_ASPEED_ADC_ENGINE "aspeed.adc.engine"
-- 
2.34.1




[PATCH v1 04/15] hw/i2c/aspeed: support discontinuous register memory region of I2C bus

2024-07-17 Thread Jamin Lin via
It only support continuous register memory region for all I2C bus.
However, the register address of all I2c bus are discontinuous
for AST2700.

Ex: the register address of I2C bus for ast2700 as following.
0x100 - 0x17F: Device 0
0x200 - 0x27F: Device 1
0x300 - 0x37F: Device 2
0x400 - 0x47F: Device 3
0x500 - 0x57F: Device 4
0x600 - 0x67F: Device 5
0x700 - 0x77F: Device 6
0x800 - 0x87F: Device 7
0x900 - 0x97F: Device 8
0xA00 - 0xA7F: Device 9
0xB00 - 0xB7F: Device 10
0xC00 - 0xC7F: Device 11
0xD00 - 0xD7F: Device 12
0xE00 - 0xE7F: Device 13
0xF00 – 0xF7F: Device 14
0x1000 – 0x107F: Device 15

Introduce a new class attribute to make user set each I2C bus gap size.
Update formula to create all I2C bus register memory regions.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 3 ++-
 include/hw/i2c/aspeed_i2c.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 7d5a53c4c0..462ad78a13 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1011,6 +1011,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 AspeedI2CState *s = ASPEED_I2C(dev);
 AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1033,7 +1034,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 
-memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
 &s->busses[i].mr);
 }
 
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 065b636d29..422ee0e298 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -275,6 +275,7 @@ struct AspeedI2CClass {
 
 uint8_t num_busses;
 uint8_t reg_size;
+uint32_t reg_gap_size;
 uint8_t gap;
 qemu_irq (*bus_get_irq)(AspeedI2CBus *);
 
-- 
2.34.1




[PATCH v1 03/15] hw/i2c/aspeed: support to set the different memory size

2024-07-17 Thread Jamin Lin via
According to the datasheet of ASPEED SOCs,
an I2C controller owns 8KB of register space for AST2700,
owns 4KB of register space for AST2600, AST2500 and AST2400,
and owns 64KB of register space for AST1030.

It set the memory region size 4KB by default and it does not compatible
register space for AST2700.

Introduce a new class attribute to set the I2C controller memory size
for different ASPEED SOCs.

Signed-off-by: Jamin Lin 
---
 hw/i2c/aspeed_i2c.c | 6 +-
 include/hw/i2c/aspeed_i2c.h | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b43afd250d..7d5a53c4c0 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1014,7 +1014,7 @@ static void aspeed_i2c_realize(DeviceState *dev, Error 
**errp)
 
 sysbus_init_irq(sbd, &s->irq);
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
-  "aspeed.i2c", 0x1000);
+  "aspeed.i2c", aic->mem_size);
 sysbus_init_mmio(sbd, &s->iomem);
 
 for (i = 0; i < aic->num_busses; i++) {
@@ -1286,6 +1286,7 @@ static void aspeed_2400_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->pool_size = 0x800;
 aic->pool_base = 0x800;
 aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base;
+aic->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_2400_i2c_info = {
@@ -1320,6 +1321,7 @@ static void aspeed_2500_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
 aic->check_sram = true;
 aic->has_dma = true;
+aic->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_2500_i2c_info = {
@@ -1353,6 +1355,7 @@ static void aspeed_2600_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->pool_base = 0xC00;
 aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
 aic->has_dma = true;
+aic->mem_size = 0x1000;
 }
 
 static const TypeInfo aspeed_2600_i2c_info = {
@@ -1376,6 +1379,7 @@ static void aspeed_1030_i2c_class_init(ObjectClass 
*klass, void *data)
 aic->pool_base = 0xC00;
 aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
 aic->has_dma = true;
+aic->mem_size = 0x1;
 }
 
 static const TypeInfo aspeed_1030_i2c_info = {
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index a064479e59..065b636d29 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -283,7 +283,7 @@ struct AspeedI2CClass {
 uint8_t *(*bus_pool_base)(AspeedI2CBus *);
 bool check_sram;
 bool has_dma;
-
+uint64_t mem_size;
 };
 
 static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
-- 
2.34.1




[PATCH v1 00/15] support ADC and I2C for AST2700

2024-07-17 Thread Jamin Lin via
v1: 
1. support ADC for AST2700
2. support I2C for AST2700

Jamin Lin (15):
  aspeed/adc: Add AST2700 support
  aspeed/soc: support ADC for AST2700
  hw/i2c/aspeed: support to set the different memory size
  hw/i2c/aspeed: support discontinuous register memory region of I2C bus
  hw/i2c/aspeed: rename the I2C class pool attribute to share_pool
  hw/i2c/aspeed: introduce a new bus pool buffer attribute in
AspeedI2Cbus
  hw/i2c/aspeed: support discontinuous poll buffer memory region of I2C
bus
  hw/i2c/aspeed: introduce a new dma_dram_offset attribute in
AspeedI2Cbus
  hw/i2c/aspeed: Add AST2700 support
  hw/i2c/aspeed: support Tx/Rx buffer 64 bits address
  hw/i2c/aspeed: support high part dram offset for DMA 64 bits
  aspeed/soc: introduce a new API to get the INTC orgate information
  aspeed/soc: support I2C for AST2700
  aspeed: fix coding style
  aspeed: add tmp105 in i2c bus 0 for AST2700

 hw/adc/aspeed_adc.c |  16 ++
 hw/arm/aspeed.c |  31 +++-
 hw/arm/aspeed_ast27x0.c |  65 +++
 hw/i2c/aspeed_i2c.c | 340 ++--
 include/hw/adc/aspeed_adc.h |   1 +
 include/hw/i2c/aspeed_i2c.h |  34 ++--
 6 files changed, 418 insertions(+), 69 deletions(-)

-- 
2.34.1




[PATCH v1 02/15] aspeed/soc: support ADC for AST2700

2024-07-17 Thread Jamin Lin via
Add ADC model for AST2700 ADC support.
The ADC controller registers base address is start at
0x14C0_ and its address space is 0x1000.
The ADC controller interrupt is connected to
GICINT130_INTC group at bit 16. The GIC IRQ is 130.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index a9fb0d4b88..4257b5e8af 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -60,6 +60,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_DEV_SLIIO] =  0x14C1E000,
 [ASPEED_GIC_DIST]  =  0x1220,
 [ASPEED_GIC_REDIST]=  0x1228,
+[ASPEED_DEV_ADC]   =  0x14C0,
 };
 
 #define AST2700_MAX_IRQ 288
@@ -344,6 +345,9 @@ static void aspeed_soc_ast2700_init(Object *obj)
 object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
 object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
 object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_2700_INTC);
+
+snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
+object_initialize_child(obj, "adc", &s->adc, typename);
 }
 
 /*
@@ -601,6 +605,14 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
 sc->memmap[ASPEED_DEV_SLIIO]);
 
+/* ADC */
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
+return;
+}
+aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
+sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
+
 create_unimplemented_device("ast2700.dpmcu", 0x1100, 0x4);
 create_unimplemented_device("ast2700.iomem0", 0x1200, 0x0100);
 create_unimplemented_device("ast2700.iomem1", 0x1400, 0x0100);
-- 
2.34.1




[PATCH v3 5/8] aspeed/soc: set dma64 property for AST2700 ftgmac100

2024-07-04 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

Set dma64 property for ftgmac100 model to support
64bits dram address DMA.

Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 18e6a8b10c..a9fb0d4b88 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -552,9 +552,12 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 return;
 }
 
+/* Net */
 for (i = 0; i < sc->macs_num; i++) {
 object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
  &error_abort);
+object_property_set_bool(OBJECT(&s->ftgmac100[i]), "dma64", true,
+ &error_abort);
 if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
 return;
 }
-- 
2.34.1




[PATCH v3 4/8] hw/net:ftgmac100: update TX and RX packet buffers address to 64 bits

2024-07-04 Thread Jamin Lin via
ASPEED AST2700 SOC is a 64 bits quad core CPUs (Cortex-a35)
And the base address of dram is "0x4 " which
is 64bits address.

It have "TXDES 2" and "RXDES 2" to save the high part
physical address of packet buffer.
Ex: TX packet buffer address [34:0]
The "TXDES 2" bits [18:16] which corresponds the bits [34:32]
of the 64 bits address of the TX packet buffer address
and "TXDES 3" bits [31:0] which corresponds the bits [31:0]
of the 64 bits address of the TX packet buffer address.

Update TX and RX packet buffers address type to
64 bits for dram 64 bits address DMA support.

Signed-off-by: Jamin Lin 
---
 hw/net/ftgmac100.c | 21 ++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 68956aeb94..80f9cd56d5 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -175,6 +175,8 @@
 #define FTGMAC100_TXDES1_TX2FIC  (1 << 30)
 #define FTGMAC100_TXDES1_TXIC(1 << 31)
 
+#define FTGMAC100_TXDES2_TXBUF_BADR_HI(x)   (((x) >> 16) & 0x7)
+
 /*
  * Receive descriptor
  */
@@ -208,13 +210,15 @@
 #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR  (1 << 26)
 #define FTGMAC100_RXDES1_IP_CHKSUM_ERR   (1 << 27)
 
+#define FTGMAC100_RXDES2_RXBUF_BADR_HI(x)   (((x) >> 16) & 0x7)
+
 /*
  * Receive and transmit Buffer Descriptor
  */
 typedef struct {
 uint32_tdes0;
 uint32_tdes1;
-uint32_tdes2;/* not used by HW */
+uint32_tdes2;/* used by HW 64 bits DMA */
 uint32_tdes3;
 } FTGMAC100Desc;
 
@@ -531,6 +535,7 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint64_t 
tx_ring,
 int frame_size = 0;
 uint8_t *ptr = s->frame;
 uint64_t addr = tx_descriptor;
+uint64_t buf_addr = 0;
 uint32_t flags = 0;
 
 while (1) {
@@ -569,7 +574,12 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint64_t 
tx_ring,
 len =  sizeof(s->frame) - frame_size;
 }
 
-if (dma_memory_read(&address_space_memory, bd.des3,
+buf_addr = bd.des3;
+if (s->dma64) {
+buf_addr = deposit64(buf_addr, 32, 32,
+ FTGMAC100_TXDES2_TXBUF_BADR_HI(bd.des2));
+}
+if (dma_memory_read(&address_space_memory, buf_addr,
 ptr, len, MEMTXATTRS_UNSPECIFIED)) {
 qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read packet @ 
0x%x\n",
   __func__, bd.des3);
@@ -1022,7 +1032,7 @@ static ssize_t ftgmac100_receive(NetClientState *nc, 
const uint8_t *buf,
 uint32_t flags = 0;
 uint64_t addr;
 uint32_t crc;
-uint32_t buf_addr;
+uint64_t buf_addr = 0;
 uint8_t *crc_ptr;
 uint32_t buf_len;
 size_t size = len;
@@ -1087,7 +1097,12 @@ static ssize_t ftgmac100_receive(NetClientState *nc, 
const uint8_t *buf,
 if (size < 4) {
 buf_len += size - 4;
 }
+
 buf_addr = bd.des3;
+if (s->dma64) {
+buf_addr = deposit64(buf_addr, 32, 32,
+ FTGMAC100_RXDES2_RXBUF_BADR_HI(bd.des2));
+}
 if (first && proto == ETH_P_VLAN && buf_len >= 18) {
 bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL;
 
-- 
2.34.1




[PATCH v3 8/8] machine_aspeed.py: update to test network for AST2700

2024-07-04 Thread Jamin Lin via
Update test case to test network connection via SSH.

Test command:
```
cd build
pyvenv/bin/avocado run 
../qemu/tests/avocado/machine_aspeed.py:AST2x00MachineSDK.test_aarch64_ast2700_evb_sdk_v09_02
```

Signed-off-by: Jamin Lin 
---
 tests/avocado/machine_aspeed.py | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 13fe128fc9..f66ad38d35 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -313,14 +313,14 @@ def do_test_arm_aspeed_sdk_start(self, image):
 
 def do_test_aarch64_aspeed_sdk_start(self, image):
 self.vm.set_console()
-self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw')
+self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-net', 
'user,hostfwd=:127.0.0.1:0-:22')
 
 self.vm.launch()
 
 self.wait_for_console_pattern('U-Boot 2023.10')
 self.wait_for_console_pattern('## Loading kernel from FIT Image')
 self.wait_for_console_pattern('Starting kernel ...')
-self.wait_for_console_pattern("systemd[1]: Hostname set to")
 
 @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on 
GitLab')
 
@@ -436,4 +436,6 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self):
 
 self.vm.add_args('-smp', str(num_cpu))
 self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
+self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
+self.ssh_connect('root', '0penBmc', False)
 
-- 
2.34.1




[PATCH v3 7/8] machine_aspeed.py: update to test ASPEED OpenBMC SDK v09.02 for AST2700

2024-07-04 Thread Jamin Lin via
Update test case to test ASPEED OpenBMC SDK v09.02 for AST2700.

ASPEED fixed TX mask issue from linux/drivers/ftgmac100.c.
It is required to use ASPEED OpenBMC SDK since v09.02
for AST2700 QEMU network testing.

A test image is downloaded from the ASPEED Forked OpenBMC GitHub
release repository :
https://github.com/AspeedTech-BMC/openbmc/releases/

Signed-off-by: Jamin Lin 
---
 tests/avocado/machine_aspeed.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 3a20644fb2..13fe128fc9 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -387,15 +387,15 @@ def test_arm_ast2600_evb_sdk(self):
 year = time.strftime("%Y")
 self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
 
-def test_aarch64_ast2700_evb_sdk_v09_01(self):
+def test_aarch64_ast2700_evb_sdk_v09_02(self):
 """
 :avocado: tags=arch:aarch64
 :avocado: tags=machine:ast2700-evb
 """
 
 image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
- 'download/v09.01/ast2700-default-obmc.tar.gz')
-image_hash = 
'b1cc0fd73c7650d34c9c8459a243f52a91e9e27144b8608b2645ab19461d1e07'
+ 'download/v09.02/ast2700-default-obmc.tar.gz')
+image_hash = 
'ac969c2602f4e6bdb69562ff466b89ae3fe1d86e1f6797bb7969d787f82116a7'
 image_path = self.fetch_asset(image_url, asset_hash=image_hash,
   algorithm='sha256')
 archive.extract(image_path, self.workdir)
-- 
2.34.1




[PATCH v3 2/8] hw/net:ftgmac100: update ring base address to 64 bits

2024-07-04 Thread Jamin Lin via
Update TX and RX ring base address data type to uint64_t for
64 bits dram address DMA support.

Both "Normal Priority Transmit Ring Base Address Register(0x20)" and
"Receive Ring Base Address Register (0x24)" are used for saving the
low part physical address of descriptor manager.

Therefore, changes to set TX and RX descriptor manager address bits [31:0]
in ftgmac100_read and ftgmac100_write functions.

Incrementing the version of vmstate to 2.

Signed-off-by: Jamin Lin 
---
 hw/net/ftgmac100.c | 33 -
 include/hw/net/ftgmac100.h |  9 -
 2 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 9e1f12cd33..d026242e2b 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -515,12 +515,12 @@ out:
 return frame_size;
 }
 
-static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
-uint32_t tx_descriptor)
+static void ftgmac100_do_tx(FTGMAC100State *s, uint64_t tx_ring,
+uint64_t tx_descriptor)
 {
 int frame_size = 0;
 uint8_t *ptr = s->frame;
-uint32_t addr = tx_descriptor;
+uint64_t addr = tx_descriptor;
 uint32_t flags = 0;
 
 while (1) {
@@ -726,9 +726,9 @@ static uint64_t ftgmac100_read(void *opaque, hwaddr addr, 
unsigned size)
 case FTGMAC100_MATH1:
 return s->math[1];
 case FTGMAC100_RXR_BADR:
-return s->rx_ring;
+return extract64(s->rx_ring, 0, 32);
 case FTGMAC100_NPTXR_BADR:
-return s->tx_ring;
+return extract64(s->tx_ring, 0, 32);
 case FTGMAC100_ITC:
 return s->itc;
 case FTGMAC100_DBLAC:
@@ -799,9 +799,8 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
   HWADDR_PRIx "\n", __func__, value);
 return;
 }
-
-s->rx_ring = value;
-s->rx_descriptor = s->rx_ring;
+s->rx_ring = deposit64(s->rx_ring, 0, 32, value);
+s->rx_descriptor = deposit64(s->rx_descriptor, 0, 32, value);
 break;
 
 case FTGMAC100_RBSR: /* DMA buffer size */
@@ -814,8 +813,8 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
   HWADDR_PRIx "\n", __func__, value);
 return;
 }
-s->tx_ring = value;
-s->tx_descriptor = s->tx_ring;
+s->tx_ring = deposit64(s->tx_ring, 0, 32, value);
+s->tx_descriptor = deposit64(s->tx_descriptor, 0, 32, value);
 break;
 
 case FTGMAC100_NPTXPD: /* Trigger transmit */
@@ -957,7 +956,7 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const 
uint8_t *buf,
 FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
 FTGMAC100Desc bd;
 uint32_t flags = 0;
-uint32_t addr;
+uint64_t addr;
 uint32_t crc;
 uint32_t buf_addr;
 uint8_t *crc_ptr;
@@ -1126,18 +1125,14 @@ static void ftgmac100_realize(DeviceState *dev, Error 
**errp)
 
 static const VMStateDescription vmstate_ftgmac100 = {
 .name = TYPE_FTGMAC100,
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32(irq_state, FTGMAC100State),
 VMSTATE_UINT32(isr, FTGMAC100State),
 VMSTATE_UINT32(ier, FTGMAC100State),
 VMSTATE_UINT32(rx_enabled, FTGMAC100State),
-VMSTATE_UINT32(rx_ring, FTGMAC100State),
 VMSTATE_UINT32(rbsr, FTGMAC100State),
-VMSTATE_UINT32(tx_ring, FTGMAC100State),
-VMSTATE_UINT32(rx_descriptor, FTGMAC100State),
-VMSTATE_UINT32(tx_descriptor, FTGMAC100State),
 VMSTATE_UINT32_ARRAY(math, FTGMAC100State, 2),
 VMSTATE_UINT32(itc, FTGMAC100State),
 VMSTATE_UINT32(aptcr, FTGMAC100State),
@@ -1156,6 +1151,10 @@ static const VMStateDescription vmstate_ftgmac100 = {
 VMSTATE_UINT32(phy_int_mask, FTGMAC100State),
 VMSTATE_UINT32(txdes0_edotr, FTGMAC100State),
 VMSTATE_UINT32(rxdes0_edorr, FTGMAC100State),
+VMSTATE_UINT64(rx_ring, FTGMAC100State),
+VMSTATE_UINT64(tx_ring, FTGMAC100State),
+VMSTATE_UINT64(rx_descriptor, FTGMAC100State),
+VMSTATE_UINT64(tx_descriptor, FTGMAC100State),
 VMSTATE_END_OF_LIST()
 }
 };
diff --git a/include/hw/net/ftgmac100.h b/include/hw/net/ftgmac100.h
index 269446e858..aae57ae8cb 100644
--- a/include/hw/net/ftgmac100.h
+++ b/include/hw/net/ftgmac100.h
@@ -42,10 +42,6 @@ struct FTGMAC100State {
 uint32_t isr;
 uint32_t ier;
 uint32_t rx_enabled;
-uint32_t rx_ring;
-uint32_t rx_descriptor;
-uint32_t tx_ring;
-uint32_t tx_descriptor;
 uint32_t math[2];
 uint32_t rbsr;
 uint32_t itc;
@@ -58,7 +54,10 @@ struct FTGMAC100State {
 uint32_t phycr;
 uint32_t phydata;
 uint32_t fcr;
-
+uint64_t rx_ring;
+uint64_t rx_descriptor;
+uint64_t tx_ring;
+uint64_t tx_descriptor;
 
 uint32_t phy_status;
 uint32_t phy_control;

  1   2   3   >