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
26
27#include "qemu/osdep.h"
28#include "hw/hw.h"
29#include "hw/block/flash.h"
30#include "qapi/error.h"
31#include "qemu/timer.h"
32#include "sysemu/block-backend.h"
33#include "exec/address-spaces.h"
34#include "qemu/host-utils.h"
35#include "hw/sysbus.h"
36
37#ifdef PL35X_ERR_DEBUG
38#define DB_PRINT(...) do { \
39 fprintf(stderr, ": %s: ", __func__); \
40 fprintf(stderr, ## __VA_ARGS__); \
41 } while (0);
42#else
43 #define DB_PRINT(...)
44#endif
45
46#define TYPE_PL35X "arm.pl35x"
47
48#define PL35X(obj) \
49 OBJECT_CHECK(PL35xState, (obj), TYPE_PL35X)
50
51typedef struct PL35xItf {
52 MemoryRegion mm;
53 DeviceState *dev;
54 uint8_t nand_pending_addr_cycles;
55} PL35xItf;
56
57typedef struct PL35xState {
58 SysBusDevice parent_obj;
59
60 MemoryRegion mmio;
61
62
63
64 PL35xItf itf[2];
65
66
67
68
69
70 uint8_t x;
71} PL35xState;
72
73static uint64_t pl35x_read(void *opaque, hwaddr addr,
74 unsigned int size)
75{
76 PL35xState *s = opaque;
77 uint32_t r = 0;
78 int rdy;
79
80 addr >>= 2;
81 switch (addr) {
82 case 0x0:
83 if (s->itf[0].dev && object_dynamic_cast(OBJECT(s->itf[0].dev),
84 "nand")) {
85 nand_getpins(s->itf[0].dev, &rdy);
86 r |= (!!rdy) << 5;
87 }
88 if (s->itf[1].dev && object_dynamic_cast(OBJECT(s->itf[1].dev),
89 "nand")) {
90 nand_getpins(s->itf[1].dev, &rdy);
91 r |= (!!rdy) << 6;
92 }
93 break;
94 default:
95 DB_PRINT("Unimplemented SMC read access reg=" TARGET_FMT_plx "\n",
96 addr * 4);
97 break;
98 }
99 return r;
100}
101
102static void pl35x_write(void *opaque, hwaddr addr, uint64_t value64,
103 unsigned int size)
104{
105 DB_PRINT("addr=%x v=%x\n", (unsigned)addr, (unsigned)value64);
106 addr >>= 2;
107
108 DB_PRINT("Unimplemented SMC write access reg=" TARGET_FMT_plx "\n",
109 addr * 4);
110}
111
112static const MemoryRegionOps pl35x_ops = {
113 .read = pl35x_read,
114 .write = pl35x_write,
115 .endianness = DEVICE_NATIVE_ENDIAN,
116 .valid = {
117 .min_access_size = 4,
118 .max_access_size = 4
119 }
120};
121
122static uint64_t nand_read(void *opaque, hwaddr addr,
123 unsigned int size)
124{
125 PL35xItf *s = opaque;
126 unsigned int len = size;
127 int shift = 0;
128 uint32_t r = 0;
129
130 while (len--) {
131 uint8_t r8;
132
133 r8 = nand_getio(s->dev) & 0xff;
134 r |= r8 << shift;
135 shift += 8;
136 }
137 DB_PRINT("addr=%x r=%x size=%d\n", (unsigned)addr, r, size);
138 return r;
139}
140
141static void nand_write(void *opaque, hwaddr addr, uint64_t value64,
142 unsigned int size)
143{
144 struct PL35xItf *s = opaque;
145 bool data_phase, ecmd_valid;
146 unsigned int addr_cycles = 0;
147 uint16_t start_cmd, end_cmd;
148 uint32_t value = value64;
149 uint32_t nandaddr = value;
150
151 DB_PRINT("addr=%x v=%x size=%d\n", (unsigned)addr, (unsigned)value, size);
152
153
154 data_phase = (addr >> 19) & 1;
155 ecmd_valid = (addr >> 20) & 1;
156 start_cmd = (addr >> 3) & 0xff;
157 end_cmd = (addr >> 11) & 0xff;
158 if (!data_phase) {
159 addr_cycles = (addr >> 21) & 7;
160 }
161
162 if (!data_phase) {
163 DB_PRINT("start_cmd=%x end_cmd=%x (valid=%d) acycl=%d\n",
164 start_cmd, end_cmd, ecmd_valid, addr_cycles);
165 }
166
167
168 if (data_phase) {
169 nand_setpins(s->dev, 0, 0, 0, 1, 0);
170 while (size--) {
171 nand_setio(s->dev, value & 0xff);
172 value >>= 8;
173 }
174 }
175
176
177 if (!data_phase && !s->nand_pending_addr_cycles) {
178 nand_setpins(s->dev, 1, 0, 0, 1, 0);
179 nand_setio(s->dev, start_cmd);
180 }
181
182 if (!addr_cycles) {
183 s->nand_pending_addr_cycles = 0;
184 }
185 if (s->nand_pending_addr_cycles) {
186 addr_cycles = s->nand_pending_addr_cycles;
187 s->nand_pending_addr_cycles = 0;
188 }
189 if (addr_cycles > 4) {
190 s->nand_pending_addr_cycles = addr_cycles - 4;
191 addr_cycles = 4;
192 }
193 while (addr_cycles) {
194 nand_setpins(s->dev, 0, 1, 0, 1, 0);
195 DB_PRINT("nand cycl=%d addr=%x\n", addr_cycles, nandaddr & 0xff);
196 nand_setio(s->dev, nandaddr & 0xff);
197 nandaddr >>= 8;
198 addr_cycles--;
199 }
200
201
202 if (ecmd_valid && !s->nand_pending_addr_cycles) {
203 nand_setpins(s->dev, 1, 0, 0, 1, 0);
204 nand_setio(s->dev, end_cmd);
205 }
206}
207
208static const MemoryRegionOps nand_ops = {
209 .read = nand_read,
210 .write = nand_write,
211 .endianness = DEVICE_NATIVE_ENDIAN,
212 .valid = {
213 .min_access_size = 1,
214 .max_access_size = 4
215 }
216};
217
218static void pl35x_init_sram(SysBusDevice *dev, PL35xItf *itf)
219{
220
221
222
223 SysBusDevice *sbd = SYS_BUS_DEVICE(itf->dev);
224
225 memory_region_init(&itf->mm, OBJECT(dev), "pl35x.sram", 1 << 24);
226 if (sbd) {
227 memory_region_add_subregion(&itf->mm, 0,
228 sysbus_mmio_get_region(sbd, 0));
229 }
230 sysbus_init_mmio(dev, &itf->mm);
231}
232
233static void pl35x_init_nand(SysBusDevice *dev, PL35xItf *itf)
234{
235
236 assert(object_dynamic_cast(OBJECT(itf->dev), "nand"));
237
238 memory_region_init_io(&itf->mm, OBJECT(dev), &nand_ops, itf, "pl35x.nand",
239 1 << 24);
240 sysbus_init_mmio(dev, &itf->mm);
241}
242
243static int pl35x_init(SysBusDevice *dev)
244{
245 PL35xState *s = PL35X(dev);
246 int itfn = 0;
247
248 memory_region_init_io(&s->mmio, OBJECT(dev), &pl35x_ops, s, "pl35x_io",
249 0x1000);
250 sysbus_init_mmio(dev, &s->mmio);
251 if (s->x != 1) {
252 pl35x_init_sram(dev, &s->itf[itfn]);
253 itfn++;
254 }
255 if (s->x & 0x1) {
256 pl35x_init_nand(dev, &s->itf[itfn]);
257 } else if (s->x == 4) {
258 pl35x_init_sram(dev, &s->itf[itfn]);
259 }
260 return 0;
261}
262static void pl35x_initfn(Object *obj)
263{
264 PL35xState *s = PL35X(obj);
265
266 object_property_add_link(obj, "dev0", TYPE_DEVICE,
267 (Object **)&s->itf[0].dev,
268 object_property_allow_set_link,
269 OBJ_PROP_LINK_UNREF_ON_RELEASE,
270 &error_abort);
271 object_property_add_link(obj, "dev1", TYPE_DEVICE,
272 (Object **)&s->itf[1].dev,
273 object_property_allow_set_link,
274 OBJ_PROP_LINK_UNREF_ON_RELEASE,
275 &error_abort);
276}
277
278static Property pl35x_properties[] = {
279 DEFINE_PROP_UINT8("x", PL35xState, x, 3),
280 DEFINE_PROP_END_OF_LIST(),
281};
282
283static const VMStateDescription vmstate_pl35x = {
284 .name = "pl35x",
285 .version_id = 1,
286 .minimum_version_id = 1,
287 .fields = (VMStateField[]) {
288 VMSTATE_UINT8(itf[0].nand_pending_addr_cycles, PL35xState),
289 VMSTATE_UINT8(itf[1].nand_pending_addr_cycles, PL35xState),
290 VMSTATE_END_OF_LIST()
291 }
292};
293
294static void pl35x_class_init(ObjectClass *klass, void *data)
295{
296 DeviceClass *dc = DEVICE_CLASS(klass);
297 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
298
299 k->init = pl35x_init;
300 dc->props = pl35x_properties;
301 dc->vmsd = &vmstate_pl35x;
302}
303
304static TypeInfo pl35x_info = {
305 .name = TYPE_PL35X,
306 .parent = TYPE_SYS_BUS_DEVICE,
307 .instance_size = sizeof(PL35xState),
308 .class_init = pl35x_class_init,
309 .instance_init = pl35x_initfn,
310};
311
312static void pl35x_register_types(void)
313{
314 type_register_static(&pl35x_info);
315}
316
317type_init(pl35x_register_types)
318