qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

chipidea.c (5023B)


      1 /*
      2  * Copyright (c) 2018, Impinj, Inc.
      3  *
      4  * Chipidea USB block emulation code
      5  *
      6  * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
      7  *
      8  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9  * See the COPYING file in the top-level directory.
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "hw/usb/hcd-ehci.h"
     14 #include "hw/usb/chipidea.h"
     15 #include "qemu/module.h"
     16 
     17 enum {
     18     CHIPIDEA_USBx_DCIVERSION   = 0x000,
     19     CHIPIDEA_USBx_DCCPARAMS    = 0x004,
     20     CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8),
     21 };
     22 
     23 static uint64_t chipidea_read(void *opaque, hwaddr offset,
     24                                unsigned size)
     25 {
     26     return 0;
     27 }
     28 
     29 static void chipidea_write(void *opaque, hwaddr offset,
     30                             uint64_t value, unsigned size)
     31 {
     32 }
     33 
     34 static const struct MemoryRegionOps chipidea_ops = {
     35     .read = chipidea_read,
     36     .write = chipidea_write,
     37     .endianness = DEVICE_NATIVE_ENDIAN,
     38     .impl = {
     39         /*
     40          * Our device would not work correctly if the guest was doing
     41          * unaligned access. This might not be a limitation on the
     42          * real device but in practice there is no reason for a guest
     43          * to access this device unaligned.
     44          */
     45         .min_access_size = 4,
     46         .max_access_size = 4,
     47         .unaligned = false,
     48     },
     49 };
     50 
     51 static uint64_t chipidea_dc_read(void *opaque, hwaddr offset,
     52                                  unsigned size)
     53 {
     54     switch (offset) {
     55     case CHIPIDEA_USBx_DCIVERSION:
     56         return 0x1;
     57     case CHIPIDEA_USBx_DCCPARAMS:
     58         /*
     59          * Real hardware (at least i.MX7) will also report the
     60          * controller as "Device Capable" (and 8 supported endpoints),
     61          * but there doesn't seem to be much point in doing so, since
     62          * we don't emulate that part.
     63          */
     64         return CHIPIDEA_USBx_DCCPARAMS_HC;
     65     }
     66 
     67     return 0;
     68 }
     69 
     70 static void chipidea_dc_write(void *opaque, hwaddr offset,
     71                               uint64_t value, unsigned size)
     72 {
     73 }
     74 
     75 static const struct MemoryRegionOps chipidea_dc_ops = {
     76     .read = chipidea_dc_read,
     77     .write = chipidea_dc_write,
     78     .endianness = DEVICE_NATIVE_ENDIAN,
     79     .impl = {
     80         /*
     81          * Our device would not work correctly if the guest was doing
     82          * unaligned access. This might not be a limitation on the real
     83          * device but in practice there is no reason for a guest to access
     84          * this device unaligned.
     85          */
     86         .min_access_size = 4,
     87         .max_access_size = 4,
     88         .unaligned = false,
     89     },
     90 };
     91 
     92 static void chipidea_init(Object *obj)
     93 {
     94     EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci;
     95     ChipideaState *ci = CHIPIDEA(obj);
     96     int i;
     97 
     98     for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) {
     99         const struct {
    100             const char *name;
    101             hwaddr offset;
    102             uint64_t size;
    103             const struct MemoryRegionOps *ops;
    104         } regions[ARRAY_SIZE(ci->iomem)] = {
    105             /*
    106              * Registers located between offsets 0x000 and 0xFC
    107              */
    108             {
    109                 .name   = TYPE_CHIPIDEA ".misc",
    110                 .offset = 0x000,
    111                 .size   = 0x100,
    112                 .ops    = &chipidea_ops,
    113             },
    114             /*
    115              * Registers located between offsets 0x1A4 and 0x1DC
    116              */
    117             {
    118                 .name   = TYPE_CHIPIDEA ".endpoints",
    119                 .offset = 0x1A4,
    120                 .size   = 0x1DC - 0x1A4 + 4,
    121                 .ops    = &chipidea_ops,
    122             },
    123             /*
    124              * USB_x_DCIVERSION and USB_x_DCCPARAMS
    125              */
    126             {
    127                 .name   = TYPE_CHIPIDEA ".dc",
    128                 .offset = 0x120,
    129                 .size   = 8,
    130                 .ops    = &chipidea_dc_ops,
    131             },
    132         };
    133 
    134         memory_region_init_io(&ci->iomem[i],
    135                               obj,
    136                               regions[i].ops,
    137                               ci,
    138                               regions[i].name,
    139                               regions[i].size);
    140 
    141         memory_region_add_subregion(&ehci->mem,
    142                                     regions[i].offset,
    143                                     &ci->iomem[i]);
    144     }
    145 }
    146 
    147 static void chipidea_class_init(ObjectClass *klass, void *data)
    148 {
    149     DeviceClass *dc = DEVICE_CLASS(klass);
    150     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
    151 
    152     /*
    153      * Offsets used were taken from i.MX7Dual Applications Processor
    154      * Reference Manual, Rev 0.1, p. 3177, Table 11-59
    155      */
    156     sec->capsbase   = 0x100;
    157     sec->opregbase  = 0x140;
    158     sec->portnr     = 1;
    159 
    160     set_bit(DEVICE_CATEGORY_USB, dc->categories);
    161     dc->desc = "Chipidea USB Module";
    162 }
    163 
    164 static const TypeInfo chipidea_info = {
    165     .name          = TYPE_CHIPIDEA,
    166     .parent        = TYPE_SYS_BUS_EHCI,
    167     .instance_size = sizeof(ChipideaState),
    168     .instance_init = chipidea_init,
    169     .class_init    = chipidea_class_init,
    170 };
    171 
    172 static void chipidea_register_type(void)
    173 {
    174     type_register_static(&chipidea_info);
    175 }
    176 type_init(chipidea_register_type)