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