1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "qemu/log.h"
27#include "hw/sysbus.h"
28#include "hw/stream.h"
29#include "hw/register.h"
30#include "qapi/error.h"
31#include "migration/vmstate.h"
32#include "hw/qdev-properties.h"
33
34#define TYPE_PMC_STREAM_ZERO "xlnx,pmc-stream-zero"
35
36#ifndef PMC_STREAM_ZERO_ERR_DEBUG
37#define PMC_STREAM_ZERO_ERR_DEBUG 0
38#endif
39
40#define DPRINT(fmt, args...) do {\
41 if (PMC_STREAM_ZERO_ERR_DEBUG) {\
42 qemu_log("%s: " fmt, __func__, ## args);\
43 } \
44} while (0);
45
46#define PMC_STREAM_ZERO(obj) \
47 OBJECT_CHECK(PmcStreamZero, (obj), TYPE_PMC_STREAM_ZERO)
48
49REG32(PRAM_ZEROIZE_SIZE, 0x0)
50 FIELD(PRAM_ZEROIZE_SIZE, VALUE, 0, 32)
51
52#define R_MAX (R_PRAM_ZEROIZE_SIZE + 1)
53
54
55#define PZM_BEAT_SIZE 16
56QEMU_BUILD_BUG_ON((PZM_BEAT_SIZE % 4) != 0);
57
58typedef struct PmcStreamZero {
59 SysBusDevice parent_obj;
60
61 MemoryRegion iomem;
62 StreamSink *tx_dev;
63
64 StreamCanPushNotifyFn notify;
65 void *notify_opaque;
66
67 uint32_t data[PZM_BEAT_SIZE / 4];
68 uint32_t regs[R_MAX];
69} PmcStreamZero;
70
71static void pmc_stream_zero_notify(void *opaque)
72{
73 PmcStreamZero *s = PMC_STREAM_ZERO(opaque);
74
75 while (s->regs[R_PRAM_ZEROIZE_SIZE] &&
76 stream_can_push(s->tx_dev, pmc_stream_zero_notify, s)) {
77 if (stream_push(s->tx_dev, (uint8_t *)s->data, PZM_BEAT_SIZE, 0) !=
78 PZM_BEAT_SIZE) {
79 qemu_log("pmc_zero_pump: transfer size < %d\n", PZM_BEAT_SIZE);
80 }
81 s->regs[R_PRAM_ZEROIZE_SIZE] -= 1;
82 }
83}
84
85static void pmc_stream_zero_reset(DeviceState *dev)
86{
87 PmcStreamZero *s = PMC_STREAM_ZERO(dev);
88
89 s->regs[R_PRAM_ZEROIZE_SIZE] = 0;
90}
91
92static void pmc_stream_zero_class_init(ObjectClass *klass, void *data)
93{
94 DeviceClass *dc = DEVICE_CLASS(klass);
95
96 dc->reset = pmc_stream_zero_reset;
97}
98
99static uint64_t pmc_stream_zero_read_reg(void *opaque, hwaddr addr,
100 unsigned size)
101{
102 PmcStreamZero *s = PMC_STREAM_ZERO(opaque);
103 uint32_t ret;
104 if (addr >= (R_MAX * 4)) {
105 qemu_log_mask(LOG_GUEST_ERROR, "%s :decode addr 0x%x invalid",
106 __func__, (unsigned int)addr);
107 return 0;
108 }
109
110 ret = s->regs[addr / 4];
111 DPRINT("addr: 0x%x data:0x%x\n", (uint32_t)addr, (uint32_t)ret);
112 return ret;
113}
114
115static void pmc_stream_zero_write_reg(void *opaque, hwaddr addr,
116 uint64_t data, unsigned size)
117{
118 PmcStreamZero *s = PMC_STREAM_ZERO(opaque);
119
120 if (addr >= (R_MAX * 4)) {
121 qemu_log_mask(LOG_GUEST_ERROR, " %s :decode addr 0x%x invalid",
122 __func__, (unsigned int) addr);
123 return;
124 }
125
126 switch (addr / 4) {
127 case R_PRAM_ZEROIZE_SIZE:
128 s->regs[R_PRAM_ZEROIZE_SIZE] = data;
129 pmc_stream_zero_notify(s);
130 break;
131 default:
132 break;
133 };
134 DPRINT("addr: 0x%x data:0x%x\n", (uint32_t)addr, (uint32_t)data);
135}
136
137
138static const MemoryRegionOps pmc_stream_zero_mem_ops = {
139 .read = pmc_stream_zero_read_reg,
140 .write = pmc_stream_zero_write_reg,
141 .endianness = DEVICE_LITTLE_ENDIAN,
142 .valid = {
143 .min_access_size = 4,
144 .max_access_size = 4,
145 }
146};
147
148static void pmc_stream_zero_init(Object *obj)
149{
150 PmcStreamZero *s = PMC_STREAM_ZERO(obj);
151 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
152 unsigned int i;
153
154 memory_region_init_io(&s->iomem, obj, &pmc_stream_zero_mem_ops, obj,
155 TYPE_PMC_STREAM_ZERO, R_MAX * 4);
156 sysbus_init_mmio(sbd, &s->iomem);
157 object_property_add_link(obj, "stream-connected-pzm", TYPE_STREAM_SINK,
158 (Object **)&s->tx_dev,
159 qdev_prop_allow_set_link_before_realize,
160 OBJ_PROP_LINK_STRONG);
161 for (i = 0; (i * 4) < PZM_BEAT_SIZE; i++) {
162 s->data[i] = 0xDEADBEEF;
163 }
164}
165
166static const TypeInfo pmc_stream_zero_info = {
167 .name = TYPE_PMC_STREAM_ZERO,
168 .parent = TYPE_SYS_BUS_DEVICE,
169 .instance_size = sizeof(PmcStreamZero),
170 .class_init = pmc_stream_zero_class_init,
171 .instance_init = pmc_stream_zero_init,
172 .interfaces = (InterfaceInfo[]) {
173 { TYPE_STREAM_SINK },
174 { }
175 }
176};
177
178static void pmc_stream_zero_register_types(void)
179{
180 type_register_static(&pmc_stream_zero_info);
181}
182
183type_init(pmc_stream_zero_register_types)
184