qemu/hw/usb/xlnx-versal-usb2-ctrl-regs.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the VersalUsb2CtrlRegs Register control/Status block for
   3 * USB2.0 controller
   4 *
   5 * This module should control phy_reset, permanent device plugs, frame length
   6 * time adjust & setting of coherency paths. None of which are emulated in
   7 * present model.
   8 *
   9 * Copyright (c) 2020 Xilinx Inc. Vikram Garhwal <fnu.vikram@xilinx.com>
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27 * THE SOFTWARE.
  28 */
  29
  30#include "qemu/osdep.h"
  31#include "hw/sysbus.h"
  32#include "hw/irq.h"
  33#include "hw/register.h"
  34#include "qemu/bitops.h"
  35#include "qom/object.h"
  36#include "migration/vmstate.h"
  37#include "hw/usb/xlnx-versal-usb2-ctrl-regs.h"
  38
  39#ifndef XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG
  40#define XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG 0
  41#endif
  42
  43REG32(BUS_FILTER, 0x30)
  44    FIELD(BUS_FILTER, BYPASS, 0, 4)
  45REG32(PORT, 0x34)
  46    FIELD(PORT, HOST_SMI_BAR_WR, 4, 1)
  47    FIELD(PORT, HOST_SMI_PCI_CMD_REG_WR, 3, 1)
  48    FIELD(PORT, HOST_MSI_ENABLE, 2, 1)
  49    FIELD(PORT, PWR_CTRL_PRSNT, 1, 1)
  50    FIELD(PORT, HUB_PERM_ATTACH, 0, 1)
  51REG32(JITTER_ADJUST, 0x38)
  52    FIELD(JITTER_ADJUST, FLADJ, 0, 6)
  53REG32(BIGENDIAN, 0x40)
  54    FIELD(BIGENDIAN, ENDIAN_GS, 0, 1)
  55REG32(COHERENCY, 0x44)
  56    FIELD(COHERENCY, USB_COHERENCY, 0, 1)
  57REG32(XHC_BME, 0x48)
  58    FIELD(XHC_BME, XHC_BME, 0, 1)
  59REG32(REG_CTRL, 0x60)
  60    FIELD(REG_CTRL, SLVERR_ENABLE, 0, 1)
  61REG32(IR_STATUS, 0x64)
  62    FIELD(IR_STATUS, HOST_SYS_ERR, 1, 1)
  63    FIELD(IR_STATUS, ADDR_DEC_ERR, 0, 1)
  64REG32(IR_MASK, 0x68)
  65    FIELD(IR_MASK, HOST_SYS_ERR, 1, 1)
  66    FIELD(IR_MASK, ADDR_DEC_ERR, 0, 1)
  67REG32(IR_ENABLE, 0x6c)
  68    FIELD(IR_ENABLE, HOST_SYS_ERR, 1, 1)
  69    FIELD(IR_ENABLE, ADDR_DEC_ERR, 0, 1)
  70REG32(IR_DISABLE, 0x70)
  71    FIELD(IR_DISABLE, HOST_SYS_ERR, 1, 1)
  72    FIELD(IR_DISABLE, ADDR_DEC_ERR, 0, 1)
  73REG32(USB3, 0x78)
  74
  75static void ir_update_irq(VersalUsb2CtrlRegs *s)
  76{
  77    bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
  78    qemu_set_irq(s->irq_ir, pending);
  79}
  80
  81static void ir_status_postw(RegisterInfo *reg, uint64_t val64)
  82{
  83    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque);
  84    /*
  85     * TODO: This should also clear USBSTS.HSE field in USB XHCI register.
  86     * May be combine both the modules.
  87     */
  88    ir_update_irq(s);
  89}
  90
  91static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64)
  92{
  93    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque);
  94    uint32_t val = val64;
  95
  96    s->regs[R_IR_MASK] &= ~val;
  97    ir_update_irq(s);
  98    return 0;
  99}
 100
 101static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
 102{
 103    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque);
 104    uint32_t val = val64;
 105
 106    s->regs[R_IR_MASK] |= val;
 107    ir_update_irq(s);
 108    return 0;
 109}
 110
 111static const RegisterAccessInfo usb2_ctrl_regs_regs_info[] = {
 112    {   .name = "BUS_FILTER",  .addr = A_BUS_FILTER,
 113        .rsvd = 0xfffffff0,
 114    },{ .name = "PORT",  .addr = A_PORT,
 115        .rsvd = 0xffffffe0,
 116    },{ .name = "JITTER_ADJUST",  .addr = A_JITTER_ADJUST,
 117        .reset = 0x20,
 118        .rsvd = 0xffffffc0,
 119    },{ .name = "BIGENDIAN",  .addr = A_BIGENDIAN,
 120        .rsvd = 0xfffffffe,
 121    },{ .name = "COHERENCY",  .addr = A_COHERENCY,
 122        .rsvd = 0xfffffffe,
 123    },{ .name = "XHC_BME",  .addr = A_XHC_BME,
 124        .reset = 0x1,
 125        .rsvd = 0xfffffffe,
 126    },{ .name = "REG_CTRL",  .addr = A_REG_CTRL,
 127        .rsvd = 0xfffffffe,
 128    },{ .name = "IR_STATUS",  .addr = A_IR_STATUS,
 129        .rsvd = 0xfffffffc,
 130        .w1c = 0x3,
 131        .post_write = ir_status_postw,
 132    },{ .name = "IR_MASK",  .addr = A_IR_MASK,
 133        .reset = 0x3,
 134        .rsvd = 0xfffffffc,
 135        .ro = 0x3,
 136    },{ .name = "IR_ENABLE",  .addr = A_IR_ENABLE,
 137        .rsvd = 0xfffffffc,
 138        .pre_write = ir_enable_prew,
 139    },{ .name = "IR_DISABLE",  .addr = A_IR_DISABLE,
 140        .rsvd = 0xfffffffc,
 141        .pre_write = ir_disable_prew,
 142    },{ .name = "USB3",  .addr = A_USB3,
 143    }
 144};
 145
 146static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type)
 147{
 148    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj);
 149    unsigned int i;
 150
 151    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 152        register_reset(&s->regs_info[i]);
 153    }
 154}
 155
 156static void usb2_ctrl_regs_reset_hold(Object *obj)
 157{
 158    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj);
 159
 160    ir_update_irq(s);
 161}
 162
 163static const MemoryRegionOps usb2_ctrl_regs_ops = {
 164    .read = register_read_memory,
 165    .write = register_write_memory,
 166    .endianness = DEVICE_LITTLE_ENDIAN,
 167    .valid = {
 168        .min_access_size = 4,
 169        .max_access_size = 4,
 170    },
 171};
 172
 173static void usb2_ctrl_regs_init(Object *obj)
 174{
 175    VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj);
 176    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 177    RegisterInfoArray *reg_array;
 178
 179    memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_USB2_CTRL_REGS,
 180                       USB2_REGS_R_MAX * 4);
 181    reg_array =
 182        register_init_block32(DEVICE(obj), usb2_ctrl_regs_regs_info,
 183                              ARRAY_SIZE(usb2_ctrl_regs_regs_info),
 184                              s->regs_info, s->regs,
 185                              &usb2_ctrl_regs_ops,
 186                              XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG,
 187                              USB2_REGS_R_MAX * 4);
 188    memory_region_add_subregion(&s->iomem,
 189                                0x0,
 190                                &reg_array->mem);
 191    sysbus_init_mmio(sbd, &s->iomem);
 192    sysbus_init_irq(sbd, &s->irq_ir);
 193}
 194
 195static const VMStateDescription vmstate_usb2_ctrl_regs = {
 196    .name = TYPE_XILINX_VERSAL_USB2_CTRL_REGS,
 197    .version_id = 1,
 198    .minimum_version_id = 1,
 199    .fields = (VMStateField[]) {
 200        VMSTATE_UINT32_ARRAY(regs, VersalUsb2CtrlRegs, USB2_REGS_R_MAX),
 201        VMSTATE_END_OF_LIST(),
 202    }
 203};
 204
 205static void usb2_ctrl_regs_class_init(ObjectClass *klass, void *data)
 206{
 207    DeviceClass *dc = DEVICE_CLASS(klass);
 208    ResettableClass *rc = RESETTABLE_CLASS(klass);
 209
 210    rc->phases.enter = usb2_ctrl_regs_reset_init;
 211    rc->phases.hold  = usb2_ctrl_regs_reset_hold;
 212    dc->vmsd = &vmstate_usb2_ctrl_regs;
 213}
 214
 215static const TypeInfo usb2_ctrl_regs_info = {
 216    .name          = TYPE_XILINX_VERSAL_USB2_CTRL_REGS,
 217    .parent        = TYPE_SYS_BUS_DEVICE,
 218    .instance_size = sizeof(VersalUsb2CtrlRegs),
 219    .class_init    = usb2_ctrl_regs_class_init,
 220    .instance_init = usb2_ctrl_regs_init,
 221};
 222
 223static void usb2_ctrl_regs_register_types(void)
 224{
 225    type_register_static(&usb2_ctrl_regs_info);
 226}
 227
 228type_init(usb2_ctrl_regs_register_types)
 229