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