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                                 &reg_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