///////////////////////////////////////////////////////////////////////// // $Id$ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2010-2017 Benjamin D Lunt (fys [at] fysnet [dot] net) // 2011-2021 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ///////////////////////////////////////////////////////////////////////// #ifndef BX_IODEV_USB_XHCI_H #define BX_IODEV_USB_XHCI_H #if BX_USE_USB_XHCI_SMF # define BX_XHCI_THIS theUSB_XHCI-> # define BX_XHCI_THIS_PTR theUSB_XHCI #else # define BX_XHCI_THIS this-> # define BX_XHCI_THIS_PTR this #endif // If in 64bit mode, print 64bits, else only print 32 bit addresses #if BX_PHY_ADDRESS_LONG #define FORMATADDRESS FMT_ADDRX64 #else #define FORMATADDRESS "%08X" #endif /************************************************************************************************ * Actual configuration of the card */ #define IO_SPACE_SIZE 8192 #define OPS_REGS_OFFSET 0x20 // Change this to 0.95, 0.96, 1.00, 1.10, according to the desired effects (LINK chain bit, etc) // uPD720202 is 1.00 #define VERSION_MAJOR 0x01 #define VERSION_MINOR 0x00 // HCSPARAMS1 #define MAX_SLOTS 32 // (1 based) #define INTERRUPTERS 8 // #define USB_XHCI_PORTS 4 // Port Registers, each supporting USB3 or USB2 (0x08 = uPD720201, 0x04 = uPD720202) #if (USB_XHCI_PORTS != 4) #error "USB_XHCI_PORTS must equal 4" #endif // HCSPARAMS2 #define ISO_SECH_THRESHOLD 1 #define MAX_SEG_TBL_SZ_EXP 1 #define SCATCH_PAD_RESTORE 1 // 1 = uses system memory and must be maintained. 0 = uses controller's internal memory #define MAX_SCRATCH_PADS 4 // 0 to 1023 // HCSPARAMS3 #define U1_DEVICE_EXIT_LAT 0 #define U2_DEVICE_EXIT_LAT 0 // HCCPARAMS1 #define ADDR_CAP_64 1 #define BW_NEGOTIATION 1 #define CONTEXT_SIZE 64 // Size of the CONTEXT blocks (32 or 64) #define PORT_POWER_CTRL 1 #define PORT_INDICATORS 0 #define LIGHT_HC_RESET 0 // Do we support the Light HC Reset function #define LAT_TOL_MSGING_CAP 1 // Latency Tolerance Messaging Capability (v1.00+) #define NO_SSD_SUPPORT 1 // No Secondary SID Support (v1.00+) #define PARSE_ALL_EVENT 1 // version 0.96 and below only (MUST BE 1 in v1.00+) #define SEC_DOMAIN_BAND 1 // version 0.96 and below only (MUST BE 1 in v1.00+) #define STOPPED_EDTLA 0 #define CONT_FRAME_ID 0 #define MAX_PSA_SIZE 0x05 #define EXT_CAPS_OFFSET 0x500 #define EXT_CAPS_SIZE 144 // HCCPARAMS2 (v1.10+) #if ((VERSION_MAJOR == 1) && (VERSION_MINOR >= 0x10)) #define U3_ENTRY_CAP 0 #define CONFIG_EP_CMND_CAP 0 #define FORCE_SAVE_CONTEXT_CAP 0 #define COMPLNC_TRANS_CAP 0 #define LARGE_ESIT_PAYLOAD_CAP 0 #define CONFIG_INFO_CAP 0 #endif #define XHCI_PAGE_SIZE 1 // Page size operational register value #define DOORBELL_OFFSET 0x800 #define RUNTIME_OFFSET 0x600 #define PORT_SET_OFFSET (0x400 + OPS_REGS_OFFSET) /************************************************************************************************/ #if ((VERSION_MAJOR > 1) || \ ((VERSION_MAJOR == 0) && ((VERSION_MINOR != 0x95) && (VERSION_MINOR != 0x96))) || \ ((VERSION_MAJOR == 1) && ((VERSION_MINOR != 0x00) && (VERSION_MINOR != 0x10)))) # error "Unknown Controller Version number specified." #endif #if (MAX_SCRATCH_PADS > 1023) # error "MAX_SCRATCH_PADS must be 0 to 1023." #endif #if (SCATCH_PAD_RESTORE && (MAX_SCRATCH_PADS == 0)) # error "Must specify amount of scratch pad buffers to use." #endif #if ((MAX_SCRATCH_PADS > 0) && !SCATCH_PAD_RESTORE) # error "Must set SCATCH_PAD_RESTORE to 1 if MAX_SCRATCH_PADS > 0" #endif #if ((PARSE_ALL_EVENT == 0) && (VERSION_MAJOR > 0)) # error "PARSE_ALL_EVENT must be 1 in version 1.0 and above" #endif #if ((SEC_DOMAIN_BAND == 0) && (VERSION_MAJOR > 0)) # error "SEC_DOMAIN_BAND must be 1 in version 1.0 and above" #endif #if ((LAT_TOL_MSGING_CAP == 1) && ((VERSION_MAJOR < 1) || (VERSION_MINOR < 0))) # error "LAT_TOL_MSGING_CAP must be used with in version 1.1 and above" #endif #if ((NO_SSD_SUPPORT == 1) && ((VERSION_MAJOR < 1) || (VERSION_MINOR < 0))) # error "NO_SSD_SUPPORT must be used with in version 1.1 and above" #endif // Each controller supports its own number of ports. We must adhere to that for now. // (The Extended Capabilities register set is hardcoded for this as of now.) // As long as BX_N_USB_XHCI_PORTS was defined as greater than what we have now, then // we are fine. // Note: BX_N_USB_XHCI_PORTS should have been defined as twice the amount of ports wanted. // ie.: Each physical port (socket) has two defined port register sets. One for USB3, one for USB2 // Only one port type may be used at a time. Port0 or Port1, not both. If Port0 is used, then // Port1 must be vacant. #define BX_N_USB_XHCI_PORTS 4 // xHCI speed values #define SPEED_FULL 1 #define SPEED_LOW 2 #define SPEED_HI 3 #define SPEED_SUPER 4 #define USB2 0 #define USB3 1 // our saved ring members struct RING_MEMBERS { struct { Bit64u dq_pointer; bool rcs; } command_ring; struct { bool rcs; unsigned trb_count; unsigned count; Bit64u cur_trb; struct { Bit64u addr; Bit32u size; Bit32u resv; } entrys[(1<> 8) #define NEC_FW_MINOR(v) (((v) & 0x000000FF) >> 0) #define TRB_GET_STYPE(x) (((x) & (0x1F << 16)) >> 16) #define TRB_SET_STYPE(x) (((x) & 0x1F) << 16) #define TRB_GET_TYPE(x) (((x) & (0x3F << 10)) >> 10) #define TRB_SET_TYPE(x) (((x) & 0x3F) << 10) #define TRB_GET_COMP_CODE(x) (((x) & (0xFF << 24)) >> 24) #define TRB_SET_COMP_CODE(x) (((x) & 0xFF) << 24) #define TRB_GET_SLOT(x) (((x) & (0xFF << 24)) >> 24) #define TRB_SET_SLOT(x) (((x) & 0xFF) << 24) #define TRB_GET_TDSIZE(x) (((x) & (0x1F << 17)) >> 17) #define TRB_SET_TDSIZE(x) (((x) & 0x1F) << 17) #define TRB_GET_EP(x) (((x) & (0x1F << 16)) >> 16) #define TRB_SET_EP(x) (((x) & 0x1F) << 16) #define TRB_GET_TARGET(x) (((x) & (0x3FF << 22)) >> 22) #define TRB_GET_TX_LEN(x) ((x) & 0x1FFFF) #define TRB_GET_TOGGLE(x) (((x) & (1<<1)) >> 1) #define TRB_DC(x) (((x) & (1<<9)) >> 9) #define TRB_IS_IMMED_DATA(x) (((x) & (1<<6)) >> 6) #define TRB_IOC(x) (((x) & (1<<5)) >> 5) #define TRB_CHAIN(x) (((x) & (1<<4)) >> 4) #define TRB_SPD(x) (((x) & (1<<2)) >> 2) #define TRB_TOGGLE(x) (((x) & (1<<1)) >> 1) #define TRB_TX_TYPE(x) (((x) == 2) ? USB_TOKEN_OUT : USB_TOKEN_IN) #define TRB_GET_DIR(x) (((x) & (1<<16)) ? USB_TOKEN_IN : USB_TOKEN_OUT) struct TRB { Bit64u parameter; Bit32u status; Bit32u command; }; typedef struct { struct XHCI_CAP_REGS { Bit32u HcCapLength; Bit32u HcSParams1; Bit32u HcSParams2; Bit32u HcSParams3; Bit32u HcCParams1; #if ((VERSION_MAJOR == 1) && (VERSION_MINOR >= 1)) Bit32u HcCParams2; #endif Bit32u DBOFF; Bit32u RTSOFF; } cap_regs; struct XHCI_OP_REGS { struct { Bit32u RsvdP1; // 18/20 bit reserved and preserved = 0x000000 RW #if ((VERSION_MAJOR == 1) && (VERSION_MINOR >= 0x10)) bool cme; // 1 bit Max Exit Latecy to Large = 0b RW bool spe; // 1 bit Generate Short Packet Comp = 0b RW #endif bool eu3s; // 1 bit Enable U3 MFINDEX Stop = 0b RW bool ewe; // 1 bit Enable Wrap Event = 0b RW bool crs; // 1 bit Controller Restore State = 0b RW bool css; // 1 bit Controller Save State = 0b RW bool lhcrst; // 1 bit Light HC Reset = 0b RW or RO (HCCPARAMS:LHRC) Bit8u RsvdP0; // 1 bit reserved and preserved = 000b RW bool hsee; // 1 bit Host System Error Enable = 0b RW bool inte; // 1 bit Interrupter Enable = 0b RW bool hcrst; // 1 bit HC Reset = 0b RW bool rs; // 1 bit Run Stop = 0b RW } HcCommand; // = 0x00000000 struct { Bit32u RsvdZ1; // 19 bit reserved and zero'd = 0x000000 RW bool hce; // 1 bit Host Controller Error = 0b RO bool cnr; // 1 bit Controller Not Ready = 0b R0 bool sre; // 1 bit Save/Restore Error = 0b RW1C bool rss; // 1 bit Restore State Status = 0b RO bool sss; // 1 bit Save State Status = 0b RO Bit8u RsvdZ0; // 3 bit reserved and zero'd = 0x0 RW bool pcd; // 1 bit Port Change Detect = 0b RW1C bool eint; // 1 bit Event Interrupt = 0b RW1C bool hse; // 1 bit Host System Error = 0b RW1C bool RsvdZ2; // 1 bit reserved and zero'd = 0b RW bool hch; // 1 bit HCHalted = 1b RO } HcStatus; // = 0x00000001 struct { Bit16u Rsvd; // 16 bit reserved = 0x0000 RO Bit16u pagesize; // 16 bit reserved = 0x0001 RO } HcPageSize; // = 0x00000001 struct { Bit16u RsvdP; // 16 bit reserved and presserved = 0x0000 RW bool n15; // 1 bit N15 = 0 RW bool n14; // 1 bit N14 = 0 RW bool n13; // 1 bit N13 = 0 RW bool n12; // 1 bit N12 = 0 RW bool n11; // 1 bit N11 = 0 RW bool n10; // 1 bit N10 = 0 RW bool n9; // 1 bit N9 = 0 RW bool n8; // 1 bit N8 = 0 RW bool n7; // 1 bit N7 = 0 RW bool n6; // 1 bit N6 = 0 RW bool n5; // 1 bit N5 = 0 RW bool n4; // 1 bit N4 = 0 RW bool n3; // 1 bit N3 = 0 RW bool n2; // 1 bit N2 = 0 RW bool n1; // 1 bit N1 = 0 RW bool n0; // 1 bit N0 = 0 RW } HcNotification; // = 0x00000000 struct { Bit64u crc; // 64 bit hi order address = 0x00000000 RW Bit8u RsvdP; // 2 bit reserved and preserved = 00b RW bool crr; // 1 bit Command Ring Running = 0 RO bool ca; // 1 bit Command Abort = 0 RW1S bool cs; // 1 bit Command Stop = 0 RW1S bool rcs; // 1 bit Ring Cycle State = 0 RW } HcCrcr; struct { Bit64u dcbaap; // 64 bit hi order address = 0x00000000 RW Bit8u RsvdZ; // 6 bit reserved and zero'd = 000000b RW } HcDCBAAP; struct { Bit32u RsvdP; // 22/24 bit reserved and preserved = 0x000000 RW #if ((VERSION_MAJOR == 1) && (VERSION_MINOR >= 0x10)) bool u3e; // 1 bit U3 Entry Enable = 0 RW bool cie; // 1 bit Config Info Enable = 0 RW #endif Bit8u MaxSlotsEn; // 8 bit Max Device Slots Enabled = 0x00 RW } HcConfig; } op_regs; struct { // our data usb_device_c *device; // device connected to this port bool is_usb3; // set if usb3 port, cleared if usb2 port. bool has_been_reset; // set if the port has been reset aftet powered up. struct { bool wpr; // 1 bit Warm Port Reset = 0b RW or RsvdZ bool dr; // 1 bit Device Removable = 0b RO Bit8u RsvdZ1; // 2 bit Reserved and Zero'd = 00b RW bool woe; // 1 bit Wake on Over Current Enable = 0b RW bool wde; // 1 bit Wake on Disconnect Enable = 0b RW bool wce; // 1 bit Wake on Connect Enable = 0b RW bool cas; // 1 bit Cold Attach Status = 0b RO bool cec; // 1 bit Port Config Error Change = 0b RW1C or RsvdZ bool plc; // 1 bit Port Link State Change = 0b RW1C bool prc; // 1 bit Port Reset Change = 0b RW1C bool occ; // 1 bit Over Current Change = 0b RW1C bool wrc; // 1 bit Warm Port Reset Change = 0b RW1C or RsvdZ bool pec; // 1 bit Port Enabled/Disabled Change= 0b RW1C bool csc; // 1 bit Connect Status Change = 0b RW1C bool lws; // 1 bit Port Link State Write Strobe= 0b RW Bit8u pic; // 2 bit Port Indicator Control = 00b RW Bit8u speed; // 4 bit Port Speed = 0000b RO bool pp; // 1 bit Port Power = 0b RW Bit8u pls; // 4 bit Port Link State = 0x00 RW bool pr; // 1 bit Port Reset = 0b RW bool oca; // 1 bit Over Current Active = 0b RO bool RsvdZ0; // 1 bit Reserved and Zero'd = 0b RW bool ped; // 1 bit Port Enabled/Disabled = 0b RW1C bool ccs; // 1 bit Current Connect Status = 0b RO } portsc; union { // if usb3 port struct { struct { Bit16u RsvdP; // 15 bit Reserved and Preserved = 0x0000 RW bool fla; // 1 bit Force Link PM Accept = 0x0000 RW Bit8u u2timeout; // 8 bit U2 Timeout = 0x0000 RW Bit8u u1timeout; // 8 bit U1 Timeout = 0x0000 RW } portpmsc; struct { Bit16u RsvdP; // 16 bit Reserved and Preserved = 0x0000 RW Bit16u lec; // 16 bit Link Error Count = 0x0000 RO } portli; } usb3; // if usb2 port struct { struct { Bit8u tmode; // 4 bit Test Mode = 0x0 RO Bit16u RsvdP; // 11 bit reserved and preseved = 0x000 RW bool hle; // 1 bit hardware LPM enable = 0b RW Bit8u l1dslot; // 8 bit L1 Device Slot = 0x00 RW Bit8u hird; // 4 bit Host Initiated Resume Durat = 0x0 RW bool rwe; // 1 bit Remote Wakeup Enable = 0b RW Bit8u l1s; // 3 bit L1 Status = 000b RO } portpmsc; struct { Bit32u RsvdP; // 32 bit reserved and preseved = 0x00000000 RW } portli; } usb2; }; struct { Bit8u hirdm; // 2 bit host initiated resume duration mode Bit8u l1timeout; // 8 bit L1 timeout Bit8u hirdd; // 4 bit host initiated resume duration deep Bit32u RsvdP; // 18 bit reserved and preseved = 0x00000000 RW } porthlpmc; } usb_port[USB_XHCI_PORTS]; // Extended Caps Registers Bit8u extended_caps[EXT_CAPS_SIZE]; struct XHCI_RUNTIME_REGS { struct { Bit32u RsvdP; // 18 bit reserved and preseved = 0x00000 RW Bit16u index; // 14 bit index = 0x0000 RO } mfindex; struct { struct { Bit32u RsvdP; // 30 bit reserved and preseved = 0x00000000 RW bool ie; // 1 bit Interrupt Enable = 0b RW bool ip; // 1 bit Interrupt Pending = 0b RW1C } iman; struct { Bit16u imodc; // 16 bit Interrupter Mod Counter = 0x0000 RW Bit16u imodi; // 16 bit Interrupter Mod Interval = 0x0000 RW } imod; struct { Bit16u RsvdP; // 16 bit reserved and preseved = 0x0000 RW Bit16u erstabsize; // 16 bit Event Ring Seg Table Size = 0x0000 RW } erstsz; Bit32u RsvdP; // 32 bit reserved and preseved = 0x00000000 RW struct { Bit64u erstabadd; // 64 bit Event Ring Seg Tab Addy = 0x00000000 RW (See #define below) Bit16u RsvdP; // 6 bit reserved and preseved = 0x0000 RW } erstba; struct { Bit64u eventadd; // 64 bit Event Ring Addy hi = 0x00000000 RW bool ehb; // 1 bit Event Handler Busy = 0b RW1C Bit8u desi; // 2 bit Dequeue ERST Seg Index = 00b RW } erdp; } interrupter[INTERRUPTERS]; } runtime_regs; struct HC_SLOT_CONTEXT slots[MAX_SLOTS]; // first one is ignored by controller. struct RING_MEMBERS ring_members; } bx_usb_xhci_t; // Version 3.0.23.0 of the Renesas uPD720202 driver, even though the card is // version 1.00, the driver still uses bits 3:0 as RsvdP as with version 0.96 // instead of bits 5:0 as RsvdP as with version 1.00+ #define RENESAS_ERSTABADD_BUG 1 #if ((VERSION_MAJOR < 1) || (RENESAS_ERSTABADD_BUG == 1)) #define ERSTABADD_MASK 0x0F // versions before 1.0 use 3:0 as preserved #elif ((VERSION_MAJOR == 1) && (VERSION_MINOR >= 0x00)) #define ERSTABADD_MASK 0x3F // versions 1.0 and above use 5:0 as preserved #else #error "ERSTABADD_MASK not defined" #endif class bx_usb_xhci_c : public bx_pci_device_c { public: bx_usb_xhci_c(); virtual ~bx_usb_xhci_c(); virtual void init(void); virtual void reset(unsigned); virtual void register_state(void); virtual void after_restore_state(void); virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len); void event_handler(int event, USBPacket *packet, int port); private: bx_usb_xhci_t hub; Bit8u devfunc; Bit8u device_change; int rt_conf_id; int xhci_timer_index; USBAsync *packets; static void reset_hc(); static void reset_port(int); static void reset_port_usb3(int, const int); static bool save_hc_state(void); static bool restore_hc_state(void); static void update_irq(unsigned interrupter); static void init_device(Bit8u port, bx_list_c *portconf); static void remove_device(Bit8u port); static bool usb_set_connect_status(Bit8u port, bool connected); static int broadcast_packet(USBPacket *p, const int port); static void xhci_timer_handler(void *); void xhci_timer(void); static void process_transfer_ring(const int slot, const int ep); static void process_command_ring(void); static void write_event_TRB(const unsigned interrupter, const Bit64u parameter, const Bit32u status, const Bit32u command, const bool fire_int); static Bit32u NEC_verification(const Bit64u parameter); static void init_event_ring(const unsigned interrupter); static void read_TRB(bx_phy_address addr, struct TRB *trb); static void write_TRB(bx_phy_address addr, const Bit64u parameter, const Bit32u status, const Bit32u command); static void update_slot_context(const int slot); static void update_ep_context(const int slot, const int ep); static void dump_slot_context(const Bit32u *context, const int slot); static void dump_ep_context(const Bit32u *context, const int slot, const int ep); static void copy_slot_from_buffer(struct SLOT_CONTEXT *slot_context, const Bit8u *buffer); static void copy_ep_from_buffer(struct EP_CONTEXT *ep_context, const Bit8u *buffer); static void copy_slot_to_buffer(Bit32u *buffer, const int slot); static void copy_ep_to_buffer(Bit32u *buffer, const int slot, const int ep); static bool validate_slot_context(const struct SLOT_CONTEXT *slot_context); static bool validate_ep_context(const struct EP_CONTEXT *ep_context, int speed, int ep_num); static int create_unique_address(const int slot); static int send_set_address(const int addr, const int port_num); static void dump_xhci_core(const int slots, const int eps); #if BX_USE_USB_XHCI_SMF static bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param); static bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param); #else bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param); bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param); #endif static void runtime_config_handler(void *); void runtime_config(void); static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val); static bool usb_param_enable_handler(bx_param_c *param, bool en); }; #endif // BX_IODEV_USB_XHCI_H