xref: /openbmc/qemu/hw/misc/aspeed_pwm.c (revision ecab2cce)
1 /*
2  * ASPEED PWM Controller
3  *
4  * Copyright (C) 2017-2021 IBM Corp.
5  *
6  * This code is licensed under the GPL version 2 or later.  See
7  * the COPYING file in the top-level directory.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "qemu/log.h"
12 #include "qemu/error-report.h"
13 #include "hw/misc/aspeed_pwm.h"
14 #include "qapi/error.h"
15 #include "migration/vmstate.h"
16 
17 #include "trace.h"
18 
19 static uint64_t aspeed_pwm_read(void *opaque, hwaddr addr,
20                                      unsigned int size)
21 {
22     AspeedPWMState *s = ASPEED_PWM(opaque);
23     uint64_t val = 0;
24 
25     addr >>= 2;
26 
27     if (addr >= ASPEED_PWM_NR_REGS) {
28         qemu_log_mask(LOG_GUEST_ERROR,
29                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
30                       __func__, addr << 2);
31     } else {
32         val = s->regs[addr];
33     }
34 
35     trace_aspeed_pwm_read(addr << 2, val);
36 
37     return val;
38 }
39 
40 static void aspeed_pwm_write(void *opaque, hwaddr addr, uint64_t data,
41                               unsigned int size)
42 {
43     AspeedPWMState *s = ASPEED_PWM(opaque);
44 
45     trace_aspeed_pwm_write(addr, data);
46 
47     addr >>= 2;
48 
49     if (addr >= ASPEED_PWM_NR_REGS) {
50         qemu_log_mask(LOG_GUEST_ERROR,
51                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
52                       __func__, addr << 2);
53         return;
54     }
55 
56     s->regs[addr] = data;
57 }
58 
59 static const MemoryRegionOps aspeed_pwm_ops = {
60     .read = aspeed_pwm_read,
61     .write = aspeed_pwm_write,
62     .endianness = DEVICE_LITTLE_ENDIAN,
63     .valid = {
64         .min_access_size = 1,
65         .max_access_size = 4,
66     },
67 };
68 
69 static void aspeed_pwm_reset(DeviceState *dev)
70 {
71     struct AspeedPWMState *s = ASPEED_PWM(dev);
72 
73     memset(s->regs, 0, sizeof(s->regs));
74 }
75 
76 static void aspeed_pwm_realize(DeviceState *dev, Error **errp)
77 {
78     AspeedPWMState *s = ASPEED_PWM(dev);
79     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
80 
81     sysbus_init_irq(sbd, &s->irq);
82 
83     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_pwm_ops, s,
84             TYPE_ASPEED_PWM, 0x1000);
85 
86     sysbus_init_mmio(sbd, &s->iomem);
87 }
88 
89 static const VMStateDescription vmstate_aspeed_pwm = {
90     .name = TYPE_ASPEED_PWM,
91     .version_id = 1,
92     .minimum_version_id = 1,
93     .fields = (VMStateField[]) {
94         VMSTATE_UINT32_ARRAY(regs, AspeedPWMState, ASPEED_PWM_NR_REGS),
95         VMSTATE_END_OF_LIST(),
96     }
97 };
98 
99 static void aspeed_pwm_class_init(ObjectClass *klass, void *data)
100 {
101     DeviceClass *dc = DEVICE_CLASS(klass);
102 
103     dc->realize = aspeed_pwm_realize;
104     dc->reset = aspeed_pwm_reset;
105     dc->desc = "Aspeed PWM Controller";
106     dc->vmsd = &vmstate_aspeed_pwm;
107 }
108 
109 static const TypeInfo aspeed_pwm_info = {
110     .name = TYPE_ASPEED_PWM,
111     .parent = TYPE_SYS_BUS_DEVICE,
112     .instance_size = sizeof(AspeedPWMState),
113     .class_init = aspeed_pwm_class_init,
114 };
115 
116 static void aspeed_pwm_register_types(void)
117 {
118     type_register_static(&aspeed_pwm_info);
119 }
120 
121 type_init(aspeed_pwm_register_types);
122