xref: /qemu/hw/adc/aspeed_adc.c (revision dbd9e084)
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 const TypeInfo aspeed_adc_info = {
393     .name = TYPE_ASPEED_ADC,
394     .parent = TYPE_SYS_BUS_DEVICE,
395     .instance_init = aspeed_adc_instance_init,
396     .instance_size = sizeof(AspeedADCState),
397     .class_init = aspeed_adc_class_init,
398     .class_size = sizeof(AspeedADCClass),
399     .abstract   = true,
400 };
401 
402 static const TypeInfo aspeed_2400_adc_info = {
403     .name = TYPE_ASPEED_2400_ADC,
404     .parent = TYPE_ASPEED_ADC,
405 };
406 
407 static const TypeInfo aspeed_2500_adc_info = {
408     .name = TYPE_ASPEED_2500_ADC,
409     .parent = TYPE_ASPEED_ADC,
410 };
411 
412 static const TypeInfo aspeed_2600_adc_info = {
413     .name = TYPE_ASPEED_2600_ADC,
414     .parent = TYPE_ASPEED_ADC,
415     .class_init = aspeed_2600_adc_class_init,
416 };
417 
418 static void aspeed_adc_register_types(void)
419 {
420     type_register_static(&aspeed_adc_engine_info);
421     type_register_static(&aspeed_adc_info);
422     type_register_static(&aspeed_2400_adc_info);
423     type_register_static(&aspeed_2500_adc_info);
424     type_register_static(&aspeed_2600_adc_info);
425 }
426 
427 type_init(aspeed_adc_register_types);
428