xref: /openbmc/qemu/hw/adc/aspeed_adc.c (revision 859524ee)
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