Named GPIOs
cover Named GPIOs
This series implements Named GPIOs on the qdev level. Patch 2 is the feature presentation.
First patch is a developer-centric patch I have had in my tree for a while. I include it so it picks up the change pattern in P2.
Last patch I give a useful example of the features use (an SSI cleanup).
Peter Crosthwaite (3):
qdev: Define qdev_get_gpio_out
qdev: Implement named GPIOs
ssi: Name the CS GPIO.
hw/arm/stellaris.c | 7 ++-- hw/arm/xilinx_zynq.c | 2 +- hw/core/qdev.c | 84 ++++++++++++++++++++++++++++++++----- hw/microblaze/petalogix_ml605_mmu.c | 2 +- hw/ssi/ssi.c | 4 +- include/hw/qdev-core.h | 26 ++++++++++-- include/hw/ssi.h | 2 + qdev-monitor.c | 14 ++++--- qtest.c | 15 ++++--- 9 files changed, 125 insertions(+), 31 deletions(-)
Signature · 1 line
1.9.1.1.gbb9f595
PATCH 1/3 qdev: Define qdev_get_gpio_out
An API similar to the existing qdev_get_gpio_in() except gets outputs. Useful for testing or debugging code which may wish to override the hardware generated value of of a GPIO with a user specified value (E.G. interrupt injection).
---
hw/core/qdev.c | 6 ++++++ include/hw/qdev-core.h | 1 + 2 files changed, 7 insertions(+)
hw/core/qdev.c +6 -0
@@ -332,6 +332,12 @@ qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)return dev->gpio_in[n]; } +qemu_irq qdev_get_gpio_out (DeviceState *dev,int n) +{ +assert (n >=0 && n < dev->num_gpio_out); +return dev->gpio_out[n]; +} +void qdev_connect_gpio_out (DeviceState * dev,int n,qemu_irq pin) {assert (n >=0 && n < dev->num_gpio_out);
include/hw/qdev-core.h +1 -0
@@ -252,6 +252,7 @@ void qdev_machine_creation_done(void);bool qdev_machine_modified (void );qemu_irq qdev_get_gpio_in (DeviceState *dev,int n); +qemu_irq qdev_get_gpio_out (DeviceState *dev,int n);void qdev_connect_gpio_out (DeviceState *dev,int n,qemu_irq pin);BusState *qdev_get_child_bus (DeviceState *dev,const char *name);
Signature · 1 line
1.9.1.1.gbb9f595
PATCH 2/3 qdev: Implement named GPIOs
In reply to Peter CrosthwaiteImplement named GPIOs on the Device layer. Listifies the existing GPIOs stuff using string keys. Legacy un-named GPIOs are preserved by using a NULL name string - they are just a single matchable element in the name list.
---
hw/core/qdev.c | 82 ++++++++++++++++++++++++++++++++++++++++++-------- include/hw/qdev-core.h | 25 ++++++++++++--- qdev-monitor.c | 14 ++++++--- qtest.c | 15 ++++++--- 4 files changed, 110 insertions(+), 26 deletions(-)
hw/core/qdev.c +70 -12
@@ -312,36 +312,94 @@ BusState *qdev_get_parent_bus(DeviceState *dev)return dev->parent_bus; } +static NamedGPIOList *qdev_get_named_gpio_list (DeviceState *dev, +const char *name) +{ +NamedGPIOList *ngl = dev->gpios; + +while (ngl) { +if (ngl->name == name || + (name && ngl->name && !strcmp (name, ngl->name))) { +return ngl; + } + ngl = ngl->next; + } + + ngl =g_malloc0 (sizeof (*ngl)); + ngl->next = dev->gpios; + ngl->name =g_strdup (name); + dev->gpios = ngl; +return ngl; +} + +void qdev_init_gpio_in_named (DeviceState *dev,qemu_irq_handler handler,int n, +const char *name) +{ +NamedGPIOList *gpio_list =qdev_get_named_gpio_list (dev, name); + + gpio_list->in =qemu_extend_irqs (gpio_list->in, gpio_list->num_in, handler, + dev, n); + gpio_list->num_in += n; +} +void qdev_init_gpio_in (DeviceState *dev,qemu_irq_handler handler,int n) { - dev->gpio_in =qemu_extend_irqs (dev->gpio_in, dev->num_gpio_in, handler, - dev, n); - dev->num_gpio_in += n; +qdev_init_gpio_in_named (dev, handler, n,NULL ); +} + +void qdev_init_gpio_out_named (DeviceState *dev,qemu_irq *pins,int n, +const char *name) +{ +NamedGPIOList *gpio_list =qdev_get_named_gpio_list (dev, name); + +assert (gpio_list->num_out ==0 ); + gpio_list->num_out = n; + gpio_list->out = pins; }void qdev_init_gpio_out (DeviceState *dev,qemu_irq *pins,int n) { -assert (dev->num_gpio_out ==0 ); - dev->num_gpio_out = n; - dev->gpio_out = pins; +qdev_init_gpio_out_named (dev, pins, n,NULL ); +} + +qemu_irq qdev_get_gpio_in_named (DeviceState *dev,int n,const char *name) +{ +NamedGPIOList *gpio_list =qdev_get_named_gpio_list (dev, name); + +assert (n >=0 && n < gpio_list->num_in); +return gpio_list->in[n]; }qemu_irq qdev_get_gpio_in (DeviceState *dev,int n) { -assert (n >=0 && n < dev->num_gpio_in); -return dev->gpio_in[n]; +return qdev_get_gpio_in_named (dev, n,NULL ); +} + +qemu_irq qdev_get_gpio_out_named (DeviceState *dev,int n,const char *name) +{ +NamedGPIOList *gpio_list =qdev_get_named_gpio_list (dev, name); + +assert (n >=0 && n < gpio_list->num_out); +return gpio_list->out[n]; }qemu_irq qdev_get_gpio_out (DeviceState *dev,int n) { -assert (n >=0 && n < dev->num_gpio_out); -return dev->gpio_out[n]; +return qdev_get_gpio_out_named (dev, n,NULL ); +} + +void qdev_connect_gpio_out_named (DeviceState *dev,int n,qemu_irq pin, +const char *name) +{ +NamedGPIOList *gpio_list =qdev_get_named_gpio_list (dev, name); + +assert (n >=0 && n < gpio_list->num_out); + gpio_list->out[n] = pin; }void qdev_connect_gpio_out (DeviceState * dev,int n,qemu_irq pin) { -assert (n >=0 && n < dev->num_gpio_out); - dev->gpio_out[n] = pin; +qdev_connect_gpio_out_named (dev, n, pin,NULL ); }BusState *qdev_get_child_bus (DeviceState *dev,const char *name)
include/hw/qdev-core.h +21 -4
@@ -131,6 +131,17 @@ typedef struct DeviceClass {const char *bus_type; } DeviceClass; +typedef struct NamedGPIOList NamedGPIOList ; + +struct NamedGPIOList { +const char *name; +int num_in; +qemu_irq *in; +qemu_irq *out; +int num_out; +struct NamedGPIOList *next; +}; +/** * DeviceState: * @realized: Indicates whether the device has been fully constructed.
@@ -148,10 +159,7 @@ struct DeviceState {QemuOpts *opts;int hotplugged;BusState *parent_bus; -int num_gpio_out; -qemu_irq *gpio_out; -int num_gpio_in; -qemu_irq *gpio_in; +NamedGPIOList *gpios; QLIST_HEAD(, BusState) child_bus;int num_child_bus;int instance_id_alias;
@@ -253,7 +261,12 @@ bool qdev_machine_modified(void);qemu_irq qdev_get_gpio_in (DeviceState *dev,int n);qemu_irq qdev_get_gpio_out (DeviceState *dev,int n); +qemu_irq qdev_get_gpio_in_named (DeviceState *dev,int n,const char *name); +qemu_irq qdev_get_gpio_out_named (DeviceState *dev,int n,const char *name); +void qdev_connect_gpio_out (DeviceState *dev,int n,qemu_irq pin); +void qdev_connect_gpio_out_named (DeviceState *dev,int n,qemu_irq pin, +const char *name);BusState *qdev_get_child_bus (DeviceState *dev,const char *name);
@@ -263,6 +276,10 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);/* GPIO inputs also double as IRQ sinks. */ void qdev_init_gpio_in (DeviceState *dev,qemu_irq_handler handler,int n);void qdev_init_gpio_out (DeviceState *dev,qemu_irq *pins,int n); +void qdev_init_gpio_in_named (DeviceState *dev,qemu_irq_handler handler,int n, +const char *name); +void qdev_init_gpio_out_named (DeviceState *dev,qemu_irq *pins,int n, +const char *name);BusState *qdev_get_parent_bus (DeviceState *dev);
qdev-monitor.c +9 -5
@@ -609,14 +609,18 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) {ObjectClass *class;BusState *child; +NamedGPIOList *ngl; +qdev_printf ("dev: %s, id \"%s\"\n" ,object_get_typename (OBJECT (dev)), dev->id ? dev->id :"" ); indent +=2 ; -if (dev->num_gpio_in) { -qdev_printf ("gpio-in %d\n" , dev->num_gpio_in); - } -if (dev->num_gpio_out) { -qdev_printf ("gpio-out %d\n" , dev->num_gpio_out); +for (ngl = dev->gpios; ngl; ngl = ngl->next) { +if (ngl->num_in) { +qdev_printf ("gpio-in \"%s\" %d\n" , ngl->name, ngl->num_in); + } +if (ngl->num_out) { +qdev_printf ("gpio-out \"%s\" %d\n" , ngl->name, ngl->num_out); + } } class =object_get_class (OBJECT (dev)); do {
qtest.c +10 -5
@@ -233,7 +233,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)g_assert (command);if (strcmp (words[0 ],"irq_intercept_out" ) ==0 ||strcmp (words[0 ],"irq_intercept_in" ) ==0 ) { -DeviceState *dev; +DeviceState *dev; +NamedGPIOList *ngl;g_assert (words[1 ]); dev =DEVICE (object_resolve_path (words[1 ],NULL ));
@@ -253,10 +254,14 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)return ; } -if (words[0 ][14 ] =='o' ) { -qemu_irq_intercept_out (&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out); - }else { -qemu_irq_intercept_in (dev->gpio_in, qtest_irq_handler, dev->num_gpio_in); +for (ngl = dev->gpios; ngl; ngl = ngl->next) { +if (words[0 ][14 ] =='o' ) { +qemu_irq_intercept_out (&ngl->out, qtest_irq_handler, + ngl->num_out); + }else { +qemu_irq_intercept_in (ngl->in, qtest_irq_handler, + ngl->num_in); + } } irq_intercept_dev = dev;qtest_send_prefix (chr);
Signature · 1 line
1.9.1.1.gbb9f595
PATCH 3/3 ssi: Name the CS GPIO.
In reply to Peter CrosthwaiteTo get it out of the default GPIO list. This allows child devices to use the un-named GPIO namespace without having to be SSI aware. That is, there is no more need for machines to know about the obscure policy where GPIO 0 is the SSI chip-select and GPIO 1..N are the concrete class GPIOs (defined locally as 0..N-1).
This is most notable is stellaris, which uses a device which has both SSI and concrete level GPIOs.
---
hw/arm/stellaris.c | 7 ++++--- hw/arm/xilinx_zynq.c | 2 +- hw/microblaze/petalogix_ml605_mmu.c | 2 +- hw/ssi/ssi.c | 4 ++-- include/hw/ssi.h | 2 ++ 5 files changed, 10 insertions(+), 7 deletions(-)
hw/arm/stellaris.c +4 -3
@@ -1287,9 +1287,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, sddev =ssi_create_slave (bus,"ssi-sd" ); ssddev =ssi_create_slave (bus,"ssd0323" ); - gpio_out[GPIO_D ][0 ] =qemu_irq_split (qdev_get_gpio_in (sddev,0 ), -qdev_get_gpio_in (ssddev,0 )); - gpio_out[GPIO_C ][7 ] =qdev_get_gpio_in (ssddev,1 ); + gpio_out[GPIO_D ][0 ] =qemu_irq_split ( +qdev_get_gpio_in_named (sddev,0 ,SSI_GPIO_CS ), +qdev_get_gpio_in_named (ssddev,0 ,SSI_GPIO_CS )); + gpio_out[GPIO_C ][7 ] =qdev_get_gpio_in (ssddev,0 );/* Make sure the select pin is high. */ qemu_irq_raise (gpio_out[GPIO_D ][0 ]);
hw/arm/xilinx_zynq.c +1 -1
@@ -94,7 +94,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,for (j =0 ; j < num_ss; ++j) { flash_dev =ssi_create_slave (spi,"n25q128" ); - cs_line =qdev_get_gpio_in (flash_dev,0 ); + cs_line =qdev_get_gpio_in_named (flash_dev,0 ,SSI_GPIO_CS );sysbus_connect_irq (busdev, i * num_ss + j +1 , cs_line); } }
hw/microblaze/petalogix_ml605_mmu.c +1 -1
@@ -196,7 +196,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)qemu_irq cs_line; dev =ssi_create_slave (spi,"n25q128" ); - cs_line =qdev_get_gpio_in (dev,0 ); + cs_line =qdev_get_gpio_in_named (dev,0 ,SSI_GPIO_CS );sysbus_connect_irq (busdev, i+1 , cs_line); } }
hw/ssi/ssi.c +2 -2
@@ -60,7 +60,7 @@ static int ssi_slave_init(DeviceState *dev)if (ssc->transfer_raw == ssi_transfer_raw_default && ssc->cs_polarity !=SSI_CS_NONE ) { -qdev_init_gpio_in (dev, ssi_cs_default,1 ); +qdev_init_gpio_in_named (dev, ssi_cs_default,1 ,SSI_GPIO_CS ); }return ssc->init (s);
@@ -156,7 +156,7 @@ static int ssi_auto_connect_slave(Object *child, void *opaque)return 0 ; } - cs_line =qdev_get_gpio_in (DEVICE (dev),0 ); + cs_line =qdev_get_gpio_in_named (DEVICE (dev),0 ,SSI_GPIO_CS );qdev_set_parent_bus (DEVICE (dev),BUS (arg->bus)); **arg->cs_linep = cs_line; (*arg->cs_linep)++;
include/hw/ssi.h +2 -0
@@ -23,6 +23,8 @@ typedef struct SSISlave SSISlave;#define SSI_SLAVE_GET_CLASS (obj) \ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE) +#define SSI_GPIO_CS "ssi-gpio-cs" + typedef enum { SSI_CS_NONE = 0, SSI_CS_LOW,
Signature · 1 line
1.9.1.1.gbb9f595