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
update_channels(uint32_t current)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
breaks_threshold(AspeedADCEngineState * s,int reg)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
read_channel_sample(AspeedADCEngineState * s,int reg)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
aspeed_adc_engine_read(void * opaque,hwaddr addr,unsigned int size)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
aspeed_adc_engine_write(void * opaque,hwaddr addr,uint64_t value,unsigned int size)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
aspeed_adc_engine_reset(DeviceState * dev)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
aspeed_adc_engine_realize(DeviceState * dev,Error ** errp)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 = (const VMStateField[]) {
284 VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS),
285 VMSTATE_END_OF_LIST(),
286 }
287 };
288
289 static const 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 };
293
aspeed_adc_engine_class_init(ObjectClass * klass,const void * data)294 static void aspeed_adc_engine_class_init(ObjectClass *klass, const void *data)
295 {
296 DeviceClass *dc = DEVICE_CLASS(klass);
297
298 dc->realize = aspeed_adc_engine_realize;
299 device_class_set_legacy_reset(dc, aspeed_adc_engine_reset);
300 device_class_set_props(dc, aspeed_adc_engine_properties);
301 dc->desc = "Aspeed Analog-to-Digital Engine";
302 dc->vmsd = &vmstate_aspeed_adc_engine;
303 }
304
305 static const TypeInfo aspeed_adc_engine_info = {
306 .name = TYPE_ASPEED_ADC_ENGINE,
307 .parent = TYPE_SYS_BUS_DEVICE,
308 .instance_size = sizeof(AspeedADCEngineState),
309 .class_init = aspeed_adc_engine_class_init,
310 };
311
aspeed_adc_instance_init(Object * obj)312 static void aspeed_adc_instance_init(Object *obj)
313 {
314 AspeedADCState *s = ASPEED_ADC(obj);
315 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj);
316 uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines;
317
318 for (int i = 0; i < aac->nr_engines; i++) {
319 AspeedADCEngineState *engine = &s->engines[i];
320 object_initialize_child(obj, "engine[*]", engine,
321 TYPE_ASPEED_ADC_ENGINE);
322 qdev_prop_set_uint32(DEVICE(engine), "engine-id", i);
323 qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels);
324 }
325 }
326
aspeed_adc_set_irq(void * opaque,int n,int level)327 static void aspeed_adc_set_irq(void *opaque, int n, int level)
328 {
329 AspeedADCState *s = opaque;
330 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s);
331 uint32_t pending = 0;
332
333 /* TODO: update Global IRQ status register on AST2600 (Need specs) */
334 for (int i = 0; i < aac->nr_engines; i++) {
335 uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF;
336 pending |= irq_status << (i * 8);
337 }
338
339 qemu_set_irq(s->irq, !!pending);
340 }
341
aspeed_adc_realize(DeviceState * dev,Error ** errp)342 static void aspeed_adc_realize(DeviceState *dev, Error **errp)
343 {
344 AspeedADCState *s = ASPEED_ADC(dev);
345 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
346 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
347
348 qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq,
349 s, NULL, aac->nr_engines);
350
351 sysbus_init_irq(sbd, &s->irq);
352
353 memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC,
354 ASPEED_ADC_MEMORY_REGION_SIZE);
355
356 sysbus_init_mmio(sbd, &s->mmio);
357
358 for (int i = 0; i < aac->nr_engines; i++) {
359 Object *eng = OBJECT(&s->engines[i]);
360
361 if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) {
362 return;
363 }
364 sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0,
365 qdev_get_gpio_in(DEVICE(sbd), i));
366 memory_region_add_subregion(&s->mmio,
367 i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE,
368 &s->engines[i].mmio);
369 }
370 }
371
aspeed_adc_class_init(ObjectClass * klass,const void * data)372 static void aspeed_adc_class_init(ObjectClass *klass, const void *data)
373 {
374 DeviceClass *dc = DEVICE_CLASS(klass);
375 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
376
377 dc->realize = aspeed_adc_realize;
378 dc->desc = "Aspeed Analog-to-Digital Converter";
379 aac->nr_engines = 1;
380 }
381
aspeed_2600_adc_class_init(ObjectClass * klass,const void * data)382 static void aspeed_2600_adc_class_init(ObjectClass *klass, const void *data)
383 {
384 DeviceClass *dc = DEVICE_CLASS(klass);
385 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
386
387 dc->desc = "ASPEED 2600 ADC Controller";
388 aac->nr_engines = 2;
389 }
390
aspeed_1030_adc_class_init(ObjectClass * klass,const void * data)391 static void aspeed_1030_adc_class_init(ObjectClass *klass, const void *data)
392 {
393 DeviceClass *dc = DEVICE_CLASS(klass);
394 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
395
396 dc->desc = "ASPEED 1030 ADC Controller";
397 aac->nr_engines = 2;
398 }
399
aspeed_2700_adc_class_init(ObjectClass * klass,const void * data)400 static void aspeed_2700_adc_class_init(ObjectClass *klass, const void *data)
401 {
402 DeviceClass *dc = DEVICE_CLASS(klass);
403 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
404
405 dc->desc = "ASPEED 2700 ADC Controller";
406 aac->nr_engines = 2;
407 }
408
409 static const TypeInfo aspeed_adc_info = {
410 .name = TYPE_ASPEED_ADC,
411 .parent = TYPE_SYS_BUS_DEVICE,
412 .instance_init = aspeed_adc_instance_init,
413 .instance_size = sizeof(AspeedADCState),
414 .class_init = aspeed_adc_class_init,
415 .class_size = sizeof(AspeedADCClass),
416 .abstract = true,
417 };
418
419 static const TypeInfo aspeed_2400_adc_info = {
420 .name = TYPE_ASPEED_2400_ADC,
421 .parent = TYPE_ASPEED_ADC,
422 };
423
424 static const TypeInfo aspeed_2500_adc_info = {
425 .name = TYPE_ASPEED_2500_ADC,
426 .parent = TYPE_ASPEED_ADC,
427 };
428
429 static const TypeInfo aspeed_2600_adc_info = {
430 .name = TYPE_ASPEED_2600_ADC,
431 .parent = TYPE_ASPEED_ADC,
432 .class_init = aspeed_2600_adc_class_init,
433 };
434
435 static const TypeInfo aspeed_1030_adc_info = {
436 .name = TYPE_ASPEED_1030_ADC,
437 .parent = TYPE_ASPEED_ADC,
438 .class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */
439 };
440
441 static const TypeInfo aspeed_2700_adc_info = {
442 .name = TYPE_ASPEED_2700_ADC,
443 .parent = TYPE_ASPEED_ADC,
444 .class_init = aspeed_2700_adc_class_init,
445 };
446
aspeed_adc_register_types(void)447 static void aspeed_adc_register_types(void)
448 {
449 type_register_static(&aspeed_adc_engine_info);
450 type_register_static(&aspeed_adc_info);
451 type_register_static(&aspeed_2400_adc_info);
452 type_register_static(&aspeed_2500_adc_info);
453 type_register_static(&aspeed_2600_adc_info);
454 type_register_static(&aspeed_1030_adc_info);
455 type_register_static(&aspeed_2700_adc_info);
456 }
457
458 type_init(aspeed_adc_register_types);
459