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_ENGINE_CTRL 0x00 21 #define ASPEED_ADC_ENGINE_CH_EN_MASK 0xffff0000 22 #define ASPEED_ADC_ENGINE_CH_EN(x) ((BIT(x)) << 16) 23 #define ASPEED_ADC_ENGINE_INIT BIT(8) 24 #define ASPEED_ADC_ENGINE_AUTO_COMP BIT(5) 25 #define ASPEED_ADC_ENGINE_COMP BIT(4) 26 #define ASPEED_ADC_ENGINE_MODE_MASK 0x0000000e 27 #define ASPEED_ADC_ENGINE_MODE_OFF (0b000 << 1) 28 #define ASPEED_ADC_ENGINE_MODE_STANDBY (0b001 << 1) 29 #define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) 30 #define ASPEED_ADC_ENGINE_EN BIT(0) 31 #define ASPEED_ADC_HYST_EN BIT(31) 32 33 #define ASPEED_ADC_L_MASK ((1 << 10) - 1) 34 #define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) 35 #define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) 36 #define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK) 37 38 static inline uint32_t update_channels(uint32_t current) 39 { 40 return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) | 41 ((current + 5) & ASPEED_ADC_L_MASK); 42 } 43 44 static bool breaks_threshold(AspeedADCEngineState *s, int ch_off) 45 { 46 const uint32_t a = ASPEED_ADC_L(s->channels[ch_off]); 47 const uint32_t a_lower = ASPEED_ADC_L(s->bounds[2 * ch_off]); 48 const uint32_t a_upper = ASPEED_ADC_H(s->bounds[2 * ch_off]); 49 const uint32_t b = ASPEED_ADC_H(s->channels[ch_off]); 50 const uint32_t b_lower = ASPEED_ADC_L(s->bounds[2 * ch_off + 1]); 51 const uint32_t b_upper = ASPEED_ADC_H(s->bounds[2 * ch_off + 1]); 52 53 return ((a < a_lower || a > a_upper)) || 54 ((b < b_lower || b > b_upper)); 55 } 56 57 static uint32_t read_channel_sample(AspeedADCEngineState *s, int ch_off) 58 { 59 uint32_t ret; 60 61 /* Poor man's sampling */ 62 ret = s->channels[ch_off]; 63 s->channels[ch_off] = update_channels(s->channels[ch_off]); 64 65 if (breaks_threshold(s, ch_off)) { 66 s->irq_ctrl |= BIT(ch_off); 67 qemu_irq_raise(s->irq); 68 } 69 70 return ret; 71 } 72 73 #define TO_INDEX(addr, base) (((addr) - (base)) >> 2) 74 75 static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr, 76 unsigned int size) 77 { 78 AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque); 79 uint64_t ret; 80 81 switch (addr) { 82 case 0x00: 83 ret = s->engine_ctrl; 84 break; 85 case 0x04: 86 ret = s->irq_ctrl; 87 break; 88 case 0x08: 89 ret = s->vga_detect_ctrl; 90 break; 91 case 0x0c: 92 ret = s->adc_clk_ctrl; 93 break; 94 case 0x10 ... 0x2e: 95 ret = read_channel_sample(s, TO_INDEX(addr, 0x10)); 96 break; 97 case 0x30 ... 0x6e: 98 ret = s->bounds[TO_INDEX(addr, 0x30)]; 99 break; 100 case 0x70 ... 0xae: 101 ret = s->hysteresis[TO_INDEX(addr, 0x70)]; 102 break; 103 case 0xc0: 104 ret = s->irq_src; 105 break; 106 case 0xc4: 107 ret = s->comp_trim; 108 break; 109 default: 110 qemu_log_mask(LOG_UNIMP, "%s: addr: 0x%" HWADDR_PRIx ", size: %u\n", 111 __func__, addr, size); 112 ret = 0; 113 break; 114 } 115 116 trace_aspeed_adc_engine_read(s->engine_id, addr, size, ret); 117 118 return ret; 119 } 120 121 static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t val, 122 unsigned int size) 123 { 124 AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque); 125 uint32_t init; 126 127 trace_aspeed_adc_engine_write(s->engine_id, addr, size, val); 128 129 switch (addr) { 130 case 0x00: 131 init = !!(val & ASPEED_ADC_ENGINE_EN); 132 init *= ASPEED_ADC_ENGINE_INIT; 133 134 val &= ~ASPEED_ADC_ENGINE_INIT; 135 val |= init; 136 137 val &= ~ASPEED_ADC_ENGINE_AUTO_COMP; 138 s->engine_ctrl = val; 139 break; 140 case 0x04: 141 s->irq_ctrl = val; 142 break; 143 case 0x08: 144 s->vga_detect_ctrl = val; 145 break; 146 case 0x0c: 147 s->adc_clk_ctrl = val; 148 break; 149 case 0x10 ... 0x2e: 150 s->channels[TO_INDEX(addr, 0x10)] = (val & ASPEED_ADC_LH_MASK); 151 break; 152 case 0x30 ... 0x6e: 153 s->bounds[TO_INDEX(addr, 0x30)] = (val & ASPEED_ADC_LH_MASK); 154 break; 155 case 0x70 ... 0xae: 156 s->hysteresis[TO_INDEX(addr, 0x70)] = 157 (val & (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK)); 158 break; 159 case 0xc0: 160 s->irq_src = (val & 0xffff); 161 break; 162 case 0xc4: 163 s->comp_trim = (val & 0xf); 164 break; 165 default: 166 qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr); 167 break; 168 } 169 } 170 171 static const MemoryRegionOps aspeed_adc_engine_ops = { 172 .read = aspeed_adc_engine_read, 173 .write = aspeed_adc_engine_write, 174 .endianness = DEVICE_LITTLE_ENDIAN, 175 .valid = { 176 .min_access_size = 1, 177 .max_access_size = 4, 178 }, 179 }; 180 181 static void aspeed_adc_engine_reset(DeviceState *dev) 182 { 183 struct AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev); 184 185 s->engine_ctrl = 0; 186 s->irq_ctrl = 0; 187 s->vga_detect_ctrl = 0x0000000f; 188 s->adc_clk_ctrl = 0x0000000f; 189 memset(s->channels, 0, sizeof(s->channels)); 190 memset(s->bounds, 0, sizeof(s->bounds)); 191 memset(s->hysteresis, 0, sizeof(s->hysteresis)); 192 s->irq_src = 0; 193 s->comp_trim = 0; 194 } 195 196 static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp) 197 { 198 AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev); 199 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 200 g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d", 201 s->engine_id); 202 203 assert(s->engine_id < 2); 204 205 sysbus_init_irq(sbd, &s->irq); 206 207 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name, 208 0x100); 209 210 sysbus_init_mmio(sbd, &s->mmio); 211 } 212 213 static const VMStateDescription vmstate_aspeed_adc_engine = { 214 .name = TYPE_ASPEED_ADC, 215 .version_id = 1, 216 .minimum_version_id = 1, 217 .fields = (VMStateField[]) { 218 VMSTATE_UINT32(engine_ctrl, AspeedADCEngineState), 219 VMSTATE_UINT32(irq_ctrl, AspeedADCEngineState), 220 VMSTATE_UINT32(vga_detect_ctrl, AspeedADCEngineState), 221 VMSTATE_UINT32(adc_clk_ctrl, AspeedADCEngineState), 222 VMSTATE_UINT32_ARRAY(channels, AspeedADCEngineState, 223 ASPEED_ADC_NR_CHANNELS / 2), 224 VMSTATE_UINT32_ARRAY(bounds, AspeedADCEngineState, 225 ASPEED_ADC_NR_CHANNELS), 226 VMSTATE_UINT32_ARRAY(hysteresis, AspeedADCEngineState, 227 ASPEED_ADC_NR_CHANNELS), 228 VMSTATE_UINT32(irq_src, AspeedADCEngineState), 229 VMSTATE_UINT32(comp_trim, AspeedADCEngineState), 230 VMSTATE_END_OF_LIST(), 231 } 232 }; 233 234 static Property aspeed_adc_engine_properties[] = { 235 DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0), 236 DEFINE_PROP_END_OF_LIST(), 237 }; 238 239 static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data) 240 { 241 DeviceClass *dc = DEVICE_CLASS(klass); 242 243 dc->realize = aspeed_adc_engine_realize; 244 dc->reset = aspeed_adc_engine_reset; 245 device_class_set_props(dc, aspeed_adc_engine_properties); 246 dc->desc = "Aspeed Analog-to-Digital Engine"; 247 dc->vmsd = &vmstate_aspeed_adc_engine; 248 } 249 250 static const TypeInfo aspeed_adc_engine_info = { 251 .name = TYPE_ASPEED_ADC_ENGINE, 252 .parent = TYPE_SYS_BUS_DEVICE, 253 .instance_size = sizeof(AspeedADCEngineState), 254 .class_init = aspeed_adc_engine_class_init, 255 }; 256 257 static void aspeed_adc_instance_init(Object *obj) 258 { 259 AspeedADCState *s = ASPEED_ADC(obj); 260 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj); 261 int i; 262 263 for (i = 0; i < aac->nr_engines; i++) { 264 object_initialize_child(obj, "engine[*]", &s->engines[i], 265 TYPE_ASPEED_ADC_ENGINE); 266 } 267 } 268 269 static void aspeed_adc_set_irq(void *opaque, int n, int level) 270 { 271 AspeedADCState *s = opaque; 272 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s); 273 uint32_t pending = 0; 274 int i; 275 276 /* TODO: update Global IRQ status register on AST2600 (Need specs) */ 277 for (i = 0; i < aac->nr_engines; i++) { 278 uint32_t irq_status = s->engines[i].irq_ctrl & 0xFF; 279 pending |= irq_status << (i * 8); 280 } 281 282 qemu_set_irq(s->irq, !!pending); 283 } 284 285 static void aspeed_adc_realize(DeviceState *dev, Error **errp) 286 { 287 AspeedADCState *s = ASPEED_ADC(dev); 288 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 289 AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev); 290 int i; 291 292 qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq, 293 s, NULL, aac->nr_engines); 294 295 sysbus_init_irq(sbd, &s->irq); 296 297 memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC, 0x1000); 298 299 sysbus_init_mmio(sbd, &s->mmio); 300 301 for (i = 0; i < aac->nr_engines; i++) { 302 Object *eng = OBJECT(&s->engines[i]); 303 304 if (!object_property_set_uint(eng, "engine-id", i, errp)) { 305 return; 306 } 307 if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) { 308 return; 309 } 310 sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0, 311 qdev_get_gpio_in(DEVICE(sbd), i)); 312 memory_region_add_subregion(&s->mmio, i * 0x100, &s->engines[i].mmio); 313 } 314 } 315 316 static void aspeed_adc_class_init(ObjectClass *klass, void *data) 317 { 318 DeviceClass *dc = DEVICE_CLASS(klass); 319 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); 320 321 dc->realize = aspeed_adc_realize; 322 dc->desc = "Aspeed Analog-to-Digital Converter"; 323 aac->nr_engines = 1; 324 } 325 326 static const TypeInfo aspeed_adc_info = { 327 .name = TYPE_ASPEED_ADC, 328 .parent = TYPE_SYS_BUS_DEVICE, 329 .instance_init = aspeed_adc_instance_init, 330 .instance_size = sizeof(AspeedADCState), 331 .class_init = aspeed_adc_class_init, 332 .class_size = sizeof(AspeedADCClass), 333 .abstract = true, 334 }; 335 336 static const TypeInfo aspeed_2400_adc_info = { 337 .name = TYPE_ASPEED_2400_ADC, 338 .parent = TYPE_ASPEED_ADC, 339 }; 340 341 static const TypeInfo aspeed_2500_adc_info = { 342 .name = TYPE_ASPEED_2500_ADC, 343 .parent = TYPE_ASPEED_ADC, 344 }; 345 346 static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data) 347 { 348 DeviceClass *dc = DEVICE_CLASS(klass); 349 AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); 350 351 dc->desc = "ASPEED 2600 ADC Controller"; 352 aac->nr_engines = 2; 353 } 354 355 static const TypeInfo aspeed_2600_adc_info = { 356 .name = TYPE_ASPEED_2600_ADC, 357 .parent = TYPE_ASPEED_ADC, 358 .class_init = aspeed_2600_adc_class_init, 359 }; 360 361 static void aspeed_adc_register_types(void) 362 { 363 type_register_static(&aspeed_adc_engine_info); 364 type_register_static(&aspeed_adc_info); 365 type_register_static(&aspeed_2400_adc_info); 366 type_register_static(&aspeed_2500_adc_info); 367 type_register_static(&aspeed_2600_adc_info); 368 } 369 370 type_init(aspeed_adc_register_types); 371