aspeed_adc.c (14406B)
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 63static 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 69static 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 90static 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 107static 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 167static 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 237static 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 248static 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 255static 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 262static 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 279static 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 289static 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 295static 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 306static 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 313static 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 328static 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 343static 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 373static 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 383static 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 392static 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 402static const TypeInfo aspeed_2400_adc_info = { 403 .name = TYPE_ASPEED_2400_ADC, 404 .parent = TYPE_ASPEED_ADC, 405}; 406 407static const TypeInfo aspeed_2500_adc_info = { 408 .name = TYPE_ASPEED_2500_ADC, 409 .parent = TYPE_ASPEED_ADC, 410}; 411 412static 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 418static 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 427type_init(aspeed_adc_register_types);