]> git.proxmox.com Git - mirror_qemu.git/blob - hw/sd/milkymist-memcard.c
Include hw/qdev-properties.h less
[mirror_qemu.git] / hw / sd / milkymist-memcard.c
1 /*
2 * QEMU model of the Milkymist SD Card Controller.
3 *
4 * Copyright (c) 2010 Michael Walle <michael@walle.cc>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 * Specification available at:
21 * http://milkymist.walle.cc/socdoc/memcard.pdf
22 */
23
24 #include "qemu/osdep.h"
25 #include "qemu/log.h"
26 #include "qemu/module.h"
27 #include "hw/sysbus.h"
28 #include "migration/vmstate.h"
29 #include "sysemu/sysemu.h"
30 #include "trace.h"
31 #include "qapi/error.h"
32 #include "sysemu/block-backend.h"
33 #include "sysemu/blockdev.h"
34 #include "hw/qdev-properties.h"
35 #include "hw/sd/sd.h"
36
37 enum {
38 ENABLE_CMD_TX = (1<<0),
39 ENABLE_CMD_RX = (1<<1),
40 ENABLE_DAT_TX = (1<<2),
41 ENABLE_DAT_RX = (1<<3),
42 };
43
44 enum {
45 PENDING_CMD_TX = (1<<0),
46 PENDING_CMD_RX = (1<<1),
47 PENDING_DAT_TX = (1<<2),
48 PENDING_DAT_RX = (1<<3),
49 };
50
51 enum {
52 START_CMD_TX = (1<<0),
53 START_DAT_RX = (1<<1),
54 };
55
56 enum {
57 R_CLK2XDIV = 0,
58 R_ENABLE,
59 R_PENDING,
60 R_START,
61 R_CMD,
62 R_DAT,
63 R_MAX
64 };
65
66 #define TYPE_MILKYMIST_MEMCARD "milkymist-memcard"
67 #define MILKYMIST_MEMCARD(obj) \
68 OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD)
69
70 struct MilkymistMemcardState {
71 SysBusDevice parent_obj;
72
73 MemoryRegion regs_region;
74 SDBus sdbus;
75
76 int command_write_ptr;
77 int response_read_ptr;
78 int response_len;
79 int ignore_next_cmd;
80 int enabled;
81 uint8_t command[6];
82 uint8_t response[17];
83 uint32_t regs[R_MAX];
84 };
85 typedef struct MilkymistMemcardState MilkymistMemcardState;
86
87 static void update_pending_bits(MilkymistMemcardState *s)
88 {
89 /* transmits are instantaneous, thus tx pending bits are never set */
90 s->regs[R_PENDING] = 0;
91 /* if rx is enabled the corresponding pending bits are always set */
92 if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
93 s->regs[R_PENDING] |= PENDING_CMD_RX;
94 }
95 if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
96 s->regs[R_PENDING] |= PENDING_DAT_RX;
97 }
98 }
99
100 static void memcard_sd_command(MilkymistMemcardState *s)
101 {
102 SDRequest req;
103
104 req.cmd = s->command[0] & 0x3f;
105 req.arg = ldl_be_p(s->command + 1);
106 req.crc = s->command[5];
107
108 s->response[0] = req.cmd;
109 s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1);
110 s->response_read_ptr = 0;
111
112 if (s->response_len == 16) {
113 /* R2 response */
114 s->response[0] = 0x3f;
115 s->response_len += 1;
116 } else if (s->response_len == 4) {
117 /* no crc calculation, insert dummy byte */
118 s->response[5] = 0;
119 s->response_len += 2;
120 }
121
122 if (req.cmd == 0) {
123 /* next write is a dummy byte to clock the initialization of the sd
124 * card */
125 s->ignore_next_cmd = 1;
126 }
127 }
128
129 static uint64_t memcard_read(void *opaque, hwaddr addr,
130 unsigned size)
131 {
132 MilkymistMemcardState *s = opaque;
133 uint32_t r = 0;
134
135 addr >>= 2;
136 switch (addr) {
137 case R_CMD:
138 if (!s->enabled) {
139 r = 0xff;
140 } else {
141 r = s->response[s->response_read_ptr++];
142 if (s->response_read_ptr > s->response_len) {
143 qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: "
144 "read more cmd bytes than available: clipping\n");
145 s->response_read_ptr = 0;
146 }
147 }
148 break;
149 case R_DAT:
150 if (!s->enabled) {
151 r = 0xffffffff;
152 } else {
153 r = 0;
154 r |= sdbus_read_data(&s->sdbus) << 24;
155 r |= sdbus_read_data(&s->sdbus) << 16;
156 r |= sdbus_read_data(&s->sdbus) << 8;
157 r |= sdbus_read_data(&s->sdbus);
158 }
159 break;
160 case R_CLK2XDIV:
161 case R_ENABLE:
162 case R_PENDING:
163 case R_START:
164 r = s->regs[addr];
165 break;
166
167 default:
168 qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
169 "read access to unknown register 0x%" HWADDR_PRIx "\n",
170 addr << 2);
171 break;
172 }
173
174 trace_milkymist_memcard_memory_read(addr << 2, r);
175
176 return r;
177 }
178
179 static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
180 unsigned size)
181 {
182 MilkymistMemcardState *s = opaque;
183
184 trace_milkymist_memcard_memory_write(addr, value);
185
186 addr >>= 2;
187 switch (addr) {
188 case R_PENDING:
189 /* clear rx pending bits */
190 s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
191 update_pending_bits(s);
192 break;
193 case R_CMD:
194 if (!s->enabled) {
195 break;
196 }
197 if (s->ignore_next_cmd) {
198 s->ignore_next_cmd = 0;
199 break;
200 }
201 s->command[s->command_write_ptr] = value & 0xff;
202 s->command_write_ptr = (s->command_write_ptr + 1) % 6;
203 if (s->command_write_ptr == 0) {
204 memcard_sd_command(s);
205 }
206 break;
207 case R_DAT:
208 if (!s->enabled) {
209 break;
210 }
211 sdbus_write_data(&s->sdbus, (value >> 24) & 0xff);
212 sdbus_write_data(&s->sdbus, (value >> 16) & 0xff);
213 sdbus_write_data(&s->sdbus, (value >> 8) & 0xff);
214 sdbus_write_data(&s->sdbus, value & 0xff);
215 break;
216 case R_ENABLE:
217 s->regs[addr] = value;
218 update_pending_bits(s);
219 break;
220 case R_CLK2XDIV:
221 case R_START:
222 s->regs[addr] = value;
223 break;
224
225 default:
226 qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
227 "write access to unknown register 0x%" HWADDR_PRIx " "
228 "(value 0x%" PRIx64 ")\n", addr << 2, value);
229 break;
230 }
231 }
232
233 static const MemoryRegionOps memcard_mmio_ops = {
234 .read = memcard_read,
235 .write = memcard_write,
236 .valid = {
237 .min_access_size = 4,
238 .max_access_size = 4,
239 },
240 .endianness = DEVICE_NATIVE_ENDIAN,
241 };
242
243 static void milkymist_memcard_reset(DeviceState *d)
244 {
245 MilkymistMemcardState *s = MILKYMIST_MEMCARD(d);
246 int i;
247
248 s->command_write_ptr = 0;
249 s->response_read_ptr = 0;
250 s->response_len = 0;
251
252 for (i = 0; i < R_MAX; i++) {
253 s->regs[i] = 0;
254 }
255 }
256
257 static void milkymist_memcard_init(Object *obj)
258 {
259 MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
260 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
261
262 memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
263 "milkymist-memcard", R_MAX * 4);
264 sysbus_init_mmio(dev, &s->regs_region);
265 }
266
267 static void milkymist_memcard_realize(DeviceState *dev, Error **errp)
268 {
269 MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
270 DeviceState *carddev;
271 BlockBackend *blk;
272 DriveInfo *dinfo;
273 Error *err = NULL;
274
275 qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
276 dev, "sd-bus");
277
278 /* Create and plug in the sd card */
279 /* FIXME use a qdev drive property instead of drive_get_next() */
280 dinfo = drive_get_next(IF_SD);
281 blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
282 carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD);
283 qdev_prop_set_drive(carddev, "drive", blk, &err);
284 object_property_set_bool(OBJECT(carddev), true, "realized", &err);
285 if (err) {
286 error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
287 return;
288 }
289 s->enabled = blk && blk_is_inserted(blk);
290 }
291
292 static const VMStateDescription vmstate_milkymist_memcard = {
293 .name = "milkymist-memcard",
294 .version_id = 1,
295 .minimum_version_id = 1,
296 .fields = (VMStateField[]) {
297 VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
298 VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
299 VMSTATE_INT32(response_len, MilkymistMemcardState),
300 VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
301 VMSTATE_INT32(enabled, MilkymistMemcardState),
302 VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
303 VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
304 VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
305 VMSTATE_END_OF_LIST()
306 }
307 };
308
309 static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
310 {
311 DeviceClass *dc = DEVICE_CLASS(klass);
312
313 dc->realize = milkymist_memcard_realize;
314 dc->reset = milkymist_memcard_reset;
315 dc->vmsd = &vmstate_milkymist_memcard;
316 /* Reason: init() method uses drive_get_next() */
317 dc->user_creatable = false;
318 }
319
320 static const TypeInfo milkymist_memcard_info = {
321 .name = TYPE_MILKYMIST_MEMCARD,
322 .parent = TYPE_SYS_BUS_DEVICE,
323 .instance_size = sizeof(MilkymistMemcardState),
324 .instance_init = milkymist_memcard_init,
325 .class_init = milkymist_memcard_class_init,
326 };
327
328 static void milkymist_memcard_register_types(void)
329 {
330 type_register_static(&milkymist_memcard_info);
331 }
332
333 type_init(milkymist_memcard_register_types)