qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

aspeed_adc.c (14888B)


      1 /*
      2  * Aspeed ADC
      3  *
      4  * Copyright 2017-2021 IBM Corp.
      5  *
      6  * Andrew Jeffery <andrew@aj.id.au>
      7  *
      8  * SPDX-License-Identifier: GPL-2.0-or-later
      9  */
     10 
     11 #include "qemu/osdep.h"
     12 #include "qapi/error.h"
     13 #include "qemu/log.h"
     14 #include "hw/irq.h"
     15 #include "hw/qdev-properties.h"
     16 #include "migration/vmstate.h"
     17 #include "hw/adc/aspeed_adc.h"
     18 #include "trace.h"
     19 
     20 #define ASPEED_ADC_MEMORY_REGION_SIZE           0x1000
     21 #define ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE    0x100
     22 #define  ASPEED_ADC_ENGINE_CH_EN_MASK           0xffff0000
     23 #define   ASPEED_ADC_ENGINE_CH_EN(x)            ((BIT(x)) << 16)
     24 #define  ASPEED_ADC_ENGINE_INIT                 BIT(8)
     25 #define  ASPEED_ADC_ENGINE_AUTO_COMP            BIT(5)
     26 #define  ASPEED_ADC_ENGINE_COMP                 BIT(4)
     27 #define  ASPEED_ADC_ENGINE_MODE_MASK            0x0000000e
     28 #define   ASPEED_ADC_ENGINE_MODE_OFF            (0b000 << 1)
     29 #define   ASPEED_ADC_ENGINE_MODE_STANDBY        (0b001 << 1)
     30 #define   ASPEED_ADC_ENGINE_MODE_NORMAL         (0b111 << 1)
     31 #define  ASPEED_ADC_ENGINE_EN                   BIT(0)
     32 #define ASPEED_ADC_HYST_EN                      BIT(31)
     33 
     34 #define ASPEED_ADC_L_MASK       ((1 << 10) - 1)
     35 #define ASPEED_ADC_L(x)         ((x) & ASPEED_ADC_L_MASK)
     36 #define ASPEED_ADC_H(x)         (((x) >> 16) & ASPEED_ADC_L_MASK)
     37 #define ASPEED_ADC_LH_MASK      (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK)
     38 #define LOWER_CHANNEL_MASK      ((1 << 10) - 1)
     39 #define LOWER_CHANNEL_DATA(x)   ((x) & LOWER_CHANNEL_MASK)
     40 #define UPPER_CHANNEL_DATA(x)   (((x) >> 16) & LOWER_CHANNEL_MASK)
     41 
     42 #define TO_REG(addr) (addr >> 2)
     43 
     44 #define ENGINE_CONTROL              TO_REG(0x00)
     45 #define INTERRUPT_CONTROL           TO_REG(0x04)
     46 #define VGA_DETECT_CONTROL          TO_REG(0x08)
     47 #define CLOCK_CONTROL               TO_REG(0x0C)
     48 #define DATA_CHANNEL_1_AND_0        TO_REG(0x10)
     49 #define DATA_CHANNEL_7_AND_6        TO_REG(0x1C)
     50 #define DATA_CHANNEL_9_AND_8        TO_REG(0x20)
     51 #define DATA_CHANNEL_15_AND_14      TO_REG(0x2C)
     52 #define BOUNDS_CHANNEL_0            TO_REG(0x30)
     53 #define BOUNDS_CHANNEL_7            TO_REG(0x4C)
     54 #define BOUNDS_CHANNEL_8            TO_REG(0x50)
     55 #define BOUNDS_CHANNEL_15           TO_REG(0x6C)
     56 #define HYSTERESIS_CHANNEL_0        TO_REG(0x70)
     57 #define HYSTERESIS_CHANNEL_7        TO_REG(0x8C)
     58 #define HYSTERESIS_CHANNEL_8        TO_REG(0x90)
     59 #define HYSTERESIS_CHANNEL_15       TO_REG(0xAC)
     60 #define INTERRUPT_SOURCE            TO_REG(0xC0)
     61 #define COMPENSATING_AND_TRIMMING   TO_REG(0xC4)
     62 
     63 static inline uint32_t update_channels(uint32_t current)
     64 {
     65     return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) |
     66         ((current + 5) & ASPEED_ADC_L_MASK);
     67 }
     68 
     69 static bool breaks_threshold(AspeedADCEngineState *s, int reg)
     70 {
     71     assert(reg >= DATA_CHANNEL_1_AND_0 &&
     72            reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
     73 
     74     int a_bounds_reg = BOUNDS_CHANNEL_0 + (reg - DATA_CHANNEL_1_AND_0) * 2;
     75     int b_bounds_reg = a_bounds_reg + 1;
     76     uint32_t a_and_b = s->regs[reg];
     77     uint32_t a_bounds = s->regs[a_bounds_reg];
     78     uint32_t b_bounds = s->regs[b_bounds_reg];
     79     uint32_t a = ASPEED_ADC_L(a_and_b);
     80     uint32_t b = ASPEED_ADC_H(a_and_b);
     81     uint32_t a_lower = ASPEED_ADC_L(a_bounds);
     82     uint32_t a_upper = ASPEED_ADC_H(a_bounds);
     83     uint32_t b_lower = ASPEED_ADC_L(b_bounds);
     84     uint32_t b_upper = ASPEED_ADC_H(b_bounds);
     85 
     86     return (a < a_lower || a > a_upper) ||
     87            (b < b_lower || b > b_upper);
     88 }
     89 
     90 static uint32_t read_channel_sample(AspeedADCEngineState *s, int reg)
     91 {
     92     assert(reg >= DATA_CHANNEL_1_AND_0 &&
     93            reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
     94 
     95     /* Poor man's sampling */
     96     uint32_t value = s->regs[reg];
     97     s->regs[reg] = update_channels(s->regs[reg]);
     98 
     99     if (breaks_threshold(s, reg)) {
    100         s->regs[INTERRUPT_CONTROL] |= BIT(reg - DATA_CHANNEL_1_AND_0);
    101         qemu_irq_raise(s->irq);
    102     }
    103 
    104     return value;
    105 }
    106 
    107 static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr,
    108                                        unsigned int size)
    109 {
    110     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
    111     int reg = TO_REG(addr);
    112     uint32_t value = 0;
    113 
    114     switch (reg) {
    115     case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
    116         if (s->nr_channels <= 8) {
    117             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    118                           "bounds register %u invalid, only 0...7 valid\n",
    119                           __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
    120             break;
    121         }
    122         /* fallthrough */
    123     case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
    124         if (s->nr_channels <= 8) {
    125             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    126                           "hysteresis register %u invalid, only 0...7 valid\n",
    127                           __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
    128             break;
    129         }
    130         /* fallthrough */
    131     case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
    132     case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
    133     case ENGINE_CONTROL:
    134     case INTERRUPT_CONTROL:
    135     case VGA_DETECT_CONTROL:
    136     case CLOCK_CONTROL:
    137     case INTERRUPT_SOURCE:
    138     case COMPENSATING_AND_TRIMMING:
    139         value = s->regs[reg];
    140         break;
    141     case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
    142         if (s->nr_channels <= 8) {
    143             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    144                           "data register %u invalid, only 0...3 valid\n",
    145                           __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
    146             break;
    147         }
    148         /* fallthrough */
    149     case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
    150         value = read_channel_sample(s, reg);
    151         /* Allow 16-bit reads of the data registers */
    152         if (addr & 0x2) {
    153             assert(size == 2);
    154             value >>= 16;
    155         }
    156         break;
    157     default:
    158         qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: 0x%" HWADDR_PRIx "\n",
    159                       __func__, s->engine_id, addr);
    160         break;
    161     }
    162 
    163     trace_aspeed_adc_engine_read(s->engine_id, addr, value);
    164     return value;
    165 }
    166 
    167 static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t value,
    168                                     unsigned int size)
    169 {
    170     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
    171     int reg = TO_REG(addr);
    172     uint32_t init = 0;
    173 
    174     trace_aspeed_adc_engine_write(s->engine_id, addr, value);
    175 
    176     switch (reg) {
    177     case ENGINE_CONTROL:
    178         init = !!(value & ASPEED_ADC_ENGINE_EN);
    179         init *= ASPEED_ADC_ENGINE_INIT;
    180 
    181         value &= ~ASPEED_ADC_ENGINE_INIT;
    182         value |= init;
    183 
    184         value &= ~ASPEED_ADC_ENGINE_AUTO_COMP;
    185         break;
    186     case INTERRUPT_CONTROL:
    187     case VGA_DETECT_CONTROL:
    188     case CLOCK_CONTROL:
    189         break;
    190     case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
    191         if (s->nr_channels <= 8) {
    192             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    193                           "data register %u invalid, only 0...3 valid\n",
    194                           __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
    195             return;
    196         }
    197         /* fallthrough */
    198     case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
    199         if (s->nr_channels <= 8) {
    200             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    201                           "bounds register %u invalid, only 0...7 valid\n",
    202                           __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
    203             return;
    204         }
    205         /* fallthrough */
    206     case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
    207     case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
    208         value &= ASPEED_ADC_LH_MASK;
    209         break;
    210     case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
    211         if (s->nr_channels <= 8) {
    212             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    213                           "hysteresis register %u invalid, only 0...7 valid\n",
    214                           __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
    215             return;
    216         }
    217         /* fallthrough */
    218     case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
    219         value &= (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK);
    220         break;
    221     case INTERRUPT_SOURCE:
    222         value &= 0xffff;
    223         break;
    224     case COMPENSATING_AND_TRIMMING:
    225         value &= 0xf;
    226         break;
    227     default:
    228         qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: "
    229                       "0x%" HWADDR_PRIx " 0x%" PRIx64 "\n",
    230                       __func__, s->engine_id, addr, value);
    231         break;
    232     }
    233 
    234     s->regs[reg] = value;
    235 }
    236 
    237 static const MemoryRegionOps aspeed_adc_engine_ops = {
    238     .read = aspeed_adc_engine_read,
    239     .write = aspeed_adc_engine_write,
    240     .endianness = DEVICE_LITTLE_ENDIAN,
    241     .valid = {
    242         .min_access_size = 2,
    243         .max_access_size = 4,
    244         .unaligned = false,
    245     },
    246 };
    247 
    248 static const uint32_t aspeed_adc_resets[ASPEED_ADC_NR_REGS] = {
    249     [ENGINE_CONTROL]     = 0x00000000,
    250     [INTERRUPT_CONTROL]  = 0x00000000,
    251     [VGA_DETECT_CONTROL] = 0x0000000f,
    252     [CLOCK_CONTROL]      = 0x0000000f,
    253 };
    254 
    255 static void aspeed_adc_engine_reset(DeviceState *dev)
    256 {
    257     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
    258 
    259     memcpy(s->regs, aspeed_adc_resets, sizeof(aspeed_adc_resets));
    260 }
    261 
    262 static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp)
    263 {
    264     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
    265     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    266     g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d",
    267                                             s->engine_id);
    268 
    269     assert(s->engine_id < 2);
    270 
    271     sysbus_init_irq(sbd, &s->irq);
    272 
    273     memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name,
    274                           ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE);
    275 
    276     sysbus_init_mmio(sbd, &s->mmio);
    277 }
    278 
    279 static const VMStateDescription vmstate_aspeed_adc_engine = {
    280     .name = TYPE_ASPEED_ADC,
    281     .version_id = 1,
    282     .minimum_version_id = 1,
    283     .fields = (VMStateField[]) {
    284         VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS),
    285         VMSTATE_END_OF_LIST(),
    286     }
    287 };
    288 
    289 static Property aspeed_adc_engine_properties[] = {
    290     DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0),
    291     DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0),
    292     DEFINE_PROP_END_OF_LIST(),
    293 };
    294 
    295 static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
    296 {
    297     DeviceClass *dc = DEVICE_CLASS(klass);
    298 
    299     dc->realize = aspeed_adc_engine_realize;
    300     dc->reset = aspeed_adc_engine_reset;
    301     device_class_set_props(dc, aspeed_adc_engine_properties);
    302     dc->desc = "Aspeed Analog-to-Digital Engine";
    303     dc->vmsd = &vmstate_aspeed_adc_engine;
    304 }
    305 
    306 static const TypeInfo aspeed_adc_engine_info = {
    307     .name = TYPE_ASPEED_ADC_ENGINE,
    308     .parent = TYPE_SYS_BUS_DEVICE,
    309     .instance_size = sizeof(AspeedADCEngineState),
    310     .class_init = aspeed_adc_engine_class_init,
    311 };
    312 
    313 static void aspeed_adc_instance_init(Object *obj)
    314 {
    315     AspeedADCState *s = ASPEED_ADC(obj);
    316     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj);
    317     uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines;
    318 
    319     for (int i = 0; i < aac->nr_engines; i++) {
    320         AspeedADCEngineState *engine = &s->engines[i];
    321         object_initialize_child(obj, "engine[*]", engine,
    322                                 TYPE_ASPEED_ADC_ENGINE);
    323         qdev_prop_set_uint32(DEVICE(engine), "engine-id", i);
    324         qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels);
    325     }
    326 }
    327 
    328 static void aspeed_adc_set_irq(void *opaque, int n, int level)
    329 {
    330     AspeedADCState *s = opaque;
    331     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s);
    332     uint32_t pending = 0;
    333 
    334     /* TODO: update Global IRQ status register on AST2600 (Need specs) */
    335     for (int i = 0; i < aac->nr_engines; i++) {
    336         uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF;
    337         pending |= irq_status << (i * 8);
    338     }
    339 
    340     qemu_set_irq(s->irq, !!pending);
    341 }
    342 
    343 static void aspeed_adc_realize(DeviceState *dev, Error **errp)
    344 {
    345     AspeedADCState *s = ASPEED_ADC(dev);
    346     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    347     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
    348 
    349     qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq,
    350                                         s, NULL, aac->nr_engines);
    351 
    352     sysbus_init_irq(sbd, &s->irq);
    353 
    354     memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC,
    355                        ASPEED_ADC_MEMORY_REGION_SIZE);
    356 
    357     sysbus_init_mmio(sbd, &s->mmio);
    358 
    359     for (int i = 0; i < aac->nr_engines; i++) {
    360         Object *eng = OBJECT(&s->engines[i]);
    361 
    362         if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) {
    363             return;
    364         }
    365         sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0,
    366                            qdev_get_gpio_in(DEVICE(sbd), i));
    367         memory_region_add_subregion(&s->mmio,
    368                                     i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE,
    369                                     &s->engines[i].mmio);
    370     }
    371 }
    372 
    373 static void aspeed_adc_class_init(ObjectClass *klass, void *data)
    374 {
    375     DeviceClass *dc = DEVICE_CLASS(klass);
    376     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
    377 
    378     dc->realize = aspeed_adc_realize;
    379     dc->desc = "Aspeed Analog-to-Digital Converter";
    380     aac->nr_engines = 1;
    381 }
    382 
    383 static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
    384 {
    385     DeviceClass *dc = DEVICE_CLASS(klass);
    386     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
    387 
    388     dc->desc = "ASPEED 2600 ADC Controller";
    389     aac->nr_engines = 2;
    390 }
    391 
    392 static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data)
    393 {
    394     DeviceClass *dc = DEVICE_CLASS(klass);
    395     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
    396 
    397     dc->desc = "ASPEED 1030 ADC Controller";
    398     aac->nr_engines = 2;
    399 }
    400 
    401 static const TypeInfo aspeed_adc_info = {
    402     .name = TYPE_ASPEED_ADC,
    403     .parent = TYPE_SYS_BUS_DEVICE,
    404     .instance_init = aspeed_adc_instance_init,
    405     .instance_size = sizeof(AspeedADCState),
    406     .class_init = aspeed_adc_class_init,
    407     .class_size = sizeof(AspeedADCClass),
    408     .abstract   = true,
    409 };
    410 
    411 static const TypeInfo aspeed_2400_adc_info = {
    412     .name = TYPE_ASPEED_2400_ADC,
    413     .parent = TYPE_ASPEED_ADC,
    414 };
    415 
    416 static const TypeInfo aspeed_2500_adc_info = {
    417     .name = TYPE_ASPEED_2500_ADC,
    418     .parent = TYPE_ASPEED_ADC,
    419 };
    420 
    421 static const TypeInfo aspeed_2600_adc_info = {
    422     .name = TYPE_ASPEED_2600_ADC,
    423     .parent = TYPE_ASPEED_ADC,
    424     .class_init = aspeed_2600_adc_class_init,
    425 };
    426 
    427 static const TypeInfo aspeed_1030_adc_info = {
    428     .name = TYPE_ASPEED_1030_ADC,
    429     .parent = TYPE_ASPEED_ADC,
    430     .class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */
    431 };
    432 
    433 static void aspeed_adc_register_types(void)
    434 {
    435     type_register_static(&aspeed_adc_engine_info);
    436     type_register_static(&aspeed_adc_info);
    437     type_register_static(&aspeed_2400_adc_info);
    438     type_register_static(&aspeed_2500_adc_info);
    439     type_register_static(&aspeed_2600_adc_info);
    440     type_register_static(&aspeed_1030_adc_info);
    441 }
    442 
    443 type_init(aspeed_adc_register_types);