qemu/hw/usb/imx-usb-phy.c
<<
>>
Prefs
   1/*
   2 * i.MX USB PHY
   3 *
   4 * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 *
   9 * We need to implement basic reset control in the PHY control register.
  10 * For everything else, it is sufficient to set whatever is written.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "hw/usb/imx-usb-phy.h"
  15#include "migration/vmstate.h"
  16#include "qemu/module.h"
  17
  18static const VMStateDescription vmstate_imx_usbphy = {
  19    .name = TYPE_IMX_USBPHY,
  20    .version_id = 1,
  21    .minimum_version_id = 1,
  22    .fields = (VMStateField[]) {
  23        VMSTATE_UINT32_ARRAY(usbphy, IMXUSBPHYState, USBPHY_MAX),
  24        VMSTATE_END_OF_LIST()
  25    },
  26};
  27
  28static void imx_usbphy_softreset(IMXUSBPHYState *s)
  29{
  30    s->usbphy[USBPHY_PWD] = 0x001e1c00;
  31    s->usbphy[USBPHY_TX] = 0x10060607;
  32    s->usbphy[USBPHY_RX] = 0x00000000;
  33    s->usbphy[USBPHY_CTRL] = 0xc0200000;
  34}
  35
  36static void imx_usbphy_reset(DeviceState *dev)
  37{
  38    IMXUSBPHYState *s = IMX_USBPHY(dev);
  39
  40    s->usbphy[USBPHY_STATUS] = 0x00000000;
  41    s->usbphy[USBPHY_DEBUG] = 0x7f180000;
  42    s->usbphy[USBPHY_DEBUG0_STATUS] = 0x00000000;
  43    s->usbphy[USBPHY_DEBUG1] = 0x00001000;
  44    s->usbphy[USBPHY_VERSION] = 0x04020000;
  45
  46    imx_usbphy_softreset(s);
  47}
  48
  49static uint64_t imx_usbphy_read(void *opaque, hwaddr offset, unsigned size)
  50{
  51    IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
  52    uint32_t index = offset >> 2;
  53    uint32_t value;
  54
  55    switch (index) {
  56    case USBPHY_PWD_SET:
  57    case USBPHY_TX_SET:
  58    case USBPHY_RX_SET:
  59    case USBPHY_CTRL_SET:
  60    case USBPHY_DEBUG_SET:
  61    case USBPHY_DEBUG1_SET:
  62        /*
  63         * All REG_NAME_SET register access are in fact targeting the
  64         * REG_NAME register.
  65         */
  66        value = s->usbphy[index - 1];
  67        break;
  68    case USBPHY_PWD_CLR:
  69    case USBPHY_TX_CLR:
  70    case USBPHY_RX_CLR:
  71    case USBPHY_CTRL_CLR:
  72    case USBPHY_DEBUG_CLR:
  73    case USBPHY_DEBUG1_CLR:
  74        /*
  75         * All REG_NAME_CLR register access are in fact targeting the
  76         * REG_NAME register.
  77         */
  78        value = s->usbphy[index - 2];
  79        break;
  80    case USBPHY_PWD_TOG:
  81    case USBPHY_TX_TOG:
  82    case USBPHY_RX_TOG:
  83    case USBPHY_CTRL_TOG:
  84    case USBPHY_DEBUG_TOG:
  85    case USBPHY_DEBUG1_TOG:
  86        /*
  87         * All REG_NAME_TOG register access are in fact targeting the
  88         * REG_NAME register.
  89         */
  90        value = s->usbphy[index - 3];
  91        break;
  92    default:
  93        value = s->usbphy[index];
  94        break;
  95    }
  96    return (uint64_t)value;
  97}
  98
  99static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value,
 100                             unsigned size)
 101{
 102    IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
 103    uint32_t index = offset >> 2;
 104
 105    switch (index) {
 106    case USBPHY_CTRL:
 107        s->usbphy[index] = value;
 108        if (value & USBPHY_CTRL_SFTRST) {
 109            imx_usbphy_softreset(s);
 110        }
 111        break;
 112    case USBPHY_PWD:
 113    case USBPHY_TX:
 114    case USBPHY_RX:
 115    case USBPHY_STATUS:
 116    case USBPHY_DEBUG:
 117    case USBPHY_DEBUG1:
 118        s->usbphy[index] = value;
 119        break;
 120    case USBPHY_CTRL_SET:
 121        s->usbphy[index - 1] |= value;
 122        if (value & USBPHY_CTRL_SFTRST) {
 123            imx_usbphy_softreset(s);
 124        }
 125        break;
 126    case USBPHY_PWD_SET:
 127    case USBPHY_TX_SET:
 128    case USBPHY_RX_SET:
 129    case USBPHY_DEBUG_SET:
 130    case USBPHY_DEBUG1_SET:
 131        /*
 132         * All REG_NAME_SET register access are in fact targeting the
 133         * REG_NAME register. So we change the value of the REG_NAME
 134         * register, setting bits passed in the value.
 135         */
 136        s->usbphy[index - 1] |= value;
 137        break;
 138    case USBPHY_PWD_CLR:
 139    case USBPHY_TX_CLR:
 140    case USBPHY_RX_CLR:
 141    case USBPHY_CTRL_CLR:
 142    case USBPHY_DEBUG_CLR:
 143    case USBPHY_DEBUG1_CLR:
 144        /*
 145         * All REG_NAME_CLR register access are in fact targeting the
 146         * REG_NAME register. So we change the value of the REG_NAME
 147         * register, unsetting bits passed in the value.
 148         */
 149        s->usbphy[index - 2] &= ~value;
 150        break;
 151    case USBPHY_CTRL_TOG:
 152        s->usbphy[index - 3] ^= value;
 153        if ((value & USBPHY_CTRL_SFTRST) &&
 154            (s->usbphy[index - 3] & USBPHY_CTRL_SFTRST)) {
 155            imx_usbphy_softreset(s);
 156        }
 157        break;
 158    case USBPHY_PWD_TOG:
 159    case USBPHY_TX_TOG:
 160    case USBPHY_RX_TOG:
 161    case USBPHY_DEBUG_TOG:
 162    case USBPHY_DEBUG1_TOG:
 163        /*
 164         * All REG_NAME_TOG register access are in fact targeting the
 165         * REG_NAME register. So we change the value of the REG_NAME
 166         * register, toggling bits passed in the value.
 167         */
 168        s->usbphy[index - 3] ^= value;
 169        break;
 170    default:
 171        /* Other registers are read-only */
 172        break;
 173    }
 174}
 175
 176static const struct MemoryRegionOps imx_usbphy_ops = {
 177    .read = imx_usbphy_read,
 178    .write = imx_usbphy_write,
 179    .endianness = DEVICE_NATIVE_ENDIAN,
 180    .valid = {
 181        /*
 182         * Our device would not work correctly if the guest was doing
 183         * unaligned access. This might not be a limitation on the real
 184         * device but in practice there is no reason for a guest to access
 185         * this device unaligned.
 186         */
 187        .min_access_size = 4,
 188        .max_access_size = 4,
 189        .unaligned = false,
 190    },
 191};
 192
 193static void imx_usbphy_realize(DeviceState *dev, Error **errp)
 194{
 195    IMXUSBPHYState *s = IMX_USBPHY(dev);
 196
 197    memory_region_init_io(&s->iomem, OBJECT(s), &imx_usbphy_ops, s,
 198                          "imx-usbphy", 0x1000);
 199    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
 200}
 201
 202static void imx_usbphy_class_init(ObjectClass *klass, void *data)
 203{
 204    DeviceClass *dc = DEVICE_CLASS(klass);
 205
 206    dc->reset = imx_usbphy_reset;
 207    dc->vmsd = &vmstate_imx_usbphy;
 208    dc->desc = "i.MX USB PHY Module";
 209    dc->realize = imx_usbphy_realize;
 210}
 211
 212static const TypeInfo imx_usbphy_info = {
 213    .name          = TYPE_IMX_USBPHY,
 214    .parent        = TYPE_SYS_BUS_DEVICE,
 215    .instance_size = sizeof(IMXUSBPHYState),
 216    .class_init    = imx_usbphy_class_init,
 217};
 218
 219static void imx_usbphy_register_types(void)
 220{
 221    type_register_static(&imx_usbphy_info);
 222}
 223
 224type_init(imx_usbphy_register_types)
 225