*
*
* Specification available at:
- * http://www.milkymist.org/socdoc/memcard.pdf
+ * http://milkymist.walle.cc/socdoc/memcard.pdf
*/
+#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "trace.h"
-#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
-#include "hw/sd.h"
+#include "hw/sd/sd.h"
enum {
ENABLE_CMD_TX = (1<<0),
R_MAX
};
+#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard"
+#define MILKYMIST_MEMCARD(obj) \
+ OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD)
+
struct MilkymistMemcardState {
- SysBusDevice busdev;
+ SysBusDevice parent_obj;
+
MemoryRegion regs_region;
- SDState *card;
+ SDBus sdbus;
int command_write_ptr;
int response_read_ptr;
req.crc = s->command[5];
s->response[0] = req.cmd;
- s->response_len = sd_do_command(s->card, &req, s->response+1);
+ s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1);
s->response_read_ptr = 0;
if (s->response_len == 16) {
} else {
r = s->response[s->response_read_ptr++];
if (s->response_read_ptr > s->response_len) {
- error_report("milkymist_memcard: "
- "read more cmd bytes than available. Clipping.");
+ qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: "
+ "read more cmd bytes than available. Clipping.");
s->response_read_ptr = 0;
}
}
r = 0xffffffff;
} else {
r = 0;
- r |= sd_read_data(s->card) << 24;
- r |= sd_read_data(s->card) << 16;
- r |= sd_read_data(s->card) << 8;
- r |= sd_read_data(s->card);
+ r |= sdbus_read_data(&s->sdbus) << 24;
+ r |= sdbus_read_data(&s->sdbus) << 16;
+ r |= sdbus_read_data(&s->sdbus) << 8;
+ r |= sdbus_read_data(&s->sdbus);
}
break;
case R_CLK2XDIV:
break;
default:
- error_report("milkymist_memcard: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
+ "read access to unknown register 0x%" HWADDR_PRIx "\n",
+ addr << 2);
break;
}
if (!s->enabled) {
break;
}
- sd_write_data(s->card, (value >> 24) & 0xff);
- sd_write_data(s->card, (value >> 16) & 0xff);
- sd_write_data(s->card, (value >> 8) & 0xff);
- sd_write_data(s->card, value & 0xff);
+ sdbus_write_data(&s->sdbus, (value >> 24) & 0xff);
+ sdbus_write_data(&s->sdbus, (value >> 16) & 0xff);
+ sdbus_write_data(&s->sdbus, (value >> 8) & 0xff);
+ sdbus_write_data(&s->sdbus, value & 0xff);
break;
case R_ENABLE:
s->regs[addr] = value;
break;
default:
- error_report("milkymist_memcard: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
+ "write access to unknown register 0x%" HWADDR_PRIx " "
+ "(value 0x%" PRIx64 ")\n", addr << 2, value);
break;
}
}
static void milkymist_memcard_reset(DeviceState *d)
{
- MilkymistMemcardState *s =
- container_of(d, MilkymistMemcardState, busdev.qdev);
+ MilkymistMemcardState *s = MILKYMIST_MEMCARD(d);
int i;
s->command_write_ptr = 0;
}
}
-static int milkymist_memcard_init(SysBusDevice *dev)
+static void milkymist_memcard_init(Object *obj)
{
- MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
- DriveInfo *dinfo;
+ MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- dinfo = drive_get_next(IF_SD);
- s->card = sd_init(dinfo ? dinfo->bdrv : NULL, false);
- s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
-
- memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
+ memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
"milkymist-memcard", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
+}
- return 0;
+static void milkymist_memcard_realize(DeviceState *dev, Error **errp)
+{
+ MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
+ DeviceState *carddev;
+ BlockBackend *blk;
+ DriveInfo *dinfo;
+ Error *err = NULL;
+
+ qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
+ dev, "sd-bus");
+
+ /* Create and plug in the sd card */
+ /* FIXME use a qdev drive property instead of drive_get_next() */
+ dinfo = drive_get_next(IF_SD);
+ blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
+ carddev = qdev_create(&s->sdbus.qbus, TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &err);
+ object_property_set_bool(OBJECT(carddev), true, "realized", &err);
+ if (err) {
+ error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
+ return;
+ }
+ s->enabled = blk && blk_is_inserted(blk);
}
static const VMStateDescription vmstate_milkymist_memcard = {
.name = "milkymist-memcard",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
+ .fields = (VMStateField[]) {
VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
VMSTATE_INT32(response_len, MilkymistMemcardState),
static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = milkymist_memcard_init;
+ dc->realize = milkymist_memcard_realize;
dc->reset = milkymist_memcard_reset;
dc->vmsd = &vmstate_milkymist_memcard;
+ /* Reason: init() method uses drive_get_next() */
+ dc->user_creatable = false;
}
static const TypeInfo milkymist_memcard_info = {
- .name = "milkymist-memcard",
+ .name = TYPE_MILKYMIST_MEMCARD,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MilkymistMemcardState),
+ .instance_init = milkymist_memcard_init,
.class_init = milkymist_memcard_class_init,
};