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
aspeed_pwm_read(void * opaque,hwaddr addr,unsigned int size)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
aspeed_pwm_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)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
aspeed_pwm_reset(DeviceState * dev)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
aspeed_pwm_realize(DeviceState * dev,Error ** errp)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
aspeed_pwm_class_init(ObjectClass * klass,void * data)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 device_class_set_legacy_reset(dc, 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
aspeed_pwm_register_types(void)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