123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /*
- * Copyright (c) 2018, Impinj, Inc.
- *
- * Chipidea USB block emulation code
- *
- * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
- #include "qemu/osdep.h"
- #include "hw/usb/hcd-ehci.h"
- #include "hw/usb/chipidea.h"
- #include "qemu/module.h"
- enum {
- CHIPIDEA_USBx_DCIVERSION = 0x000,
- CHIPIDEA_USBx_DCCPARAMS = 0x004,
- CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8),
- };
- static uint64_t chipidea_read(void *opaque, hwaddr offset,
- unsigned size)
- {
- return 0;
- }
- static void chipidea_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
- {
- }
- static const struct MemoryRegionOps chipidea_ops = {
- .read = chipidea_read,
- .write = chipidea_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the
- * real device but in practice there is no reason for a guest
- * to access this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
- };
- static uint64_t chipidea_dc_read(void *opaque, hwaddr offset,
- unsigned size)
- {
- switch (offset) {
- case CHIPIDEA_USBx_DCIVERSION:
- return 0x1;
- case CHIPIDEA_USBx_DCCPARAMS:
- /*
- * Real hardware (at least i.MX7) will also report the
- * controller as "Device Capable" (and 8 supported endpoints),
- * but there doesn't seem to be much point in doing so, since
- * we don't emulate that part.
- */
- return CHIPIDEA_USBx_DCCPARAMS_HC;
- }
- return 0;
- }
- static void chipidea_dc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
- {
- }
- static const struct MemoryRegionOps chipidea_dc_ops = {
- .read = chipidea_dc_read,
- .write = chipidea_dc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- /*
- * Our device would not work correctly if the guest was doing
- * unaligned access. This might not be a limitation on the real
- * device but in practice there is no reason for a guest to access
- * this device unaligned.
- */
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
- };
- static void chipidea_init(Object *obj)
- {
- EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci;
- ChipideaState *ci = CHIPIDEA(obj);
- int i;
- for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) {
- const struct {
- const char *name;
- hwaddr offset;
- uint64_t size;
- const struct MemoryRegionOps *ops;
- } regions[ARRAY_SIZE(ci->iomem)] = {
- /*
- * Registers located between offsets 0x000 and 0xFC
- */
- {
- .name = TYPE_CHIPIDEA ".misc",
- .offset = 0x000,
- .size = 0x100,
- .ops = &chipidea_ops,
- },
- /*
- * Registers located between offsets 0x1A4 and 0x1DC
- */
- {
- .name = TYPE_CHIPIDEA ".endpoints",
- .offset = 0x1A4,
- .size = 0x1DC - 0x1A4 + 4,
- .ops = &chipidea_ops,
- },
- /*
- * USB_x_DCIVERSION and USB_x_DCCPARAMS
- */
- {
- .name = TYPE_CHIPIDEA ".dc",
- .offset = 0x120,
- .size = 8,
- .ops = &chipidea_dc_ops,
- },
- };
- memory_region_init_io(&ci->iomem[i],
- obj,
- regions[i].ops,
- ci,
- regions[i].name,
- regions[i].size);
- memory_region_add_subregion(&ehci->mem,
- regions[i].offset,
- &ci->iomem[i]);
- }
- }
- static void chipidea_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
- /*
- * Offsets used were taken from i.MX7Dual Applications Processor
- * Reference Manual, Rev 0.1, p. 3177, Table 11-59
- */
- sec->capsbase = 0x100;
- sec->opregbase = 0x140;
- sec->portnr = 1;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- dc->desc = "Chipidea USB Module";
- }
- static const TypeInfo chipidea_info = {
- .name = TYPE_CHIPIDEA,
- .parent = TYPE_SYS_BUS_EHCI,
- .instance_size = sizeof(ChipideaState),
- .instance_init = chipidea_init,
- .class_init = chipidea_class_init,
- };
- static void chipidea_register_type(void)
- {
- type_register_static(&chipidea_info);
- }
- type_init(chipidea_register_type)
|