diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-10-27 23:43:53 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-10-27 23:43:53 +0000 |
commit | cddfbe07749a44f83d0f8241fff7ca96a6631882 (patch) | |
tree | 8a299cef18894f323de9976c1609ba8c7f14a18d /hw/misc | |
parent | cfc1105649947f03134294a2448ce2b2e117456f (diff) | |
parent | 06972067c48fc21a47445b5d706368f1129f216f (diff) |
Merge remote-tracking branch 'remotes/philmd-gitlab/tags/led-api-20201026' into staging
API to model LED.
CI jobs results:
. https://cirrus-ci.com/build/4879251751043072
. https://gitlab.com/philmd/qemu/-/pipelines/207661784
. https://travis-ci.org/github/philmd/qemu/builds/738958191
. https://app.shippable.com/github/philmd/qemu/runs/891/summary/console
# gpg: Signature made Mon 26 Oct 2020 22:03:59 GMT
# gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE
* remotes/philmd-gitlab/tags/led-api-20201026:
hw/arm/tosa: Replace fprintf() calls by LED devices
hw/misc/mps2-scc: Use the LED device
hw/misc/mps2-fpgaio: Use the LED device
hw/arm/aspeed: Add the 3 front LEDs drived by the PCA9552 #1
hw/misc/led: Emit a trace event when LED intensity has changed
hw/misc/led: Allow connecting from GPIO output
hw/misc/led: Add a LED device
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/misc')
-rw-r--r-- | hw/misc/Kconfig | 5 | ||||
-rw-r--r-- | hw/misc/led.c | 161 | ||||
-rw-r--r-- | hw/misc/meson.build | 1 | ||||
-rw-r--r-- | hw/misc/mps2-fpgaio.c | 23 | ||||
-rw-r--r-- | hw/misc/mps2-scc.c | 27 | ||||
-rw-r--r-- | hw/misc/trace-events | 6 |
6 files changed, 205 insertions, 18 deletions
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 3185456110..877ecff447 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -93,9 +93,11 @@ config MIPS_ITU config MPS2_FPGAIO bool + select LED config MPS2_SCC bool + select LED config TZ_MPC bool @@ -126,6 +128,9 @@ config AUX config UNIMP bool +config LED + bool + config MAC_VIA bool select MOS6522 diff --git a/hw/misc/led.c b/hw/misc/led.c new file mode 100644 index 0000000000..5266d026d0 --- /dev/null +++ b/hw/misc/led.c @@ -0,0 +1,161 @@ +/* + * QEMU single LED device + * + * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/misc/led.h" +#include "hw/irq.h" +#include "trace.h" + +#define LED_INTENSITY_PERCENT_MAX 100 + +static const char * const led_color_name[] = { + [LED_COLOR_VIOLET] = "violet", + [LED_COLOR_BLUE] = "blue", + [LED_COLOR_CYAN] = "cyan", + [LED_COLOR_GREEN] = "green", + [LED_COLOR_AMBER] = "amber", + [LED_COLOR_ORANGE] = "orange", + [LED_COLOR_RED] = "red", +}; + +static bool led_color_name_is_valid(const char *color_name) +{ + for (size_t i = 0; i < ARRAY_SIZE(led_color_name); i++) { + if (strcmp(color_name, led_color_name[i]) == 0) { + return true; + } + } + return false; +} + +void led_set_intensity(LEDState *s, unsigned intensity_percent) +{ + if (intensity_percent > LED_INTENSITY_PERCENT_MAX) { + intensity_percent = LED_INTENSITY_PERCENT_MAX; + } + trace_led_set_intensity(s->description, s->color, intensity_percent); + if (intensity_percent != s->intensity_percent) { + trace_led_change_intensity(s->description, s->color, + s->intensity_percent, intensity_percent); + } + s->intensity_percent = intensity_percent; +} + +unsigned led_get_intensity(LEDState *s) +{ + return s->intensity_percent; +} + +void led_set_state(LEDState *s, bool is_emitting) +{ + led_set_intensity(s, is_emitting ? LED_INTENSITY_PERCENT_MAX : 0); +} + +static void led_set_state_gpio_handler(void *opaque, int line, int new_state) +{ + LEDState *s = LED(opaque); + + assert(line == 0); + led_set_state(s, !!new_state != s->gpio_active_high); +} + +static void led_reset(DeviceState *dev) +{ + LEDState *s = LED(dev); + + led_set_state(s, s->gpio_active_high); +} + +static const VMStateDescription vmstate_led = { + .name = TYPE_LED, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(intensity_percent, LEDState), + VMSTATE_END_OF_LIST() + } +}; + +static void led_realize(DeviceState *dev, Error **errp) +{ + LEDState *s = LED(dev); + + if (s->color == NULL) { + error_setg(errp, "property 'color' not specified"); + return; + } else if (!led_color_name_is_valid(s->color)) { + error_setg(errp, "property 'color' invalid or not supported"); + return; + } + if (s->description == NULL) { + s->description = g_strdup("n/a"); + } + + qdev_init_gpio_in(DEVICE(s), led_set_state_gpio_handler, 1); +} + +static Property led_properties[] = { + DEFINE_PROP_STRING("color", LEDState, color), + DEFINE_PROP_STRING("description", LEDState, description), + DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void led_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "LED"; + dc->vmsd = &vmstate_led; + dc->reset = led_reset; + dc->realize = led_realize; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + device_class_set_props(dc, led_properties); +} + +static const TypeInfo led_info = { + .name = TYPE_LED, + .parent = TYPE_DEVICE, + .instance_size = sizeof(LEDState), + .class_init = led_class_init +}; + +static void led_register_types(void) +{ + type_register_static(&led_info); +} + +type_init(led_register_types) + +LEDState *led_create_simple(Object *parentobj, + GpioPolarity gpio_polarity, + LEDColor color, + const char *description) +{ + g_autofree char *name = NULL; + DeviceState *dev; + + dev = qdev_new(TYPE_LED); + qdev_prop_set_bit(dev, "gpio-active-high", + gpio_polarity == GPIO_POLARITY_ACTIVE_HIGH); + qdev_prop_set_string(dev, "color", led_color_name[color]); + if (!description) { + static unsigned undescribed_led_id; + name = g_strdup_printf("undescribed-led-#%u", undescribed_led_id++); + } else { + qdev_prop_set_string(dev, "description", description); + name = g_ascii_strdown(description, -1); + name = g_strdelimit(name, " #", '-'); + } + object_property_add_child(parentobj, name, OBJECT(dev)); + qdev_realize_and_unref(dev, NULL, &error_fatal); + + return LED(dev); +} diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 793d45b1dc..aa8ec3bca9 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c')) softmmu_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c')) softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) +softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) # ARM devices softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c index 2f3fbeef34..6af0e8f837 100644 --- a/hw/misc/mps2-fpgaio.c +++ b/hw/misc/mps2-fpgaio.c @@ -24,6 +24,7 @@ #include "migration/vmstate.h" #include "hw/registerfields.h" #include "hw/misc/mps2-fpgaio.h" +#include "hw/misc/led.h" #include "hw/qdev-properties.h" #include "qemu/timer.h" @@ -176,12 +177,9 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case A_LED0: - /* LED bits [1:0] control board LEDs. We don't currently have - * a mechanism for displaying this graphically, so use a trace event. - */ - trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.', - value & 0x01 ? '*' : '.'); s->led0 = value & 0x3; + led_set_state(s->led[0], value & 0x01); + led_set_state(s->led[1], value & 0x02); break; case A_PRESCALE: resync_counter(s); @@ -239,6 +237,10 @@ static void mps2_fpgaio_reset(DeviceState *dev) s->counter = 0; s->pscntr = 0; s->pscntr_sync_ticks = now; + + for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) { + device_cold_reset(DEVICE(s->led[i])); + } } static void mps2_fpgaio_init(Object *obj) @@ -251,6 +253,16 @@ static void mps2_fpgaio_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } +static void mps2_fpgaio_realize(DeviceState *dev, Error **errp) +{ + MPS2FPGAIO *s = MPS2_FPGAIO(dev); + + s->led[0] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH, + LED_COLOR_GREEN, "USERLED0"); + s->led[1] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH, + LED_COLOR_GREEN, "USERLED1"); +} + static bool mps2_fpgaio_counters_needed(void *opaque) { /* Currently vmstate.c insists all subsections have a 'needed' function */ @@ -299,6 +311,7 @@ static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &mps2_fpgaio_vmstate; + dc->realize = mps2_fpgaio_realize; dc->reset = mps2_fpgaio_reset; device_class_set_props(dc, mps2_fpgaio_properties); } diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index 9d0909e7b3..ce1dfe9356 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -20,11 +20,13 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/module.h" +#include "qemu/bitops.h" #include "trace.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/registerfields.h" #include "hw/misc/mps2-scc.h" +#include "hw/misc/led.h" #include "hw/qdev-properties.h" REG32(CFG0, 0) @@ -152,18 +154,10 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value, s->cfg0 = value; break; case A_CFG1: - /* CFG1 bits [7:0] control the board LEDs. We don't currently have - * a mechanism for displaying this graphically, so use a trace event. - */ - trace_mps2_scc_leds(value & 0x80 ? '*' : '.', - value & 0x40 ? '*' : '.', - value & 0x20 ? '*' : '.', - value & 0x10 ? '*' : '.', - value & 0x08 ? '*' : '.', - value & 0x04 ? '*' : '.', - value & 0x02 ? '*' : '.', - value & 0x01 ? '*' : '.'); s->cfg1 = value; + for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) { + led_set_state(s->led[i], extract32(value, i, 1)); + } break; case A_CFGDATA_OUT: s->cfgdata_out = value; @@ -236,6 +230,9 @@ static void mps2_scc_reset(DeviceState *dev) for (i = 0; i < NUM_OSCCLK; i++) { s->oscclk[i] = s->oscclk_reset[i]; } + for (i = 0; i < ARRAY_SIZE(s->led); i++) { + device_cold_reset(DEVICE(s->led[i])); + } } static void mps2_scc_init(Object *obj) @@ -249,6 +246,14 @@ static void mps2_scc_init(Object *obj) static void mps2_scc_realize(DeviceState *dev, Error **errp) { + MPS2SCC *s = MPS2_SCC(dev); + + for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) { + char *name = g_strdup_printf("SCC LED%zu", i); + s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH, + LED_COLOR_GREEN, name); + g_free(name); + } } static const VMStateDescription mps2_scc_vmstate = { diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 6054f9adf3..c68811b670 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -84,7 +84,6 @@ aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" mps2_scc_write(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" mps2_scc_reset(void) "MPS2 SCC: reset" -mps2_scc_leds(char led7, char led6, char led5, char led4, char led3, char led2, char led1, char led0) "MPS2 SCC LEDs: %c%c%c%c%c%c%c%c" mps2_scc_cfg_write(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config write: function %d device %d data 0x%" PRIx32 mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config read: function %d device %d data 0x%" PRIx32 @@ -92,7 +91,6 @@ mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC mps2_fpgaio_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" mps2_fpgaio_write(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" mps2_fpgaio_reset(void) "MPS2 FPGAIO: reset" -mps2_fpgaio_leds(char led1, char led0) "MPS2 FPGAIO LEDs: %c%c" # msf2-sysreg.c msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" PRIx64 " data 0x%" PRIx32 " prev 0x%" PRIx32 @@ -223,6 +221,10 @@ via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x" grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx64" data:0x%08x" +# led.c +led_set_intensity(const char *color, const char *desc, uint8_t intensity_percent) "LED desc:'%s' color:%s intensity: %u%%" +led_change_intensity(const char *color, const char *desc, uint8_t old_intensity_percent, uint8_t new_intensity_percent) "LED desc:'%s' color:%s intensity %u%% -> %u%%" + # pca9552.c pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]" pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u" |