1 /* 2 * Aspeed ADC 3 * 4 * Andrew Jeffery <andrew@aj.id.au> 5 * 6 * Copyright 2017 IBM Corp. 7 * 8 * This code is licensed under the GPL version 2 or later. See 9 * the COPYING file in the top-level directory. 10 */ 11 12 #include "qemu/osdep.h" 13 #include "hw/adc/aspeed_adc.h" 14 #include "qapi/error.h" 15 #include "qemu/log.h" 16 17 #define ASPEED_ADC_ENGINE_CTRL 0x00 18 #define ASPEED_ADC_ENGINE_CH_EN_MASK 0xffff0000 19 #define ASPEED_ADC_ENGINE_CH_EN(x) ((BIT(x)) << 16) 20 #define ASPEED_ADC_ENGINE_INIT BIT(8) 21 #define ASPEED_ADC_ENGINE_AUTO_COMP BIT(5) 22 #define ASPEED_ADC_ENGINE_COMP BIT(4) 23 #define ASPEED_ADC_ENGINE_MODE_MASK 0x0000000e 24 #define ASPEED_ADC_ENGINE_MODE_OFF (0b000 << 1) 25 #define ASPEED_ADC_ENGINE_MODE_STANDBY (0b001 << 1) 26 #define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) 27 #define ASPEED_ADC_ENGINE_EN BIT(0) 28 #define ASPEED_ADC_HYST_EN BIT(31) 29 30 #define ASPEED_ADC_L_MASK ((1 << 10) - 1) 31 #define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) 32 #define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) 33 #define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK) 34 35 static inline uint32_t update_channels(uint32_t current) 36 { 37 return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) | 38 ((current + 5) & ASPEED_ADC_L_MASK); 39 } 40 41 static bool breaks_threshold(AspeedADCState *s, int ch_off) 42 { 43 const uint32_t a = ASPEED_ADC_L(s->channels[ch_off]); 44 const uint32_t a_lower = ASPEED_ADC_L(s->bounds[2 * ch_off]); 45 const uint32_t a_upper = ASPEED_ADC_H(s->bounds[2 * ch_off]); 46 const uint32_t b = ASPEED_ADC_H(s->channels[ch_off]); 47 const uint32_t b_lower = ASPEED_ADC_L(s->bounds[2 * ch_off + 1]); 48 const uint32_t b_upper = ASPEED_ADC_H(s->bounds[2 * ch_off + 1]); 49 50 return ((a < a_lower || a > a_upper)) || 51 ((b < b_lower || b > b_upper)); 52 } 53 54 static uint32_t read_channel_sample(AspeedADCState *s, int ch_off) 55 { 56 uint32_t ret; 57 58 /* Poor man's sampling */ 59 ret = s->channels[ch_off]; 60 s->channels[ch_off] = update_channels(s->channels[ch_off]); 61 62 if (breaks_threshold(s, ch_off)) { 63 qemu_irq_raise(s->irq); 64 } 65 66 return ret; 67 } 68 69 #define TO_INDEX(addr, base) (((addr) - (base)) >> 2) 70 71 static uint64_t aspeed_adc_read(void *opaque, hwaddr addr, 72 unsigned int size) 73 { 74 AspeedADCState *s = ASPEED_ADC(opaque); 75 uint64_t ret; 76 77 switch (addr) { 78 case 0x00: 79 ret = s->engine_ctrl; 80 break; 81 case 0x04: 82 ret = s->irq_ctrl; 83 break; 84 case 0x08: 85 ret = s->vga_detect_ctrl; 86 break; 87 case 0x0c: 88 ret = s->adc_clk_ctrl; 89 break; 90 case 0x10 ... 0x2e: 91 ret = read_channel_sample(s, TO_INDEX(addr, 0x10)); 92 break; 93 case 0x30 ... 0x6e: 94 ret = s->bounds[TO_INDEX(addr, 0x30)]; 95 break; 96 case 0x70 ... 0xae: 97 ret = s->hysteresis[TO_INDEX(addr, 0x70)]; 98 break; 99 case 0xc0: 100 ret = s->irq_src; 101 break; 102 case 0xc4: 103 ret = s->comp_trim; 104 break; 105 default: 106 qemu_log_mask(LOG_UNIMP, "%s: addr: 0x%" HWADDR_PRIx ", size: %u\n", 107 __func__, addr, size); 108 ret = 0; 109 break; 110 } 111 112 return ret; 113 } 114 115 static void aspeed_adc_write(void *opaque, hwaddr addr, uint64_t val, 116 unsigned int size) 117 { 118 AspeedADCState *s = ASPEED_ADC(opaque); 119 120 switch (addr) { 121 case 0x00: 122 { 123 uint32_t init; 124 125 init = !!(val & ASPEED_ADC_ENGINE_EN); 126 init *= ASPEED_ADC_ENGINE_INIT; 127 128 val &= ~ASPEED_ADC_ENGINE_INIT; 129 val |= init; 130 } 131 132 val &= ~ASPEED_ADC_ENGINE_AUTO_COMP; 133 s->engine_ctrl = val; 134 135 break; 136 case 0x04: 137 s->irq_ctrl = val; 138 break; 139 case 0x08: 140 s->vga_detect_ctrl = val; 141 break; 142 case 0x0c: 143 s->adc_clk_ctrl = val; 144 break; 145 case 0x10 ... 0x2e: 146 s->channels[TO_INDEX(addr, 0x10)] = (val & ASPEED_ADC_LH_MASK); 147 break; 148 case 0x30 ... 0x6e: 149 s->bounds[TO_INDEX(addr, 0x30)] = (val & ASPEED_ADC_LH_MASK); 150 break; 151 case 0x70 ... 0xae: 152 s->hysteresis[TO_INDEX(addr, 0x70)] = 153 (val & (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK)); 154 break; 155 case 0xc0: 156 s->irq_src = (val & 0xffff); 157 break; 158 case 0xc4: 159 s->comp_trim = (val & 0xf); 160 break; 161 default: 162 qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr); 163 break; 164 } 165 } 166 167 static const MemoryRegionOps aspeed_adc_ops = { 168 .read = aspeed_adc_read, 169 .write = aspeed_adc_write, 170 .endianness = DEVICE_LITTLE_ENDIAN, 171 .valid.min_access_size = 1, 172 .valid.max_access_size = 4, 173 .valid.unaligned = false, 174 .impl.min_access_size = 4, 175 .impl.max_access_size = 4, 176 .impl.unaligned = false, 177 }; 178 179 static void aspeed_adc_reset(DeviceState *dev) 180 { 181 struct AspeedADCState *s = ASPEED_ADC(dev); 182 183 s->engine_ctrl = 0; 184 s->irq_ctrl = 0; 185 s->vga_detect_ctrl = 0x0000000f; 186 s->adc_clk_ctrl = 0x0000000f; 187 memset(s->channels, 0, sizeof(s->channels)); 188 memset(s->bounds, 0, sizeof(s->bounds)); 189 memset(s->hysteresis, 0, sizeof(s->hysteresis)); 190 s->irq_src = 0; 191 s->comp_trim = 0; 192 } 193 194 static void aspeed_adc_realize(DeviceState *dev, Error **errp) 195 { 196 AspeedADCState *s = ASPEED_ADC(dev); 197 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 198 199 sysbus_init_irq(sbd, &s->irq); 200 201 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_ops, s, 202 TYPE_ASPEED_ADC, 0x1000); 203 204 sysbus_init_mmio(sbd, &s->mmio); 205 } 206 207 static const VMStateDescription vmstate_aspeed_adc = { 208 .name = TYPE_ASPEED_ADC, 209 .version_id = 1, 210 .minimum_version_id = 1, 211 .fields = (VMStateField[]) { 212 VMSTATE_UINT32(engine_ctrl, AspeedADCState), 213 VMSTATE_UINT32(irq_ctrl, AspeedADCState), 214 VMSTATE_UINT32(vga_detect_ctrl, AspeedADCState), 215 VMSTATE_UINT32(adc_clk_ctrl, AspeedADCState), 216 VMSTATE_UINT32_ARRAY(channels, AspeedADCState, 217 ASPEED_ADC_NR_CHANNELS / 2), 218 VMSTATE_UINT32_ARRAY(bounds, AspeedADCState, ASPEED_ADC_NR_CHANNELS), 219 VMSTATE_UINT32_ARRAY(hysteresis, AspeedADCState, 220 ASPEED_ADC_NR_CHANNELS), 221 VMSTATE_UINT32(irq_src, AspeedADCState), 222 VMSTATE_UINT32(comp_trim, AspeedADCState), 223 VMSTATE_END_OF_LIST(), 224 } 225 }; 226 227 static void aspeed_adc_class_init(ObjectClass *klass, void *data) 228 { 229 DeviceClass *dc = DEVICE_CLASS(klass); 230 231 dc->realize = aspeed_adc_realize; 232 dc->reset = aspeed_adc_reset; 233 dc->desc = "Aspeed Analog-to-Digital Converter", 234 dc->vmsd = &vmstate_aspeed_adc; 235 } 236 237 static const TypeInfo aspeed_adc_info = { 238 .name = TYPE_ASPEED_ADC, 239 .parent = TYPE_SYS_BUS_DEVICE, 240 .instance_size = sizeof(AspeedADCState), 241 .class_init = aspeed_adc_class_init, 242 }; 243 244 static void aspeed_adc_register_types(void) 245 { 246 type_register_static(&aspeed_adc_info); 247 } 248 249 type_init(aspeed_adc_register_types); 250