4 * Copyright 2017-2021 IBM Corp.
6 * Andrew Jeffery <andrew@aj.id.au>
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
15 #include "hw/qdev-properties.h"
16 #include "migration/vmstate.h"
17 #include "hw/adc/aspeed_adc.h"
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)
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)
42 #define TO_REG(addr) (addr >> 2)
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)
63 static inline uint32_t update_channels(uint32_t current
)
65 return ((((current
>> 16) & ASPEED_ADC_L_MASK
) + 7) << 16) |
66 ((current
+ 5) & ASPEED_ADC_L_MASK
);
69 static bool breaks_threshold(AspeedADCEngineState
*s
, int reg
)
71 assert(reg
>= DATA_CHANNEL_1_AND_0
&&
72 reg
< DATA_CHANNEL_1_AND_0
+ s
->nr_channels
/ 2);
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
);
86 return (a
< a_lower
|| a
> a_upper
) ||
87 (b
< b_lower
|| b
> b_upper
);
90 static uint32_t read_channel_sample(AspeedADCEngineState
*s
, int reg
)
92 assert(reg
>= DATA_CHANNEL_1_AND_0
&&
93 reg
< DATA_CHANNEL_1_AND_0
+ s
->nr_channels
/ 2);
95 /* Poor man's sampling */
96 uint32_t value
= s
->regs
[reg
];
97 s
->regs
[reg
] = update_channels(s
->regs
[reg
]);
99 if (breaks_threshold(s
, reg
)) {
100 s
->regs
[INTERRUPT_CONTROL
] |= BIT(reg
- DATA_CHANNEL_1_AND_0
);
101 qemu_irq_raise(s
->irq
);
107 static uint64_t aspeed_adc_engine_read(void *opaque
, hwaddr addr
,
110 AspeedADCEngineState
*s
= ASPEED_ADC_ENGINE(opaque
);
111 int reg
= TO_REG(addr
);
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
);
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
);
131 case BOUNDS_CHANNEL_0
... BOUNDS_CHANNEL_7
:
132 case HYSTERESIS_CHANNEL_0
... HYSTERESIS_CHANNEL_7
:
134 case INTERRUPT_CONTROL
:
135 case VGA_DETECT_CONTROL
:
137 case INTERRUPT_SOURCE
:
138 case COMPENSATING_AND_TRIMMING
:
139 value
= s
->regs
[reg
];
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
);
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 */
158 qemu_log_mask(LOG_UNIMP
, "%s: engine[%u]: 0x%" HWADDR_PRIx
"\n",
159 __func__
, s
->engine_id
, addr
);
163 trace_aspeed_adc_engine_read(s
->engine_id
, addr
, value
);
167 static void aspeed_adc_engine_write(void *opaque
, hwaddr addr
, uint64_t value
,
170 AspeedADCEngineState
*s
= ASPEED_ADC_ENGINE(opaque
);
171 int reg
= TO_REG(addr
);
174 trace_aspeed_adc_engine_write(s
->engine_id
, addr
, value
);
178 init
= !!(value
& ASPEED_ADC_ENGINE_EN
);
179 init
*= ASPEED_ADC_ENGINE_INIT
;
181 value
&= ~ASPEED_ADC_ENGINE_INIT
;
184 value
&= ~ASPEED_ADC_ENGINE_AUTO_COMP
;
186 case INTERRUPT_CONTROL
:
187 case VGA_DETECT_CONTROL
:
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
);
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
);
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
;
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
);
218 case HYSTERESIS_CHANNEL_0
... HYSTERESIS_CHANNEL_7
:
219 value
&= (ASPEED_ADC_HYST_EN
| ASPEED_ADC_LH_MASK
);
221 case INTERRUPT_SOURCE
:
224 case COMPENSATING_AND_TRIMMING
:
228 qemu_log_mask(LOG_UNIMP
, "%s: engine[%u]: "
229 "0x%" HWADDR_PRIx
" 0x%" PRIx64
"\n",
230 __func__
, s
->engine_id
, addr
, value
);
234 s
->regs
[reg
] = value
;
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
,
242 .min_access_size
= 2,
243 .max_access_size
= 4,
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,
255 static void aspeed_adc_engine_reset(DeviceState
*dev
)
257 AspeedADCEngineState
*s
= ASPEED_ADC_ENGINE(dev
);
259 memcpy(s
->regs
, aspeed_adc_resets
, sizeof(aspeed_adc_resets
));
262 static void aspeed_adc_engine_realize(DeviceState
*dev
, Error
**errp
)
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",
269 assert(s
->engine_id
< 2);
271 sysbus_init_irq(sbd
, &s
->irq
);
273 memory_region_init_io(&s
->mmio
, OBJECT(s
), &aspeed_adc_engine_ops
, s
, name
,
274 ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE
);
276 sysbus_init_mmio(sbd
, &s
->mmio
);
279 static const VMStateDescription vmstate_aspeed_adc_engine
= {
280 .name
= TYPE_ASPEED_ADC
,
282 .minimum_version_id
= 1,
283 .fields
= (VMStateField
[]) {
284 VMSTATE_UINT32_ARRAY(regs
, AspeedADCEngineState
, ASPEED_ADC_NR_REGS
),
285 VMSTATE_END_OF_LIST(),
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(),
295 static void aspeed_adc_engine_class_init(ObjectClass
*klass
, void *data
)
297 DeviceClass
*dc
= DEVICE_CLASS(klass
);
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
;
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
,
313 static void aspeed_adc_instance_init(Object
*obj
)
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
;
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
);
328 static void aspeed_adc_set_irq(void *opaque
, int n
, int level
)
330 AspeedADCState
*s
= opaque
;
331 AspeedADCClass
*aac
= ASPEED_ADC_GET_CLASS(s
);
332 uint32_t pending
= 0;
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);
340 qemu_set_irq(s
->irq
, !!pending
);
343 static void aspeed_adc_realize(DeviceState
*dev
, Error
**errp
)
345 AspeedADCState
*s
= ASPEED_ADC(dev
);
346 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
347 AspeedADCClass
*aac
= ASPEED_ADC_GET_CLASS(dev
);
349 qdev_init_gpio_in_named_with_opaque(DEVICE(sbd
), aspeed_adc_set_irq
,
350 s
, NULL
, aac
->nr_engines
);
352 sysbus_init_irq(sbd
, &s
->irq
);
354 memory_region_init(&s
->mmio
, OBJECT(s
), TYPE_ASPEED_ADC
,
355 ASPEED_ADC_MEMORY_REGION_SIZE
);
357 sysbus_init_mmio(sbd
, &s
->mmio
);
359 for (int i
= 0; i
< aac
->nr_engines
; i
++) {
360 Object
*eng
= OBJECT(&s
->engines
[i
]);
362 if (!sysbus_realize(SYS_BUS_DEVICE(eng
), errp
)) {
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
);
373 static void aspeed_adc_class_init(ObjectClass
*klass
, void *data
)
375 DeviceClass
*dc
= DEVICE_CLASS(klass
);
376 AspeedADCClass
*aac
= ASPEED_ADC_CLASS(klass
);
378 dc
->realize
= aspeed_adc_realize
;
379 dc
->desc
= "Aspeed Analog-to-Digital Converter";
383 static void aspeed_2600_adc_class_init(ObjectClass
*klass
, void *data
)
385 DeviceClass
*dc
= DEVICE_CLASS(klass
);
386 AspeedADCClass
*aac
= ASPEED_ADC_CLASS(klass
);
388 dc
->desc
= "ASPEED 2600 ADC Controller";
392 static void aspeed_1030_adc_class_init(ObjectClass
*klass
, void *data
)
394 DeviceClass
*dc
= DEVICE_CLASS(klass
);
395 AspeedADCClass
*aac
= ASPEED_ADC_CLASS(klass
);
397 dc
->desc
= "ASPEED 1030 ADC Controller";
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
),
411 static const TypeInfo aspeed_2400_adc_info
= {
412 .name
= TYPE_ASPEED_2400_ADC
,
413 .parent
= TYPE_ASPEED_ADC
,
416 static const TypeInfo aspeed_2500_adc_info
= {
417 .name
= TYPE_ASPEED_2500_ADC
,
418 .parent
= TYPE_ASPEED_ADC
,
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
,
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 */
433 static void aspeed_adc_register_types(void)
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
);
443 type_init(aspeed_adc_register_types
);