All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030
@ 2022-03-21  9:14 Jamin Lin
  2022-03-21  9:14 ` [PATCH v1 1/1] hw/gpio: " Jamin Lin
  2022-03-21 10:55 ` [PATCH v1 0/1] hw/gpio " Cédric Le Goater
  0 siblings, 2 replies; 6+ messages in thread
From: Jamin Lin @ 2022-03-21  9:14 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, steven_lee

1. Add GPIO read/write trace event.
2. Support GPIO index mode for write operation.
It did not support GPIO index mode for read operation.
3. AST1030 integrates one set of Parallel GPIO Controller
with maximum 151 control pins, which are 21 groups
(A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
S5 S6 S7 ) and the group T and U are input only.

Test Steps:
1. Download image from
https://github.com/AspeedTech-BMC/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip
2. Extract the zip file to obtain zephyr.elf
3. Run ./qemu-system-arm -M ast1030-evb -kernel $PATH/zephyr.elf -nographic
4. Test GPIO D6 Pin
uart:~$ gpio conf GPIO0_A_D 30 out
uart:~$ gpio get GPIO0_A_D 30
[Result]
Reading GPIO0_A_D pin 30
Value 0
uart:~$ gpio set GPIO0_A_D 30 1
uart:~$ gpio get GPIO0_A_D 30
[Result]
Reading GPIO0_A_D pin 30
Value 1
uart:~$ gpio set GPIO0_A_D 30 0
uart:~$ gpio get GPIO0_A_D 30
[Result]
Reading GPIO0_A_D pin 30
Value 0

Jamin Lin (1):
  hw/gpio: Add ASPEED GPIO model for AST1030

 hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
 hw/gpio/trace-events          |   5 +
 include/hw/gpio/aspeed_gpio.h |  16 ++-
 3 files changed, 255 insertions(+), 16 deletions(-)

-- 
2.17.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 1/1] hw/gpio: Add ASPEED GPIO model for AST1030
  2022-03-21  9:14 [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030 Jamin Lin
@ 2022-03-21  9:14 ` Jamin Lin
  2022-05-11  6:14   ` Cédric Le Goater
  2022-03-21 10:55 ` [PATCH v1 0/1] hw/gpio " Cédric Le Goater
  1 sibling, 1 reply; 6+ messages in thread
From: Jamin Lin @ 2022-03-21  9:14 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, steven_lee

1. Add GPIO read/write trace event.
2. Support GPIO index mode for write operation.
It did not support GPIO index mode for read operation.
3. AST1030 integrates one set of Parallel GPIO Controller
with maximum 151 control pins, which are 21 groups
(A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
S5 S6 S7 ) and the group T and U are input only.

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
 hw/gpio/trace-events          |   5 +
 include/hw/gpio/aspeed_gpio.h |  16 ++-
 3 files changed, 255 insertions(+), 16 deletions(-)

diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index c63634d3d3..3f0bd036b7 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -15,6 +15,8 @@
 #include "qapi/visitor.h"
 #include "hw/irq.h"
 #include "migration/vmstate.h"
+#include "trace.h"
+#include "hw/registerfields.h"
 
 #define GPIOS_PER_GROUP 8
 
@@ -203,6 +205,28 @@
 #define GPIO_1_8V_MEM_SIZE            0x1D8
 #define GPIO_1_8V_REG_ARRAY_SIZE      (GPIO_1_8V_MEM_SIZE >> 2)
 
+/*
+ * GPIO index mode support
+ * It only supports write operation
+ */
+REG32(GPIO_INDEX_REG, 0x2AC)
+    FIELD(GPIO_INDEX_REG, NUMBER, 0, 8)
+    FIELD(GPIO_INDEX_REG, COMMAND, 12, 1)
+    FIELD(GPIO_INDEX_REG, TYPE, 16, 4)
+    FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1)
+    FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1)
+    FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1)
+    FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1)
+    FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1)
+    FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1)
+    FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1)
+    FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1)
+    FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1)
+    FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1)
+    FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1)
+    FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
+    FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
+
 static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
 {
     uint32_t falling_edge = 0, rising_edge = 0;
@@ -523,11 +547,16 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
     uint64_t idx = -1;
     const AspeedGPIOReg *reg;
     GPIOSets *set;
+    uint32_t value = 0;
+    uint64_t debounce_value;
 
     idx = offset >> 2;
     if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
         idx -= GPIO_DEBOUNCE_TIME_1;
-        return (uint64_t) s->debounce_regs[idx];
+        debounce_value = (uint64_t) s->debounce_regs[idx];
+        trace_aspeed_gpio_read(DEVICE(s)->canonical_path,
+                               offset, debounce_value);
+        return debounce_value;
     }
 
     reg = &agc->reg_table[idx];
@@ -540,38 +569,193 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
     set = &s->sets[reg->set_idx];
     switch (reg->type) {
     case gpio_reg_data_value:
-        return set->data_value;
+         value = set->data_value;
+         break;
     case gpio_reg_direction:
-        return set->direction;
+        value = set->direction;
+        break;
     case gpio_reg_int_enable:
-        return set->int_enable;
+        value = set->int_enable;
+        break;
     case gpio_reg_int_sens_0:
-        return set->int_sens_0;
+        value = set->int_sens_0;
+        break;
     case gpio_reg_int_sens_1:
-        return set->int_sens_1;
+        value = set->int_sens_1;
+        break;
     case gpio_reg_int_sens_2:
-        return set->int_sens_2;
+        value = set->int_sens_2;
+        break;
     case gpio_reg_int_status:
-        return set->int_status;
+        value = set->int_status;
+        break;
     case gpio_reg_reset_tolerant:
-        return set->reset_tol;
+        value = set->reset_tol;
+        break;
     case gpio_reg_debounce_1:
-        return set->debounce_1;
+        value = set->debounce_1;
+        break;
     case gpio_reg_debounce_2:
-        return set->debounce_2;
+        value = set->debounce_2;
+        break;
     case gpio_reg_cmd_source_0:
-        return set->cmd_source_0;
+        value = set->cmd_source_0;
+        break;
     case gpio_reg_cmd_source_1:
-        return set->cmd_source_1;
+        value = set->cmd_source_1;
+        break;
     case gpio_reg_data_read:
-        return set->data_read;
+        value = set->data_read;
+        break;
     case gpio_reg_input_mask:
-        return set->input_mask;
+        value = set->input_mask;
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
                       HWADDR_PRIx"\n", __func__, offset);
         return 0;
     }
+
+    trace_aspeed_gpio_read(DEVICE(s)->canonical_path, offset, value);
+    return value;
+}
+
+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;
+    GPIOSets *set;
+    uint32_t reg_idx_number = FIELD_EX32(data, GPIO_INDEX_REG, NUMBER);
+    uint32_t reg_idx_type = FIELD_EX32(data, GPIO_INDEX_REG, TYPE);
+    uint32_t reg_idx_command = FIELD_EX32(data, GPIO_INDEX_REG, COMMAND);
+    uint32_t set_idx = reg_idx_number / ASPEED_GPIOS_PER_SET;
+    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;
+
+    set = &s->sets[set_idx];
+    props = &agc->props[set_idx];
+
+    if (reg_idx_command)
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
+            HWADDR_PRIx "index mode wrong command 0x%x\n",
+            __func__, offset, data, reg_idx_command);
+
+    switch (reg_idx_type) {
+    case gpio_reg_idx_data:
+        reg_value = set->data_read;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE));
+        reg_value &= props->output;
+        reg_value = update_value_control_source(set, set->data_value,
+                                                reg_value);
+        set->data_read = reg_value;
+        aspeed_gpio_update(s, set, reg_value);
+        return;
+    case gpio_reg_idx_direction:
+        reg_value = set->direction;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION));
+        /*
+         *   where data is the value attempted to be written to the pin:
+         *    pin type      | input mask | output mask | expected value
+         *    ------------------------------------------------------------
+         *   bidirectional  |   1       |   1        |  data
+         *   input only     |   1       |   0        |   0
+         *   output only    |   0       |   1        |   1
+         *   no pin         |   0       |   0        |   0
+         *
+         *  which is captured by:
+         *  data = ( data | ~input) & output;
+         */
+        reg_value = (reg_value | ~props->input) & props->output;
+        set->direction = update_value_control_source(set, set->direction,
+                                                     reg_value);
+        break;
+    case gpio_reg_idx_interrupt:
+        reg_value = set->int_enable;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE));
+        set->int_enable = update_value_control_source(set, set->int_enable,
+                                                      reg_value);
+        reg_value = set->int_sens_0;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0));
+        set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
+                                                      reg_value);
+        reg_value = set->int_sens_1;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1));
+        set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
+                                                      reg_value);
+        reg_value = set->int_sens_2;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              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;
+        }
+        set->int_status &= ~reg_value;
+        break;
+    case gpio_reg_idx_debounce:
+        reg_value = set->debounce_1;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1));
+        set->debounce_1 = update_value_control_source(set, set->debounce_1,
+                                                      reg_value);
+        reg_value = set->debounce_2;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2));
+        set->debounce_2 = update_value_control_source(set, set->debounce_2,
+                                                      reg_value);
+        return;
+    case gpio_reg_idx_tolerance:
+        reg_value = set->reset_tol;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLERANT));
+        set->reset_tol = update_value_control_source(set, set->reset_tol,
+                                                     reg_value);
+        return;
+    case gpio_reg_idx_cmd_src:
+        reg_value = set->cmd_source_0;
+        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_0));
+        set->cmd_source_0 = reg_value & ASPEED_CMD_SRC_MASK;
+        reg_value = set->cmd_source_1;
+        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_1));
+        set->cmd_source_1 = reg_value & ASPEED_CMD_SRC_MASK;
+        return;
+    case gpio_reg_idx_input_mask:
+        reg_value = set->input_mask;
+        reg_value = deposit32(reg_value, pin_idx, 1,
+                              FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK));
+        /*
+         * feeds into interrupt generation
+         * 0: read from data value reg will be updated
+         * 1: read from data value reg will not be updated
+         */
+        set->input_mask = reg_value & props->input;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
+            HWADDR_PRIx "index mode wrong type 0x%x\n",
+            __func__, offset, data, reg_idx_type);
+        return;
+    }
+    aspeed_gpio_update(s, set, set->data_value);
+    return;
 }
 
 static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
@@ -585,7 +769,16 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
     GPIOSets *set;
     uint32_t cleared;
 
+    trace_aspeed_gpio_write(DEVICE(s)->canonical_path, offset, data);
+
     idx = offset >> 2;
+
+    /* check gpio index mode */
+    if (idx == R_GPIO_INDEX_REG) {
+        aspeed_gpio_write_index_mode(opaque, offset, data, size);
+        return;
+    }
+
     if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
         idx -= GPIO_DEBOUNCE_TIME_1;
         s->debounce_regs[idx] = (uint32_t) data;
@@ -795,6 +988,15 @@ static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
     [1] = {0x0000000f,  0x0000000f,  {"18E"} },
 };
 
+static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
+    [0] = {0xffffffff,  0xffffffff,  {"A", "B", "C", "D"} },
+    [1] = {0xffffffff,  0xffffffff,  {"E", "F", "G", "H"} },
+    [2] = {0xffffffff,  0xffffffff,  {"I", "J", "K", "L"} },
+    [3] = {0xffffff3f,  0xffffff3f,  {"M", "N", "O", "P"} },
+    [4] = {0xff060c1f,  0x00060c1f,  {"Q", "R", "S", "T"} },
+    [5] = {0x000000ff,  0x00000000,  {"U"} },
+};
+
 static const MemoryRegionOps aspeed_gpio_ops = {
     .read       = aspeed_gpio_read,
     .write      = aspeed_gpio_write,
@@ -947,6 +1149,16 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
     agc->reg_table = aspeed_1_8v_gpios;
 }
 
+static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
+{
+    AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+    agc->props = ast1030_set_props;
+    agc->nr_gpio_pins = 151;
+    agc->nr_gpio_sets = 6;
+    agc->reg_table = aspeed_3_3v_gpios;
+}
+
 static const TypeInfo aspeed_gpio_info = {
     .name           = TYPE_ASPEED_GPIO,
     .parent         = TYPE_SYS_BUS_DEVICE,
@@ -984,6 +1196,13 @@ static const TypeInfo aspeed_gpio_ast2600_1_8v_info = {
     .instance_init  = aspeed_gpio_init,
 };
 
+static const TypeInfo aspeed_gpio_ast1030_info = {
+    .name           = TYPE_ASPEED_GPIO "-ast1030",
+    .parent         = TYPE_ASPEED_GPIO,
+    .class_init     = aspeed_gpio_1030_class_init,
+    .instance_init  = aspeed_gpio_init,
+};
+
 static void aspeed_gpio_register_types(void)
 {
     type_register_static(&aspeed_gpio_info);
@@ -991,6 +1210,7 @@ static void aspeed_gpio_register_types(void)
     type_register_static(&aspeed_gpio_ast2500_info);
     type_register_static(&aspeed_gpio_ast2600_3_3v_info);
     type_register_static(&aspeed_gpio_ast2600_1_8v_info);
+    type_register_static(&aspeed_gpio_ast1030_info);
 }
 
 type_init(aspeed_gpio_register_types);
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
index 1dab99c560..717d6cf7cc 100644
--- a/hw/gpio/trace-events
+++ b/hw/gpio/trace-events
@@ -27,3 +27,8 @@ sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" P
 sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
 sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
 sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
+
+# aspeed_gpio.c
+aspeed_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
+aspeed_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
+
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 801846befb..cb7671149f 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -50,10 +50,24 @@ enum GPIORegType {
     gpio_reg_input_mask,
 };
 
+/* GPIO index mode */
+enum GPIORegIndexType {
+    gpio_reg_idx_data = 0,
+    gpio_reg_idx_direction,
+    gpio_reg_idx_interrupt,
+    gpio_reg_idx_debounce,
+    gpio_reg_idx_tolerance,
+    gpio_reg_idx_cmd_src,
+    gpio_reg_idx_input_mask,
+    gpio_reg_idx_reserved,
+    gpio_reg_idx_new_w_cmd_src,
+    gpio_reg_idx_new_r_cmd_src,
+};
+
 typedef struct AspeedGPIOReg {
     uint16_t set_idx;
     enum GPIORegType type;
- } AspeedGPIOReg;
+} AspeedGPIOReg;
 
 struct AspeedGPIOClass {
     SysBusDevice parent_obj;
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030
  2022-03-21  9:14 [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030 Jamin Lin
  2022-03-21  9:14 ` [PATCH v1 1/1] hw/gpio: " Jamin Lin
@ 2022-03-21 10:55 ` Cédric Le Goater
  2022-03-22  3:08   ` Jamin Lin
  1 sibling, 1 reply; 6+ messages in thread
From: Cédric Le Goater @ 2022-03-21 10:55 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here
  Cc: troy_lee, steven_lee

Hello Jamin,

On 3/21/22 10:14, Jamin Lin wrote:
> 1. Add GPIO read/write trace event.
> 2. Support GPIO index mode for write operation.
> It did not support GPIO index mode for read operation.
> 3. AST1030 integrates one set of Parallel GPIO Controller

Is the AST1030 a new SoC you are developing ? We don't have a machine
for it in QEMU. We should introduce the models first if the changes
are specific to this SoC.

Thanks,

C.


> with maximum 151 control pins, which are 21 groups
> (A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
> S5 S6 S7 ) and the group T and U are input only.
> 
> Test Steps:
> 1. Download image from
> https://github.com/AspeedTech-BMC/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip
> 2. Extract the zip file to obtain zephyr.elf
> 3. Run ./qemu-system-arm -M ast1030-evb -kernel $PATH/zephyr.elf -nographic
> 4. Test GPIO D6 Pin
> uart:~$ gpio conf GPIO0_A_D 30 out
> uart:~$ gpio get GPIO0_A_D 30
> [Result]
> Reading GPIO0_A_D pin 30
> Value 0
> uart:~$ gpio set GPIO0_A_D 30 1
> uart:~$ gpio get GPIO0_A_D 30
> [Result]
> Reading GPIO0_A_D pin 30
> Value 1
> uart:~$ gpio set GPIO0_A_D 30 0
> uart:~$ gpio get GPIO0_A_D 30
> [Result]
> Reading GPIO0_A_D pin 30
> Value 0
> 
> Jamin Lin (1):
>    hw/gpio: Add ASPEED GPIO model for AST1030
> 
>   hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
>   hw/gpio/trace-events          |   5 +
>   include/hw/gpio/aspeed_gpio.h |  16 ++-
>   3 files changed, 255 insertions(+), 16 deletions(-)
> 



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030
  2022-03-21 10:55 ` [PATCH v1 0/1] hw/gpio " Cédric Le Goater
@ 2022-03-22  3:08   ` Jamin Lin
  0 siblings, 0 replies; 6+ messages in thread
From: Jamin Lin @ 2022-03-22  3:08 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Peter Maydell, Andrew Jeffery, Troy Lee, Steven Lee,
	open list:All patches CC here, open list:ASPEED BMCs,
	Joel Stanley

The 03/21/2022 10:55, Cédric Le Goater wrote:
> Hello Jamin,
> 
> On 3/21/22 10:14, Jamin Lin wrote:
> > 1. Add GPIO read/write trace event.
> > 2. Support GPIO index mode for write operation.
> > It did not support GPIO index mode for read operation.
> > 3. AST1030 integrates one set of Parallel GPIO Controller
> 
> Is the AST1030 a new SoC you are developing ? We don't have a machine
> for it in QEMU. We should introduce the models first if the changes
> are specific to this SoC.
> 
> Thanks,
> 
> C.
> 
> 
I submitted a new patch series for AST1030 model support.
So far, only GPIO driver for AST1030 used "index mode" for write
operation.
Thanks-Jamin
> > with maximum 151 control pins, which are 21 groups
> > (A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
> > S5 S6 S7 ) and the group T and U are input only.
> > 
> > Test Steps:
> > 1. Download image from
> > https://github.com/AspeedTech-BMC/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip
> > 2. Extract the zip file to obtain zephyr.elf
> > 3. Run ./qemu-system-arm -M ast1030-evb -kernel $PATH/zephyr.elf -nographic
> > 4. Test GPIO D6 Pin
> > uart:~$ gpio conf GPIO0_A_D 30 out
> > uart:~$ gpio get GPIO0_A_D 30
> > [Result]
> > Reading GPIO0_A_D pin 30
> > Value 0
> > uart:~$ gpio set GPIO0_A_D 30 1
> > uart:~$ gpio get GPIO0_A_D 30
> > [Result]
> > Reading GPIO0_A_D pin 30
> > Value 1
> > uart:~$ gpio set GPIO0_A_D 30 0
> > uart:~$ gpio get GPIO0_A_D 30
> > [Result]
> > Reading GPIO0_A_D pin 30
> > Value 0
> > 
> > Jamin Lin (1):
> >    hw/gpio: Add ASPEED GPIO model for AST1030
> > 
> >   hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
> >   hw/gpio/trace-events          |   5 +
> >   include/hw/gpio/aspeed_gpio.h |  16 ++-
> >   3 files changed, 255 insertions(+), 16 deletions(-)
> > 
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 1/1] hw/gpio: Add ASPEED GPIO model for AST1030
  2022-03-21  9:14 ` [PATCH v1 1/1] hw/gpio: " Jamin Lin
@ 2022-05-11  6:14   ` Cédric Le Goater
  2022-05-25  5:47     ` Jamin Lin
  0 siblings, 1 reply; 6+ messages in thread
From: Cédric Le Goater @ 2022-05-11  6:14 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here,
	Peter Delevoryas, Maheswara Kurapati
  Cc: steven_lee, troy_lee

Hello Jamin,

(Adding a few people that could help with the review)

On 3/21/22 10:14, Jamin Lin wrote:

> 1. Add GPIO read/write trace event.

Do we really need the "DEVICE(s)->canonical_path" parameter ?
That would be patch 1.

> 2. Support GPIO index mode for write operation.
> It did not support GPIO index mode for read operation.

these changes would be in patch 2.

> 3. AST1030 integrates one set of Parallel GPIO Controller
> with maximum 151 control pins, which are 21 groups
> (A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
> S5 S6 S7 ) and the group T and U are input only.

and a last patch 3.

> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Some minor comments below,

Thanks,

C.


> ---
>   hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
>   hw/gpio/trace-events          |   5 +
>   include/hw/gpio/aspeed_gpio.h |  16 ++-
>   3 files changed, 255 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
> index c63634d3d3..3f0bd036b7 100644
> --- a/hw/gpio/aspeed_gpio.c
> +++ b/hw/gpio/aspeed_gpio.c
> @@ -15,6 +15,8 @@
>   #include "qapi/visitor.h"
>   #include "hw/irq.h"
>   #include "migration/vmstate.h"
> +#include "trace.h"
> +#include "hw/registerfields.h"
>   
>   #define GPIOS_PER_GROUP 8
>   
> @@ -203,6 +205,28 @@
>   #define GPIO_1_8V_MEM_SIZE            0x1D8
>   #define GPIO_1_8V_REG_ARRAY_SIZE      (GPIO_1_8V_MEM_SIZE >> 2)
>   
> +/*
> + * GPIO index mode support
> + * It only supports write operation
> + */
> +REG32(GPIO_INDEX_REG, 0x2AC)
> +    FIELD(GPIO_INDEX_REG, NUMBER, 0, 8)
> +    FIELD(GPIO_INDEX_REG, COMMAND, 12, 1)
> +    FIELD(GPIO_INDEX_REG, TYPE, 16, 4)
> +    FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1)
> +    FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1)
> +    FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1)
> +    FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1)
> +    FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1)
> +    FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1)
> +    FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1)
> +    FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1)
> +    FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1)
> +    FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1)
> +    FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1)
> +    FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
> +    FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)

That's a good idea. We should start switching the models to the registerfields
interface.

>   static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
>   {
>       uint32_t falling_edge = 0, rising_edge = 0;
> @@ -523,11 +547,16 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
>       uint64_t idx = -1;
>       const AspeedGPIOReg *reg;
>       GPIOSets *set;
> +    uint32_t value = 0;
> +    uint64_t debounce_value;
>   
>       idx = offset >> 2;
>       if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
>           idx -= GPIO_DEBOUNCE_TIME_1;
> -        return (uint64_t) s->debounce_regs[idx];
> +        debounce_value = (uint64_t) s->debounce_regs[idx];
> +        trace_aspeed_gpio_read(DEVICE(s)->canonical_path,
> +                               offset, debounce_value);
> +        return debounce_value;
>       }
>   
>       reg = &agc->reg_table[idx];
> @@ -540,38 +569,193 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
>       set = &s->sets[reg->set_idx];
>       switch (reg->type) {
>       case gpio_reg_data_value:
> -        return set->data_value;
> +         value = set->data_value;
> +         break;
>       case gpio_reg_direction:
> -        return set->direction;
> +        value = set->direction;
> +        break;
>       case gpio_reg_int_enable:
> -        return set->int_enable;
> +        value = set->int_enable;
> +        break;
>       case gpio_reg_int_sens_0:
> -        return set->int_sens_0;
> +        value = set->int_sens_0;
> +        break;
>       case gpio_reg_int_sens_1:
> -        return set->int_sens_1;
> +        value = set->int_sens_1;
> +        break;
>       case gpio_reg_int_sens_2:
> -        return set->int_sens_2;
> +        value = set->int_sens_2;
> +        break;
>       case gpio_reg_int_status:
> -        return set->int_status;
> +        value = set->int_status;
> +        break;
>       case gpio_reg_reset_tolerant:
> -        return set->reset_tol;
> +        value = set->reset_tol;
> +        break;
>       case gpio_reg_debounce_1:
> -        return set->debounce_1;
> +        value = set->debounce_1;
> +        break;
>       case gpio_reg_debounce_2:
> -        return set->debounce_2;
> +        value = set->debounce_2;
> +        break;
>       case gpio_reg_cmd_source_0:
> -        return set->cmd_source_0;
> +        value = set->cmd_source_0;
> +        break;
>       case gpio_reg_cmd_source_1:
> -        return set->cmd_source_1;
> +        value = set->cmd_source_1;
> +        break;
>       case gpio_reg_data_read:
> -        return set->data_read;
> +        value = set->data_read;
> +        break;
>       case gpio_reg_input_mask:
> -        return set->input_mask;
> +        value = set->input_mask;
> +        break;
>       default:
>           qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
>                         HWADDR_PRIx"\n", __func__, offset);
>           return 0;
>       }
> +
> +    trace_aspeed_gpio_read(DEVICE(s)->canonical_path, offset, value);
> +    return value;
> +}
> +
> +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;
> +    GPIOSets *set;
> +    uint32_t reg_idx_number = FIELD_EX32(data, GPIO_INDEX_REG, NUMBER);
> +    uint32_t reg_idx_type = FIELD_EX32(data, GPIO_INDEX_REG, TYPE);
> +    uint32_t reg_idx_command = FIELD_EX32(data, GPIO_INDEX_REG, COMMAND);
> +    uint32_t set_idx = reg_idx_number / ASPEED_GPIOS_PER_SET;
> +    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;
> +
> +    set = &s->sets[set_idx];
> +    props = &agc->props[set_idx];
> +
> +    if (reg_idx_command)
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
> +            HWADDR_PRIx "index mode wrong command 0x%x\n",

The format should use PRIx64 for the data

> +            __func__, offset, data, reg_idx_command);
> +
> +    switch (reg_idx_type) {
> +    case gpio_reg_idx_data:
> +        reg_value = set->data_read;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE));
> +        reg_value &= props->output;
> +        reg_value = update_value_control_source(set, set->data_value,
> +                                                reg_value);
> +        set->data_read = reg_value;
> +        aspeed_gpio_update(s, set, reg_value);
> +        return;
> +    case gpio_reg_idx_direction:
> +        reg_value = set->direction;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION));
> +        /*
> +         *   where data is the value attempted to be written to the pin:
> +         *    pin type      | input mask | output mask | expected value
> +         *    ------------------------------------------------------------
> +         *   bidirectional  |   1       |   1        |  data
> +         *   input only     |   1       |   0        |   0
> +         *   output only    |   0       |   1        |   1
> +         *   no pin         |   0       |   0        |   0
> +         *
> +         *  which is captured by:
> +         *  data = ( data | ~input) & output;
> +         */
> +        reg_value = (reg_value | ~props->input) & props->output;
> +        set->direction = update_value_control_source(set, set->direction,
> +                                                     reg_value);
> +        break;
> +    case gpio_reg_idx_interrupt:
> +        reg_value = set->int_enable;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE));
> +        set->int_enable = update_value_control_source(set, set->int_enable,
> +                                                      reg_value);
> +        reg_value = set->int_sens_0;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0));
> +        set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
> +                                                      reg_value);
> +        reg_value = set->int_sens_1;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1));
> +        set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
> +                                                      reg_value);
> +        reg_value = set->int_sens_2;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              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;
> +        }
> +        set->int_status &= ~reg_value;
> +        break;
> +    case gpio_reg_idx_debounce:
> +        reg_value = set->debounce_1;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1));
> +        set->debounce_1 = update_value_control_source(set, set->debounce_1,
> +                                                      reg_value);
> +        reg_value = set->debounce_2;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2));
> +        set->debounce_2 = update_value_control_source(set, set->debounce_2,
> +                                                      reg_value);
> +        return;
> +    case gpio_reg_idx_tolerance:
> +        reg_value = set->reset_tol;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLERANT));
> +        set->reset_tol = update_value_control_source(set, set->reset_tol,
> +                                                     reg_value);
> +        return;
> +    case gpio_reg_idx_cmd_src:
> +        reg_value = set->cmd_source_0;
> +        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_0));
> +        set->cmd_source_0 = reg_value & ASPEED_CMD_SRC_MASK;
> +        reg_value = set->cmd_source_1;
> +        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_1));
> +        set->cmd_source_1 = reg_value & ASPEED_CMD_SRC_MASK;
> +        return;
> +    case gpio_reg_idx_input_mask:
> +        reg_value = set->input_mask;
> +        reg_value = deposit32(reg_value, pin_idx, 1,
> +                              FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK));
> +        /*
> +         * feeds into interrupt generation
> +         * 0: read from data value reg will be updated
> +         * 1: read from data value reg will not be updated
> +         */
> +        set->input_mask = reg_value & props->input;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
> +            HWADDR_PRIx "index mode wrong type 0x%x\n",
> +            __func__, offset, data, reg_idx_type);
> +        return;
> +    }
> +    aspeed_gpio_update(s, set, set->data_value);
> +    return;
>   }
>   
>   static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
> @@ -585,7 +769,16 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
>       GPIOSets *set;
>       uint32_t cleared;
>   
> +    trace_aspeed_gpio_write(DEVICE(s)->canonical_path, offset, data);
> +
>       idx = offset >> 2;
> +
> +    /* check gpio index mode */
> +    if (idx == R_GPIO_INDEX_REG) {
> +        aspeed_gpio_write_index_mode(opaque, offset, data, size);
> +        return;
> +    }
> +
>       if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
>           idx -= GPIO_DEBOUNCE_TIME_1;
>           s->debounce_regs[idx] = (uint32_t) data;
> @@ -795,6 +988,15 @@ static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
>       [1] = {0x0000000f,  0x0000000f,  {"18E"} },
>   };
>   
> +static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
> +    [0] = {0xffffffff,  0xffffffff,  {"A", "B", "C", "D"} },
> +    [1] = {0xffffffff,  0xffffffff,  {"E", "F", "G", "H"} },
> +    [2] = {0xffffffff,  0xffffffff,  {"I", "J", "K", "L"} },
> +    [3] = {0xffffff3f,  0xffffff3f,  {"M", "N", "O", "P"} },
> +    [4] = {0xff060c1f,  0x00060c1f,  {"Q", "R", "S", "T"} },
> +    [5] = {0x000000ff,  0x00000000,  {"U"} },
> +};
> +
>   static const MemoryRegionOps aspeed_gpio_ops = {
>       .read       = aspeed_gpio_read,
>       .write      = aspeed_gpio_write,
> @@ -947,6 +1149,16 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
>       agc->reg_table = aspeed_1_8v_gpios;
>   }
>   
> +static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
> +{
> +    AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
> +
> +    agc->props = ast1030_set_props;
> +    agc->nr_gpio_pins = 151;
> +    agc->nr_gpio_sets = 6;
> +    agc->reg_table = aspeed_3_3v_gpios;
> +}
> +
>   static const TypeInfo aspeed_gpio_info = {
>       .name           = TYPE_ASPEED_GPIO,
>       .parent         = TYPE_SYS_BUS_DEVICE,
> @@ -984,6 +1196,13 @@ static const TypeInfo aspeed_gpio_ast2600_1_8v_info = {
>       .instance_init  = aspeed_gpio_init,
>   };
>   
> +static const TypeInfo aspeed_gpio_ast1030_info = {
> +    .name           = TYPE_ASPEED_GPIO "-ast1030",
> +    .parent         = TYPE_ASPEED_GPIO,
> +    .class_init     = aspeed_gpio_1030_class_init,
> +    .instance_init  = aspeed_gpio_init,
> +};
> +
>   static void aspeed_gpio_register_types(void)
>   {
>       type_register_static(&aspeed_gpio_info);
> @@ -991,6 +1210,7 @@ static void aspeed_gpio_register_types(void)
>       type_register_static(&aspeed_gpio_ast2500_info);
>       type_register_static(&aspeed_gpio_ast2600_3_3v_info);
>       type_register_static(&aspeed_gpio_ast2600_1_8v_info);
> +    type_register_static(&aspeed_gpio_ast1030_info);
>   }
>   
>   type_init(aspeed_gpio_register_types);
> diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
> index 1dab99c560..717d6cf7cc 100644
> --- a/hw/gpio/trace-events
> +++ b/hw/gpio/trace-events
> @@ -27,3 +27,8 @@ sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" P
>   sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
>   sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
>   sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
> +
> +# aspeed_gpio.c
> +aspeed_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
> +aspeed_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
> +
> diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
> index 801846befb..cb7671149f 100644
> --- a/include/hw/gpio/aspeed_gpio.h
> +++ b/include/hw/gpio/aspeed_gpio.h
> @@ -50,10 +50,24 @@ enum GPIORegType {
>       gpio_reg_input_mask,
>   };
>   
> +/* GPIO index mode */
> +enum GPIORegIndexType {
> +    gpio_reg_idx_data = 0,
> +    gpio_reg_idx_direction,
> +    gpio_reg_idx_interrupt,
> +    gpio_reg_idx_debounce,
> +    gpio_reg_idx_tolerance,
> +    gpio_reg_idx_cmd_src,
> +    gpio_reg_idx_input_mask,
> +    gpio_reg_idx_reserved,
> +    gpio_reg_idx_new_w_cmd_src,
> +    gpio_reg_idx_new_r_cmd_src,
> +};
> +
>   typedef struct AspeedGPIOReg {
>       uint16_t set_idx;
>       enum GPIORegType type;
> - } AspeedGPIOReg;
> +} AspeedGPIOReg;
>   
>   struct AspeedGPIOClass {
>       SysBusDevice parent_obj;



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 1/1] hw/gpio: Add ASPEED GPIO model for AST1030
  2022-05-11  6:14   ` Cédric Le Goater
@ 2022-05-25  5:47     ` Jamin Lin
  0 siblings, 0 replies; 6+ messages in thread
From: Jamin Lin @ 2022-05-25  5:47 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Peter Maydell, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here,
	Peter Delevoryas, Maheswara Kurapati, Steven Lee, Troy Lee

The 05/11/2022 06:14, Cédric Le Goater wrote:
Hi Cerdic,
> Hello Jamin,
> 
> (Adding a few people that could help with the review)
> 
> On 3/21/22 10:14, Jamin Lin wrote:
> 
> > 1. Add GPIO read/write trace event.
> 
> Do we really need the "DEVICE(s)->canonical_path" parameter ?
> That would be patch 1.
> 
Fixed in v2 patch
> > 2. Support GPIO index mode for write operation.
> > It did not support GPIO index mode for read operation.
> 
> these changes would be in patch 2.
> 
Fixed in v2 patch
> > 3. AST1030 integrates one set of Parallel GPIO Controller
> > with maximum 151 control pins, which are 21 groups
> > (A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4
> > S5 S6 S7 ) and the group T and U are input only.
> 
> and a last patch 3.
> 
Fixed in v2 patch
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> 
> 
> Some minor comments below,
> 
> Thanks,
> 
> C.
> 
I created v2-patches to fix above issues, please help to review.
http://patchwork.ozlabs.org/project/qemu-devel/list/?series=301873
Thanks-Jamin
> 
> > ---
> >   hw/gpio/aspeed_gpio.c         | 250 ++++++++++++++++++++++++++++++++--
> >   hw/gpio/trace-events          |   5 +
> >   include/hw/gpio/aspeed_gpio.h |  16 ++-
> >   3 files changed, 255 insertions(+), 16 deletions(-)
> > 
> > diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
> > index c63634d3d3..3f0bd036b7 100644
> > --- a/hw/gpio/aspeed_gpio.c
> > +++ b/hw/gpio/aspeed_gpio.c
> > @@ -15,6 +15,8 @@
> >   #include "qapi/visitor.h"
> >   #include "hw/irq.h"
> >   #include "migration/vmstate.h"
> > +#include "trace.h"
> > +#include "hw/registerfields.h"
> >   
> >   #define GPIOS_PER_GROUP 8
> >   
> > @@ -203,6 +205,28 @@
> >   #define GPIO_1_8V_MEM_SIZE            0x1D8
> >   #define GPIO_1_8V_REG_ARRAY_SIZE      (GPIO_1_8V_MEM_SIZE >> 2)
> >   
> > +/*
> > + * GPIO index mode support
> > + * It only supports write operation
> > + */
> > +REG32(GPIO_INDEX_REG, 0x2AC)
> > +    FIELD(GPIO_INDEX_REG, NUMBER, 0, 8)
> > +    FIELD(GPIO_INDEX_REG, COMMAND, 12, 1)
> > +    FIELD(GPIO_INDEX_REG, TYPE, 16, 4)
> > +    FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1)
> > +    FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1)
> > +    FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1)
> > +    FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1)
> > +    FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1)
> > +    FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1)
> > +    FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
> > +    FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
> 
> That's a good idea. We should start switching the models to the registerfields
> interface.
> 
> >   static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
> >   {
> >       uint32_t falling_edge = 0, rising_edge = 0;
> > @@ -523,11 +547,16 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
> >       uint64_t idx = -1;
> >       const AspeedGPIOReg *reg;
> >       GPIOSets *set;
> > +    uint32_t value = 0;
> > +    uint64_t debounce_value;
> >   
> >       idx = offset >> 2;
> >       if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
> >           idx -= GPIO_DEBOUNCE_TIME_1;
> > -        return (uint64_t) s->debounce_regs[idx];
> > +        debounce_value = (uint64_t) s->debounce_regs[idx];
> > +        trace_aspeed_gpio_read(DEVICE(s)->canonical_path,
> > +                               offset, debounce_value);
> > +        return debounce_value;
> >       }
> >   
> >       reg = &agc->reg_table[idx];
> > @@ -540,38 +569,193 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
> >       set = &s->sets[reg->set_idx];
> >       switch (reg->type) {
> >       case gpio_reg_data_value:
> > -        return set->data_value;
> > +         value = set->data_value;
> > +         break;
> >       case gpio_reg_direction:
> > -        return set->direction;
> > +        value = set->direction;
> > +        break;
> >       case gpio_reg_int_enable:
> > -        return set->int_enable;
> > +        value = set->int_enable;
> > +        break;
> >       case gpio_reg_int_sens_0:
> > -        return set->int_sens_0;
> > +        value = set->int_sens_0;
> > +        break;
> >       case gpio_reg_int_sens_1:
> > -        return set->int_sens_1;
> > +        value = set->int_sens_1;
> > +        break;
> >       case gpio_reg_int_sens_2:
> > -        return set->int_sens_2;
> > +        value = set->int_sens_2;
> > +        break;
> >       case gpio_reg_int_status:
> > -        return set->int_status;
> > +        value = set->int_status;
> > +        break;
> >       case gpio_reg_reset_tolerant:
> > -        return set->reset_tol;
> > +        value = set->reset_tol;
> > +        break;
> >       case gpio_reg_debounce_1:
> > -        return set->debounce_1;
> > +        value = set->debounce_1;
> > +        break;
> >       case gpio_reg_debounce_2:
> > -        return set->debounce_2;
> > +        value = set->debounce_2;
> > +        break;
> >       case gpio_reg_cmd_source_0:
> > -        return set->cmd_source_0;
> > +        value = set->cmd_source_0;
> > +        break;
> >       case gpio_reg_cmd_source_1:
> > -        return set->cmd_source_1;
> > +        value = set->cmd_source_1;
> > +        break;
> >       case gpio_reg_data_read:
> > -        return set->data_read;
> > +        value = set->data_read;
> > +        break;
> >       case gpio_reg_input_mask:
> > -        return set->input_mask;
> > +        value = set->input_mask;
> > +        break;
> >       default:
> >           qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
> >                         HWADDR_PRIx"\n", __func__, offset);
> >           return 0;
> >       }
> > +
> > +    trace_aspeed_gpio_read(DEVICE(s)->canonical_path, offset, value);
> > +    return value;
> > +}
> > +
> > +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;
> > +    GPIOSets *set;
> > +    uint32_t reg_idx_number = FIELD_EX32(data, GPIO_INDEX_REG, NUMBER);
> > +    uint32_t reg_idx_type = FIELD_EX32(data, GPIO_INDEX_REG, TYPE);
> > +    uint32_t reg_idx_command = FIELD_EX32(data, GPIO_INDEX_REG, COMMAND);
> > +    uint32_t set_idx = reg_idx_number / ASPEED_GPIOS_PER_SET;
> > +    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;
> > +
> > +    set = &s->sets[set_idx];
> > +    props = &agc->props[set_idx];
> > +
> > +    if (reg_idx_command)
> > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
> > +            HWADDR_PRIx "index mode wrong command 0x%x\n",
> 
> The format should use PRIx64 for the data
> 
> > +            __func__, offset, data, reg_idx_command);
> > +
> > +    switch (reg_idx_type) {
> > +    case gpio_reg_idx_data:
> > +        reg_value = set->data_read;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE));
> > +        reg_value &= props->output;
> > +        reg_value = update_value_control_source(set, set->data_value,
> > +                                                reg_value);
> > +        set->data_read = reg_value;
> > +        aspeed_gpio_update(s, set, reg_value);
> > +        return;
> > +    case gpio_reg_idx_direction:
> > +        reg_value = set->direction;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION));
> > +        /*
> > +         *   where data is the value attempted to be written to the pin:
> > +         *    pin type      | input mask | output mask | expected value
> > +         *    ------------------------------------------------------------
> > +         *   bidirectional  |   1       |   1        |  data
> > +         *   input only     |   1       |   0        |   0
> > +         *   output only    |   0       |   1        |   1
> > +         *   no pin         |   0       |   0        |   0
> > +         *
> > +         *  which is captured by:
> > +         *  data = ( data | ~input) & output;
> > +         */
> > +        reg_value = (reg_value | ~props->input) & props->output;
> > +        set->direction = update_value_control_source(set, set->direction,
> > +                                                     reg_value);
> > +        break;
> > +    case gpio_reg_idx_interrupt:
> > +        reg_value = set->int_enable;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE));
> > +        set->int_enable = update_value_control_source(set, set->int_enable,
> > +                                                      reg_value);
> > +        reg_value = set->int_sens_0;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0));
> > +        set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
> > +                                                      reg_value);
> > +        reg_value = set->int_sens_1;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1));
> > +        set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
> > +                                                      reg_value);
> > +        reg_value = set->int_sens_2;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              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;
> > +        }
> > +        set->int_status &= ~reg_value;
> > +        break;
> > +    case gpio_reg_idx_debounce:
> > +        reg_value = set->debounce_1;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1));
> > +        set->debounce_1 = update_value_control_source(set, set->debounce_1,
> > +                                                      reg_value);
> > +        reg_value = set->debounce_2;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2));
> > +        set->debounce_2 = update_value_control_source(set, set->debounce_2,
> > +                                                      reg_value);
> > +        return;
> > +    case gpio_reg_idx_tolerance:
> > +        reg_value = set->reset_tol;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLERANT));
> > +        set->reset_tol = update_value_control_source(set, set->reset_tol,
> > +                                                     reg_value);
> > +        return;
> > +    case gpio_reg_idx_cmd_src:
> > +        reg_value = set->cmd_source_0;
> > +        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_0));
> > +        set->cmd_source_0 = reg_value & ASPEED_CMD_SRC_MASK;
> > +        reg_value = set->cmd_source_1;
> > +        reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_1));
> > +        set->cmd_source_1 = reg_value & ASPEED_CMD_SRC_MASK;
> > +        return;
> > +    case gpio_reg_idx_input_mask:
> > +        reg_value = set->input_mask;
> > +        reg_value = deposit32(reg_value, pin_idx, 1,
> > +                              FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK));
> > +        /*
> > +         * feeds into interrupt generation
> > +         * 0: read from data value reg will be updated
> > +         * 1: read from data value reg will not be updated
> > +         */
> > +        set->input_mask = reg_value & props->input;
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" HWADDR_PRIx "data 0x%"
> > +            HWADDR_PRIx "index mode wrong type 0x%x\n",
> > +            __func__, offset, data, reg_idx_type);
> > +        return;
> > +    }
> > +    aspeed_gpio_update(s, set, set->data_value);
> > +    return;
> >   }
> >   
> >   static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
> > @@ -585,7 +769,16 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
> >       GPIOSets *set;
> >       uint32_t cleared;
> >   
> > +    trace_aspeed_gpio_write(DEVICE(s)->canonical_path, offset, data);
> > +
> >       idx = offset >> 2;
> > +
> > +    /* check gpio index mode */
> > +    if (idx == R_GPIO_INDEX_REG) {
> > +        aspeed_gpio_write_index_mode(opaque, offset, data, size);
> > +        return;
> > +    }
> > +
> >       if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) {
> >           idx -= GPIO_DEBOUNCE_TIME_1;
> >           s->debounce_regs[idx] = (uint32_t) data;
> > @@ -795,6 +988,15 @@ static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
> >       [1] = {0x0000000f,  0x0000000f,  {"18E"} },
> >   };
> >   
> > +static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
> > +    [0] = {0xffffffff,  0xffffffff,  {"A", "B", "C", "D"} },
> > +    [1] = {0xffffffff,  0xffffffff,  {"E", "F", "G", "H"} },
> > +    [2] = {0xffffffff,  0xffffffff,  {"I", "J", "K", "L"} },
> > +    [3] = {0xffffff3f,  0xffffff3f,  {"M", "N", "O", "P"} },
> > +    [4] = {0xff060c1f,  0x00060c1f,  {"Q", "R", "S", "T"} },
> > +    [5] = {0x000000ff,  0x00000000,  {"U"} },
> > +};
> > +
> >   static const MemoryRegionOps aspeed_gpio_ops = {
> >       .read       = aspeed_gpio_read,
> >       .write      = aspeed_gpio_write,
> > @@ -947,6 +1149,16 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
> >       agc->reg_table = aspeed_1_8v_gpios;
> >   }
> >   
> > +static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
> > +{
> > +    AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
> > +
> > +    agc->props = ast1030_set_props;
> > +    agc->nr_gpio_pins = 151;
> > +    agc->nr_gpio_sets = 6;
> > +    agc->reg_table = aspeed_3_3v_gpios;
> > +}
> > +
> >   static const TypeInfo aspeed_gpio_info = {
> >       .name           = TYPE_ASPEED_GPIO,
> >       .parent         = TYPE_SYS_BUS_DEVICE,
> > @@ -984,6 +1196,13 @@ static const TypeInfo aspeed_gpio_ast2600_1_8v_info = {
> >       .instance_init  = aspeed_gpio_init,
> >   };
> >   
> > +static const TypeInfo aspeed_gpio_ast1030_info = {
> > +    .name           = TYPE_ASPEED_GPIO "-ast1030",
> > +    .parent         = TYPE_ASPEED_GPIO,
> > +    .class_init     = aspeed_gpio_1030_class_init,
> > +    .instance_init  = aspeed_gpio_init,
> > +};
> > +
> >   static void aspeed_gpio_register_types(void)
> >   {
> >       type_register_static(&aspeed_gpio_info);
> > @@ -991,6 +1210,7 @@ static void aspeed_gpio_register_types(void)
> >       type_register_static(&aspeed_gpio_ast2500_info);
> >       type_register_static(&aspeed_gpio_ast2600_3_3v_info);
> >       type_register_static(&aspeed_gpio_ast2600_1_8v_info);
> > +    type_register_static(&aspeed_gpio_ast1030_info);
> >   }
> >   
> >   type_init(aspeed_gpio_register_types);
> > diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
> > index 1dab99c560..717d6cf7cc 100644
> > --- a/hw/gpio/trace-events
> > +++ b/hw/gpio/trace-events
> > @@ -27,3 +27,8 @@ sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" P
> >   sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
> >   sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
> >   sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
> > +
> > +# aspeed_gpio.c
> > +aspeed_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
> > +aspeed_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
> > +
> > diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
> > index 801846befb..cb7671149f 100644
> > --- a/include/hw/gpio/aspeed_gpio.h
> > +++ b/include/hw/gpio/aspeed_gpio.h
> > @@ -50,10 +50,24 @@ enum GPIORegType {
> >       gpio_reg_input_mask,
> >   };
> >   
> > +/* GPIO index mode */
> > +enum GPIORegIndexType {
> > +    gpio_reg_idx_data = 0,
> > +    gpio_reg_idx_direction,
> > +    gpio_reg_idx_interrupt,
> > +    gpio_reg_idx_debounce,
> > +    gpio_reg_idx_tolerance,
> > +    gpio_reg_idx_cmd_src,
> > +    gpio_reg_idx_input_mask,
> > +    gpio_reg_idx_reserved,
> > +    gpio_reg_idx_new_w_cmd_src,
> > +    gpio_reg_idx_new_r_cmd_src,
> > +};
> > +
> >   typedef struct AspeedGPIOReg {
> >       uint16_t set_idx;
> >       enum GPIORegType type;
> > - } AspeedGPIOReg;
> > +} AspeedGPIOReg;
> >   
> >   struct AspeedGPIOClass {
> >       SysBusDevice parent_obj;
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-05-25  6:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-21  9:14 [PATCH v1 0/1] hw/gpio Add ASPEED GPIO model for AST1030 Jamin Lin
2022-03-21  9:14 ` [PATCH v1 1/1] hw/gpio: " Jamin Lin
2022-05-11  6:14   ` Cédric Le Goater
2022-05-25  5:47     ` Jamin Lin
2022-03-21 10:55 ` [PATCH v1 0/1] hw/gpio " Cédric Le Goater
2022-03-22  3:08   ` Jamin Lin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.