[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH 1/1] hw: aspeed_adc: Add initial Aspeed ADC support
From: |
Peter Delevoryas |
Subject: |
Re: [RFC PATCH 1/1] hw: aspeed_adc: Add initial Aspeed ADC support |
Date: |
Thu, 30 Sep 2021 15:24:59 +0000 |
> On Sep 29, 2021, at 11:22 PM, Cédric Le Goater <clg@kaod.org> wrote:
>
> Hello Peter,
>
> If you run ./scripts/get_maintainer.pl on the patch, it will build
> the list of persons and mailing list to send to.
Oh, sorry about that, I’ll cc everyone properly when I resubmit this.
>
> On 9/30/21 02:42, pdel@fb.com wrote:
>> From: Peter Delevoryas <pdel@fb.com>
>> This change sets up Aspeed SoC ADC emulation, so that most ADC drivers
>> will pass the initialization sequence and load successfully. In the
>> future, we can extend this to emulate more features.
>> The initialization sequence is:
>> 1. Set `ADC00` to `0xF`.
>> 2. Wait for bit 8 of `ADC00` to be set.
>> I also added the sequence for enabling "Auto compensating sensing mode":
>> 1. Set `ADC00` to `0x2F` (set bit 5).
>> 2. Wait for bit 5 of `ADC00` to be reset (to zero).
>> 3. ...
>> 4. ...
>> Fuji (AST2600):
>> Before:
>> [ 56.185778] aspeed_adc: probe of 1e6e9000.adc failed with error -110
>> [ 56.687936] aspeed_adc: probe of 1e6e9100.adc failed with error -110
>> After:
>> aspeed_adc_read 0x0c read 0x0000
>> aspeed_adc_read 0x0c read 0x0000
>> aspeed_adc_write 0x00 write 0x000f
>> aspeed_adc_read 0x00 read 0x010f
>> aspeed_adc_read 0x00 read 0x010f
>> [ 55.885164] aspeed_adc 1e6e9000.adc: trim 8
>> aspeed_adc_read 0xc4 read 0x0000
>> aspeed_adc_write 0xc4 write 0x0008
>> aspeed_adc_write 0x00 write 0x011f
>> aspeed_adc_write 0x00 write 0x1011f
>> aspeed_adc_read 0x10 read 0x0000
>> aspeed_adc_write 0x00 write 0x010f
>> [ 55.886509] aspeed_adc 1e6e9000.adc: cv 512
>> aspeed_adc_write 0x00 write 0xffff010f
>> aspeed_adc_read 0x0c read 0x0000
>> aspeed_adc_read 0x0c read 0x0000
>> aspeed_adc_write 0x00 write 0x000f
>> aspeed_adc_read 0x00 read 0x010f
>> aspeed_adc_read 0x00 read 0x010f
>> [ 55.890609] aspeed_adc 1e6e9100.adc: trim 8
>> aspeed_adc_read 0xc4 read 0x0000
>> aspeed_adc_write 0xc4 write 0x0008
>> aspeed_adc_write 0x00 write 0x011f
>> aspeed_adc_write 0x00 write 0x1011f
>> aspeed_adc_read 0x10 read 0x0000
>> aspeed_adc_write 0x00 write 0x010f
>> [ 55.891863] aspeed_adc 1e6e9100.adc: cv 512
>> aspeed_adc_write 0x00 write 0xffff010f
>> YosemiteV2 (AST2500):
>> Before:
>> [ 20.561588] ast_adc ast_adc.0: ast_adc_probe
>> [ 20.563741] hwmon hwmon0: write offset: c4, val: 8
>> [ 20.563925] hwmon hwmon0: write offset: c, val: 40
>> [ 20.564099] hwmon hwmon0: write offset: 0, val: f
>> [ 21.066110] ast_adc: driver init failed (ret=-110)!
>> [ 21.066635] ast_adc: probe of ast_adc.0 failed with error -110
>> After:
>> aspeed_adc_write 0xc4 write 0x0008
>> aspeed_adc_write 0x0c write 0x0040
>> aspeed_adc_write 0x00 write 0x000f
>> aspeed_adc_read 0x00 read 0x010f
>> aspeed_adc_write 0x00 write 0x002f
>> aspeed_adc_read 0x00 read 0x000f
>> aspeed_adc_read 0xc4 read 0x0008
>> [ 19.602033] ast_adc: driver successfully loaded.
>
>
> FYI, these series was sent by Andrew in 2017 and I have been keeping
> it alive since in the aspeed-x.y branches :
>
> * memory: Support unaligned accesses on aligned-only models
>
> https://github.com/legoater/qemu/commit/1960ba6bde27b91edb5336985a9210260a4c8938
>
> That was requested by Phil I think.
>
> * hw/adc: Add basic Aspeed ADC model
>
> https://github.com/legoater/qemu/commit/1eff7b1cf10d1777635f7d2cef8ecb441cc607c4
>
> This is the initial patch. I added multi-engine support recently
> for the fuji.
>
> * hw/arm: Integrate ADC model into Aspeed SoC
>
> https://github.com/legoater/qemu/commit/3052f9d8ccdaf78b753e53574b7e8cc2ee01429f
>
> That one is trivial.
>
>
> Overall comments :
>
> I prefer the 'regs' array approach of your proposal.
Ok (I was just following patterns from aspeed_scu.c), I’ll keep that aspect.
>
> I think the AspeedADCEngine should appear as a QOM object. Check
> the patches above.
I see, I’ll make sure to test this.
>
> To move on, maybe, you could rework the initial series and take
> ownership ?
>
Yeah definitely! I’ll resubmit once I’ve reworked it. I don’t intend
to include the unaligned-access support though, at least not w/ the ADC
changes.
>
> Some more below,
>
>
>> Signed-off-by: Peter Delevoryas <pdel@fb.com>
>> ---
>> hw/adc/aspeed_adc.c | 205 ++++++++++++++++++++++++++++++++++++
>> hw/adc/meson.build | 1 +
>> hw/adc/trace-events | 4 +
>> hw/arm/aspeed_ast2600.c | 18 ++++
>> hw/arm/aspeed_soc.c | 17 +++
>> include/hw/adc/aspeed_adc.h | 48 +++++++++
>> include/hw/arm/aspeed_soc.h | 5 +
>> 7 files changed, 298 insertions(+)
>> create mode 100644 hw/adc/aspeed_adc.c
>> create mode 100644 include/hw/adc/aspeed_adc.h
>> diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c
>> new file mode 100644
>> index 0000000000..590936148b
>> --- /dev/null
>> +++ b/hw/adc/aspeed_adc.c
>> @@ -0,0 +1,205 @@
>> +/*
>> + * Aspeed ADC Controller
>> + *
>> + * Copyright 2021 Facebook, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
>> + * for more details.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/adc/aspeed_adc.h"
>> +#include "hw/qdev-properties.h"
>> +#include "migration/vmstate.h"
>> +#include "trace.h"
>> +#include "qemu/log.h"
>> +
>> +#define TO_REG(offset) ((offset) >> 2)
>> +#define ENGINE_CONTROL TO_REG(0x00)
>> +
>> +static uint64_t aspeed_adc_read(void *opaque, hwaddr offset, unsigned size)
>> +{
>> + AspeedADCState *s = ASPEED_ADC(opaque);
>> + int reg = TO_REG(offset);
>> +
>> + if (reg >= ASPEED_ADC_MAX_REGS) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Out-of-bounds read 0x%04" HWADDR_PRIX "\n",
>> + __func__, offset);
>> + return 0;
>> + }
>> +
>> + int value = s->regs[reg];
>> +
>> + trace_aspeed_adc_read(offset, value);
>> + return value;
>> +}
>> +
>> +static void aspeed_adc_write(void *opaque, hwaddr offset, uint64_t data,
>> + unsigned size)
>> +{
>> + AspeedADCState *s = ASPEED_ADC(opaque);
>> + int reg = TO_REG(offset);
>> +
>> + if (reg >= ASPEED_ADC_MAX_REGS) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Out-of-bounds write 0x%04" HWADDR_PRIX "\n",
>> + __func__, offset);
>> + return;
>> + }
>> +
>> + trace_aspeed_adc_write(offset, data);
>> +
>> + switch (reg) {
>> + case ENGINE_CONTROL:
>> + switch (data) {
>> + case 0xF:
>> + s->regs[ENGINE_CONTROL] = 0x10F;
>> + return;
>> + case 0x2F:
>> + s->regs[ENGINE_CONTROL] = 0xF;
>> + return;
>> + }
>> + break;
>> + }
>> +
>> + s->regs[reg] = data;
>> +}
>> +
>> +static const MemoryRegionOps aspeed_adc_ops = {
>> + .read = aspeed_adc_read,
>> + .write = aspeed_adc_write,
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> + .valid.min_access_size = 4,
>> + .valid.max_access_size = 4,
>> + .valid.unaligned = false,
>
> That's THE question that has been blocking the patches from being
> merged since 2017.
Oh I see, because the ADC supports unaligned access and some
drivers actually take advantage of that? Maybe I can just leave
a comment or add a qemu_log_mask that says it’s not supported yet?
I could also resubmit that patch Andrew made for unaligned access too.
>
>> +};
>> +
>> +static void aspeed_adc_realize(DeviceState *dev, Error **errp)
>> +{
>> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> + AspeedADCState *s = ASPEED_ADC(dev);
>> +
>> + sysbus_init_irq(sbd, &s->irq);
>> + // The memory region is actually 4KB (0x1000), but there's 2 ADC's in
>> the
>> + // AST2600 that are offset by 0x100.
>
> No C++ comments. Please run ./scripts/checkpatch.pl.
Erg, yeah sorry about that. I forgot about checkpatch.pl, I was
looking at “make help” and tried running sparse cause I couldn’t
remember where/what the linter script was.
>
>
>> + memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_ops, s,
>> + TYPE_ASPEED_ADC, 0x100);
>> + sysbus_init_mmio(sbd, &s->mmio);
>> +}
>> +
>> +static void aspeed_adc_reset(DeviceState *dev)
>> +{
>> + AspeedADCState *s = ASPEED_ADC(dev);
>> + AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
>> +
>> + memcpy(s->regs, aac->resets, aac->nr_regs << 2);
>> +}
>> +
>> +static const uint32_t aspeed_2400_resets[ASPEED_2400_ADC_NR_REGS] = {
>> + [ENGINE_CONTROL] = 0x00000000,
>> +};
>> +
>> +static const uint32_t aspeed_2500_resets[ASPEED_2500_ADC_NR_REGS] = {
>> + [ENGINE_CONTROL] = 0x00000000,
>> +};
>> +
>> +static const uint32_t aspeed_2600_resets[ASPEED_2600_ADC_NR_REGS] = {
>> + [ENGINE_CONTROL] = 0x00000000,
>> +};
>> +
>> +static const VMStateDescription aspeed_adc_vmstate = {
>> + .name = TYPE_ASPEED_ADC,
>> + .version_id = 0,
>> + .minimum_version_id = 0,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32_ARRAY(regs, AspeedADCState, ASPEED_ADC_MAX_REGS),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static void aspeed_adc_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + dc->realize = aspeed_adc_realize;
>> + dc->reset = aspeed_adc_reset;
>> + dc->desc = "Aspeed Analog-to-Digital Converter";
>> + dc->vmsd = &aspeed_adc_vmstate;
>> +}
>> +
>> +static void aspeed_2400_adc_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
>> +
>> + dc->desc = "Aspeed 2400 Analog-to-Digital Converter";
>> + aac->resets = aspeed_2400_resets;
>> + aac->nr_regs = ASPEED_2400_ADC_NR_REGS;
>> +}
>> +
>> +static void aspeed_2500_adc_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
>> +
>> + dc->desc = "Aspeed 2500 Analog-to-Digital Converter";
>> + aac->resets = aspeed_2500_resets;
>> + aac->nr_regs = ASPEED_2500_ADC_NR_REGS;
>> +}
>> +
>> +static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
>> +
>> + dc->desc = "Aspeed 2600 Analog-to-Digital Converter";
>> + aac->resets = aspeed_2600_resets;
>> + aac->nr_regs = ASPEED_2600_ADC_NR_REGS;
>> +}
>> +
>> +static const TypeInfo aspeed_adc_info = {
>> + .name = TYPE_ASPEED_ADC,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(AspeedADCState),
>> + .class_init = aspeed_adc_class_init,
>> + .class_size = sizeof(AspeedADCClass),
>> + .abstract = true,
>> +};
>> +
>> +static const TypeInfo aspeed_2400_adc_info = {
>> + .name = TYPE_ASPEED_2400_ADC,
>> + .parent = TYPE_ASPEED_ADC,
>> + .instance_size = sizeof(AspeedADCState),
>> + .class_init = aspeed_2400_adc_class_init,
>> +};
>> +
>> +static const TypeInfo aspeed_2500_adc_info = {
>> + .name = TYPE_ASPEED_2500_ADC,
>> + .parent = TYPE_ASPEED_ADC,
>> + .instance_size = sizeof(AspeedADCState),
>> + .class_init = aspeed_2500_adc_class_init,
>> +};
>> +
>> +static const TypeInfo aspeed_2600_adc_info = {
>> + .name = TYPE_ASPEED_2600_ADC,
>> + .parent = TYPE_ASPEED_ADC,
>> + .instance_size = sizeof(AspeedADCState),
>> + .class_init = aspeed_2600_adc_class_init,
>> +};
>> +
>> +static void aspeed_adc_register_types(void)
>> +{
>> + type_register_static(&aspeed_adc_info);
>> + type_register_static(&aspeed_2400_adc_info);
>> + type_register_static(&aspeed_2500_adc_info);
>> + type_register_static(&aspeed_2600_adc_info);
>> +}
>> +
>> +type_init(aspeed_adc_register_types);
>> diff --git a/hw/adc/meson.build b/hw/adc/meson.build
>> index ac4f093fea..65e1dd73c1 100644
>> --- a/hw/adc/meson.build
>> +++ b/hw/adc/meson.build
>> @@ -2,3 +2,4 @@ softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true:
>> files('stm32f2xx_adc.c'))
>> softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
>> softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c'))
>> softmmu_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c'))
>> +softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c'))
>> diff --git a/hw/adc/trace-events b/hw/adc/trace-events
>> index 456f21c8f4..c23d7bb6d7 100644
>> --- a/hw/adc/trace-events
>> +++ b/hw/adc/trace-events
>> @@ -3,3 +3,7 @@
>> # npcm7xx_adc.c
>> npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s
>> offset: 0x%04" PRIx64 " value 0x%04" PRIx32
>> npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s
>> offset: 0x%04" PRIx64 " value 0x%04" PRIx32
>> +
>> +# aspeed_adc.c
>> +aspeed_adc_read(uint8_t offset, uint32_t value) "0x%02" PRIx8 " read
>> 0x%04" PRIx32
>> +aspeed_adc_write(uint8_t offset, uint32_t value) "0x%02" PRIx8 " write
>> 0x%04" PRIx32
>> diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
>> index 9d70e8e060..a582e882f2 100644
>> --- a/hw/arm/aspeed_ast2600.c
>> +++ b/hw/arm/aspeed_ast2600.c
>> @@ -44,6 +44,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
>> [ASPEED_DEV_SCU] = 0x1E6E2000,
>> [ASPEED_DEV_XDMA] = 0x1E6E7000,
>> [ASPEED_DEV_ADC] = 0x1E6E9000,
>> + [ASPEED_DEV_ADC2] = 0x1E6E9100,
>
> Look at the AspeedADCEngine approach introduced in the initial
> series. It simplifies the integration in the machine.
Oh yeah, I’ll use the AspeedADCEngine approach instead.
>
> Thanks,
>
> C.
>
>> [ASPEED_DEV_VIDEO] = 0x1E700000,
>> [ASPEED_DEV_SDHCI] = 0x1E740000,
>> [ASPEED_DEV_EMMC] = 0x1E750000,
>> @@ -77,6 +78,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
>> [ASPEED_DEV_SDMC] = 0,
>> [ASPEED_DEV_SCU] = 12,
>> [ASPEED_DEV_ADC] = 78,
>> + [ASPEED_DEV_ADC2] = 78,
>> [ASPEED_DEV_XDMA] = 6,
>> [ASPEED_DEV_SDHCI] = 43,
>> [ASPEED_DEV_EHCI1] = 5,
>> @@ -216,6 +218,11 @@ static void aspeed_soc_ast2600_init(Object *obj)
>> snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
>> object_initialize_child(obj, "hace", &s->hace, typename);
>> +
>> + snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
>> + for (i = 0; i < sc->adcs_num; i++) {
>> + object_initialize_child(obj, "adc[*]", &s->adc[i], typename);
>> + }
>> }
>> /*
>> @@ -507,6 +514,16 @@ static void aspeed_soc_ast2600_realize(DeviceState
>> *dev, Error **errp)
>> sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0,
>> sc->memmap[ASPEED_DEV_HACE]);
>> sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
>> aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
>> +
>> + /* ADC */
>> + for (int i = 0; i < sc->adcs_num; i++) {
>> + SysBusDevice *bus = SYS_BUS_DEVICE(&s->adc[i]);
>> + if (!sysbus_realize(bus, errp)) {
>> + return;
>> + }
>> + sysbus_mmio_map(bus, 0, sc->memmap[ASPEED_DEV_ADC + i]);
>> + sysbus_connect_irq(bus, 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC +
>> i));
>> + }
>> }
>> static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
>> @@ -524,6 +541,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass
>> *oc, void *data)
>> sc->ehcis_num = 2;
>> sc->wdts_num = 4;
>> sc->macs_num = 4;
>> + sc->adcs_num = 2;
>> sc->irqmap = aspeed_soc_ast2600_irqmap;
>> sc->memmap = aspeed_soc_ast2600_memmap;
>> sc->num_cpus = 2;
>> diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
>> index ed84502e23..412c557e40 100644
>> --- a/hw/arm/aspeed_soc.c
>> +++ b/hw/arm/aspeed_soc.c
>> @@ -216,6 +216,11 @@ static void aspeed_soc_init(Object *obj)
>> snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
>> object_initialize_child(obj, "hace", &s->hace, typename);
>> +
>> + snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
>> + for (i = 0; i < sc->adcs_num; i++) {
>> + object_initialize_child(obj, "adc[*]", &s->adc[i], typename);
>> + }
>> }
>> static void aspeed_soc_realize(DeviceState *dev, Error **errp)
>> @@ -435,6 +440,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error
>> **errp)
>> sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0,
>> sc->memmap[ASPEED_DEV_HACE]);
>> sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
>> aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
>> +
>> + /* ADC */
>> + for (int i = 0; i < sc->adcs_num; i++) {
>> + SysBusDevice *bus = SYS_BUS_DEVICE(&s->adc[i]);
>> + if (!sysbus_realize(bus, errp)) {
>> + return;
>> + }
>> + sysbus_mmio_map(bus, 0, sc->memmap[ASPEED_DEV_ADC + i]);
>> + sysbus_connect_irq(bus, 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC +
>> i));
>> + }
>> }
>> static Property aspeed_soc_properties[] = {
>> DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
>> @@ -475,6 +490,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass
>> *oc, void *data)
>> sc->ehcis_num = 1;
>> sc->wdts_num = 2;
>> sc->macs_num = 2;
>> + sc->adcs_num = 1;
>> sc->irqmap = aspeed_soc_ast2400_irqmap;
>> sc->memmap = aspeed_soc_ast2400_memmap;
>> sc->num_cpus = 1;
>> @@ -500,6 +516,7 @@ static void aspeed_soc_ast2500_class_init(ObjectClass
>> *oc, void *data)
>> sc->ehcis_num = 2;
>> sc->wdts_num = 3;
>> sc->macs_num = 2;
>> + sc->adcs_num = 1;
>> sc->irqmap = aspeed_soc_ast2500_irqmap;
>> sc->memmap = aspeed_soc_ast2500_memmap;
>> sc->num_cpus = 1;
>> diff --git a/include/hw/adc/aspeed_adc.h b/include/hw/adc/aspeed_adc.h
>> new file mode 100644
>> index 0000000000..5528781be0
>> --- /dev/null
>> +++ b/include/hw/adc/aspeed_adc.h
>> @@ -0,0 +1,48 @@
>> +/*
>> + * Aspeed ADC Controller
>> + *
>> + * Copyright 2021 Facebook, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
>> + * for more details.
>> + */
>> +
>> +#ifndef ASPEED_ADC_H
>> +#define ASPEED_ADC_H
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/sysbus.h"
>> +#include "qom/object.h"
>> +
>> +#define TYPE_ASPEED_ADC "aspeed.adc"
>> +OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC)
>> +#define TYPE_ASPEED_2400_ADC TYPE_ASPEED_ADC "-ast2400"
>> +#define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500"
>> +#define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600"
>> +
>> +#define ASPEED_2400_ADC_NR_REGS (0xC4 >> 2)
>> +#define ASPEED_2500_ADC_NR_REGS (0xC8 >> 2)
>> +#define ASPEED_2600_ADC_NR_REGS (0xD0 >> 2)
>> +#define ASPEED_ADC_MAX_REGS ASPEED_2600_ADC_NR_REGS
>> +
>> +struct AspeedADCState {
>> + SysBusDevice parent;
>> + MemoryRegion mmio;
>> + qemu_irq irq;
>> + uint32_t regs[ASPEED_ADC_MAX_REGS];
>> +};
>> +
>> +struct AspeedADCClass {
>> + SysBusDeviceClass parent;
>> + const uint32_t *resets;
>> + uint32_t nr_regs;
>> +};
>> +
>> +#endif
>> diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
>> index 87d76c9259..4503f08870 100644
>> --- a/include/hw/arm/aspeed_soc.h
>> +++ b/include/hw/arm/aspeed_soc.h
>> @@ -30,12 +30,14 @@
>> #include "hw/usb/hcd-ehci.h"
>> #include "qom/object.h"
>> #include "hw/misc/aspeed_lpc.h"
>> +#include "hw/adc/aspeed_adc.h"
>> #define ASPEED_SPIS_NUM 2
>> #define ASPEED_EHCIS_NUM 2
>> #define ASPEED_WDTS_NUM 4
>> #define ASPEED_CPUS_NUM 2
>> #define ASPEED_MACS_NUM 4
>> +#define ASPEED_ADCS_NUM 2
>> struct AspeedSoCState {
>> /*< private >*/
>> @@ -65,6 +67,7 @@ struct AspeedSoCState {
>> AspeedSDHCIState sdhci;
>> AspeedSDHCIState emmc;
>> AspeedLPCState lpc;
>> + AspeedADCState adc[ASPEED_ADCS_NUM];
>> uint32_t uart_default;
>> };
>> @@ -82,6 +85,7 @@ struct AspeedSoCClass {
>> int ehcis_num;
>> int wdts_num;
>> int macs_num;
>> + int adcs_num;
>> const int *irqmap;
>> const hwaddr *memmap;
>> uint32_t num_cpus;
>> @@ -105,6 +109,7 @@ enum {
>> ASPEED_DEV_SDMC,
>> ASPEED_DEV_SCU,
>> ASPEED_DEV_ADC,
>> + ASPEED_DEV_ADC2,
>> ASPEED_DEV_VIDEO,
>> ASPEED_DEV_SRAM,
>> ASPEED_DEV_SDHCI,
>