| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_DEVICES_USB_DRIVERS_CRG_UDC_CRG_UDC_REGS_H_ |
| #define SRC_DEVICES_USB_DRIVERS_CRG_UDC_CRG_UDC_REGS_H_ |
| |
| #include <hwreg/bitfields.h> |
| #include <usb/usb.h> |
| |
| // clang-format off |
| // transfer |
| #define TRB_TRANSFER_LEN_MASK 0x0001FFFF |
| #define TRB_TRANSFER_LEN_SHIFT 0 |
| #define TRB_TD_SIZE_MASK 0x0000001F |
| #define TRB_TD_SIZE_SHIFT 17 |
| #define TRB_INTR_TARGET_MASK 0x000003FF |
| #define TRB_INTR_TARGET_SHIFT 22 |
| |
| #define TRB_CYCLE_BIT_MASK 0x00000001 |
| #define TRB_CYCLE_BIT_SHIFT 0 |
| #define TRB_LINK_TOGGLE_CYCLE_MASK 0x00000001 |
| #define TRB_LINK_TOGGLE_CYCLE_SHIFT 1 |
| #define TRB_INTR_ON_SHORT_PKT_MASK 0x00000001 |
| #define TRB_INTR_ON_SHORT_PKT_SHIFT 2 |
| #define TRB_NO_SNOOP_MASK 0x00000001 |
| #define TRB_NO_SNOOP_SHIFT 3 |
| #define TRB_CHAIN_BIT_MASK 0x00000001 |
| #define TRB_CHAIN_BIT_SHIFT 4 |
| #define TRB_INTR_ON_COMPLETION_MASK 0x00000001 |
| #define TRB_INTR_ON_COMPLETION_SHIFT 5 |
| |
| #define TRB_APPEND_ZLP_MASK 0x00000001 |
| #define TRB_APPEND_ZLP_SHIFT 7 |
| |
| #define TRB_BLOCK_EVENT_INT_MASK 0x00000001 |
| #define TRB_BLOCK_EVENT_INT_SHIFT 9 |
| #define TRB_TYPE_MASK 0x0000003F |
| #define TRB_TYPE_SHIFT 10 |
| #define DATA_STAGE_TRB_DIR_MASK 0x00000001 |
| #define DATA_STAGE_TRB_DIR_SHIFT 16 |
| #define TRB_SETUP_TAG_MASK 0x00000003 |
| #define TRB_SETUP_TAG_SHIFT 17 |
| #define STATUS_STAGE_TRB_STALL_MASK 0x00000001 |
| #define STATUS_STAGE_TRB_STALL_SHIFT 19 |
| #define STATUS_STAGE_TRB_SET_ADDR_MASK 0x00000001 |
| #define STATUS_STAGE_TRB_SET_ADDR_SHIFT 20 |
| |
| #define ISOC_TRB_FRAME_ID_MASK 0x000007FF |
| #define ISOC_TRB_FRAME_ID_SHIFT 20 |
| #define ISOC_TRB_SIA_MASK 0x00000001 |
| #define ISOC_TRB_SIA_SHIFT 31 |
| |
| // event |
| #define EVE_TRB_TRAN_LEN_MASK 0x0001FFFF |
| #define EVE_TRB_TRAN_LEN_SHIFT 0 |
| #define EVE_TRB_COMPL_CODE_MASK 0x000000FF |
| #define EVE_TRB_COMPL_CODE_SHIFT 24 |
| #define EVE_TRB_CYCLE_BIT_MASK 0x00000001 |
| #define EVE_TRB_CYCLE_BIT_SHIFT 0 |
| #define EVE_TRB_TYPE_MASK 0x0000003F |
| #define EVE_TRB_TYPE_SHIFT 10 |
| #define EVE_TRB_ENDPOINT_ID_MASK 0x0000001F |
| #define EVE_TRB_ENDPOINT_ID_SHIFT 16 |
| #define EVE_TRB_SETUP_TAG_MASK 0x00000003 |
| #define EVE_TRB_SETUP_TAG_SHIFT 21 |
| |
| // endpoint context |
| #define EP_CX_LOGICAL_EP_NUM_MASK 0x0000000F |
| #define EP_CX_LOGICAL_EP_NUM_SHIFT 3 |
| #define EP_CX_INTERVAL_MASK 0x000000FF |
| #define EP_CX_INTERVAL_SHIFT 16 |
| #define EP_CX_EP_TYPE_MASK 0x00000007 |
| #define EP_CX_EP_TYPE_SHIFT 3 |
| #define EP_CX_MAX_BURST_SIZE_MASK 0x000000FF |
| #define EP_CX_MAX_BURST_SIZE_SHIFT 8 |
| #define EP_CX_MAX_PACKET_SIZE_MASK 0x0000FFFF |
| #define EP_CX_MAX_PACKET_SIZE_SHIFT 16 |
| #define EP_CX_DEQ_CYC_STATE_MASK 0x00000001 |
| #define EP_CX_DEQ_CYC_STATE_SHIFT 0 |
| #define EP_CX_TR_DQPT_LO_MASK 0xFFFFFFF0 |
| #define EP_CX_TR_DQPT_LO_SHIFT 4 |
| // clang-format on |
| |
| // converts a USB endpoint address to 2 - 31 index |
| constexpr uint8_t CRG_UDC_ADDR_TO_INDEX(uint8_t addr) { |
| // | 31 | 30 | ...... | 3 | 2 | 1 | 0 | |
| // |IEP15|OEP15| ...... |IEP1|OEP1|reserved|EP0| |
| // |
| // OEP: Outbound EP (EP_IN from Host perspective) |
| // IEP: Inbound EP (EP_OUT from Host perspective) |
| return static_cast<uint8_t>((2 * (addr & 0xF)) + ((addr & USB_DIR_IN) ? 0 : 1)); |
| } |
| // Refer the above table, the direction is from the perspective of USB host, |
| // On the perspective of USB device, we should reverse the direction. |
| constexpr bool CRG_UDC_EP_IS_OUT(uint8_t ep) { return ((ep % 2) != 0); } |
| |
| // CRG UDC |
| constexpr uint32_t CTRL_REQ_QUEUE_DEPTH = 5; |
| |
| constexpr uint32_t CRG_UDC_MAX_EPS = 32; |
| constexpr uint32_t CRG_UCCR_OFFSET = 0x2400; |
| constexpr uint32_t CRG_UICR_OFFSET = 0x2500; |
| |
| constexpr uint32_t CRG_UDC_EVENT_RING_NUM = 1; |
| constexpr uint32_t CRG_UDC_EVENT_TRB_NUM = 256; |
| constexpr uint32_t CRG_CONTROL_EP_TD_RING_SIZE = 16; |
| constexpr uint32_t CRG_BULK_EP_TD_RING_SIZE = 32; |
| constexpr uint32_t CRG_ISOC_EP_TD_RING_SIZE = 32; |
| constexpr uint32_t CRG_INT_EP_TD_RING_SIZE = 8; |
| |
| constexpr uint32_t CRG_U3DC_PORTSC_SPEED_FS = 0x1; |
| constexpr uint32_t CRG_U3DC_PORTSC_SPEED_LS = 0x2; |
| constexpr uint32_t CRG_U3DC_PORTSC_SPEED_HS = 0x3; |
| constexpr uint32_t CRG_U3DC_PORTSC_SPEED_SS = 0x4; |
| constexpr uint32_t CRG_U3DC_PORTSC_SPEED_SSP = 0x5; |
| |
| constexpr uint32_t TRB_MAX_BUFFER_SIZE = 65536; |
| constexpr uint32_t CRGUDC_CONTROL_EP_TD_RING_SIZE = 16; |
| constexpr uint32_t CRGUDC_BULK_EP_TD_RING_SIZE = 16; |
| constexpr uint32_t CRGUDC_ISOC_EP_TD_RING_SIZE = 16; |
| constexpr uint32_t CRGUDC_INT_EP_TD_RING_SIZE = 16; |
| |
| // TRB type |
| constexpr uint32_t TRB_TYPE_XFER_NORMAL = 1; |
| constexpr uint32_t TRB_TYPE_XFER_DATA_STAGE = 3; |
| constexpr uint32_t TRB_TYPE_XFER_STATUS_STAGE = 4; |
| constexpr uint32_t TRB_TYPE_XFER_DATA_ISOCH = 5; |
| constexpr uint32_t TRB_TYPE_LINK = 6; |
| constexpr uint32_t TRB_TYPE_EVT_TRANSFER = 32; |
| constexpr uint32_t TRB_TYPE_EVT_CMD_COMP = 33; |
| constexpr uint32_t TRB_TYPE_EVT_PORT_STATUS_CHANGE = 34; |
| constexpr uint32_t TRB_TYPE_EVT_MFINDEX_WRAP = 39; |
| constexpr uint32_t TRB_TYPE_EVT_SETUP_PKT = 40; |
| |
| // EP type |
| constexpr uint32_t EP_TYPE_INVALID = 0; |
| constexpr uint32_t EP_TYPE_ISOCH_OUTBOUND = 1; |
| constexpr uint32_t EP_TYPE_BULK_OUTBOUND = 2; |
| constexpr uint32_t EP_TYPE_INTR_OUTBOUND = 3; |
| constexpr uint32_t EP_TYPE_INVALID2 = 4; |
| constexpr uint32_t EP_TYPE_ISOCH_INBOUND = 5; |
| constexpr uint32_t EP_TYPE_BULK_INBOUND = 6; |
| constexpr uint32_t EP_TYPE_INTR_INBOUND = 7; |
| |
| constexpr uint32_t LOWER_32_BITS(uint64_t x) { return static_cast<uint32_t>(x); } |
| constexpr uint32_t UPPER_32_BITS(uint64_t x) { return static_cast<uint32_t>((x >> 16) >> 16); } |
| |
| class CAPABILITY : public hwreg::RegisterBase<CAPABILITY, uint32_t> { |
| public: |
| DEF_FIELD(7, 0, version); |
| DEF_FIELD(11, 8, ep_in_num); |
| DEF_FIELD(15, 12, ep_out_num); |
| DEF_FIELD(26, 16, max_int); |
| DEF_BIT(27, gen1_support); |
| DEF_BIT(1, gen2_support); |
| DEF_BIT(2, isoch_support); |
| static auto Get() { return hwreg::RegisterAddr<CAPABILITY>(CRG_UCCR_OFFSET + 0x0); } |
| }; |
| |
| class CONFIG0 : public hwreg::RegisterBase<CONFIG0, uint32_t> { |
| public: |
| DEF_FIELD(3, 0, max_speed); |
| DEF_FIELD(7, 4, usb3_dis_count_limit); |
| static auto Get() { return hwreg::RegisterAddr<CONFIG0>(CRG_UCCR_OFFSET + 0x10); } |
| }; |
| |
| class CONFIG1 : public hwreg::RegisterBase<CONFIG1, uint32_t> { |
| public: |
| DEF_BIT(0, csc_event_en); |
| DEF_BIT(1, pec_event_en); |
| DEF_BIT(3, ppc_event_en); |
| DEF_BIT(4, prc_event_en); |
| DEF_BIT(5, plc_event_en); |
| DEF_BIT(6, cec_event_en); |
| DEF_BIT(8, u3_entry_plc_en); |
| DEF_BIT(9, l1_entry_plc_en); |
| DEF_BIT(10, u3_resume_plc_en); |
| DEF_BIT(11, l1_resume_plc_en); |
| DEF_BIT(12, inactive_plc_en); |
| DEF_BIT(13, usb3_resume_no_response_plc_en); |
| DEF_BIT(14, usb2_resume_no_response_plc_en); |
| DEF_BIT(16, setup_event_en); |
| DEF_BIT(17, stopped_len_invalid_event_en); |
| DEF_BIT(18, halted_len_invalid_event_en); |
| DEF_BIT(19, disabled_len_invalid_event_en); |
| DEF_BIT(20, disabled_event_en); |
| static auto Get() { return hwreg::RegisterAddr<CONFIG1>(CRG_UCCR_OFFSET + 0x14); } |
| }; |
| |
| class COMMAND : public hwreg::RegisterBase<COMMAND, uint32_t> { |
| public: |
| DEF_BIT(0, start); |
| DEF_BIT(1, soft_reset); |
| DEF_BIT(2, interrupt_en); |
| DEF_BIT(3, sys_err_en); |
| DEF_BIT(10, ewe); // Enable MFINDEX Wrap Event whenever MFINDEX transitions from 3FFFh to 0 |
| DEF_BIT(11, keep_connect); |
| static auto Get() { return hwreg::RegisterAddr<COMMAND>(CRG_UCCR_OFFSET + 0x20); } |
| }; |
| |
| class STATUS : public hwreg::RegisterBase<STATUS, uint32_t> { |
| public: |
| DEF_BIT(0, controller_halted); |
| DEF_BIT(2, sys_err); |
| DEF_BIT(3, eint); |
| DEF_BIT(12, controller_idle); |
| static auto Get() { return hwreg::RegisterAddr<STATUS>(CRG_UCCR_OFFSET + 0x24); } |
| }; |
| |
| // Device Context Base Address Pointer Low |
| class DCBAPLO : public hwreg::RegisterBase<DCBAPLO, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, dcbap_lo); |
| static auto Get() { return hwreg::RegisterAddr<DCBAPLO>(CRG_UCCR_OFFSET + 0x28); } |
| }; |
| |
| // Device Context Base Address Pointer High |
| class DCBAPHI : public hwreg::RegisterBase<DCBAPHI, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, dcbap_hi); |
| static auto Get() { return hwreg::RegisterAddr<DCBAPHI>(CRG_UCCR_OFFSET + 0x2c); } |
| }; |
| |
| // Port Status and Control Register |
| class PORTSC : public hwreg::RegisterBase<PORTSC, uint32_t> { |
| public: |
| DEF_BIT(0, ccs); |
| DEF_BIT(3, pp); |
| DEF_BIT(4, pr); |
| DEF_FIELD(8, 5, pls); |
| DEF_FIELD(13, 10, speed); |
| DEF_BIT(16, lws); |
| DEF_BIT(17, csc); |
| DEF_BIT(20, ppc); |
| DEF_BIT(21, prc); |
| DEF_BIT(22, plc); |
| DEF_BIT(23, cec); |
| DEF_BIT(25, wce); |
| DEF_BIT(26, wde); |
| DEF_BIT(31, wpr); |
| static auto Get() { return hwreg::RegisterAddr<PORTSC>(CRG_UCCR_OFFSET + 0x30); } |
| }; |
| |
| class U3PORTPMSC : public hwreg::RegisterBase<U3PORTPMSC, uint32_t> { |
| public: |
| DEF_FIELD(7, 0, u1_timeout); |
| DEF_FIELD(15, 8, u2_timeout); |
| DEF_BIT(16, fla); |
| DEF_BIT(20, u1_initiate_en); |
| DEF_BIT(21, u2_initiate_en); |
| DEF_BIT(22, u1_accept_en); |
| DEF_BIT(23, u2_accept_en); |
| DEF_FIELD(31, 24, u12u2_timeout); |
| static auto Get() { return hwreg::RegisterAddr<U3PORTPMSC>(CRG_UCCR_OFFSET + 0x34); } |
| }; |
| |
| class U2PORTPMSC : public hwreg::RegisterBase<U2PORTPMSC, uint32_t> { |
| public: |
| DEF_FIELD(3, 0, reject_threshold); |
| DEF_FIELD(7, 4, deepsleep_threshold); |
| DEF_BIT(8, lpm_en); |
| DEF_BIT(9, reject_threshold_en); |
| DEF_BIT(10, deepsleep_en); |
| DEF_BIT(11, sleep_en); |
| DEF_BIT(12, plm_force_ack); |
| DEF_BIT(13, l1_auto_exit_en); |
| DEF_FIELD(19, 16, hird_besl); |
| DEF_BIT(20, rwe); |
| DEF_FIELD(31, 28, test_mode); |
| static auto Get() { return hwreg::RegisterAddr<U2PORTPMSC>(CRG_UCCR_OFFSET + 0x38); } |
| }; |
| |
| class U3PORTLI : public hwreg::RegisterBase<U3PORTLI, uint32_t> { |
| public: |
| DEF_FIELD(15, 0, link_err_count); |
| static auto Get() { return hwreg::RegisterAddr<U3PORTLI>(CRG_UCCR_OFFSET + 0x3c); } |
| }; |
| |
| class DOORBELL : public hwreg::RegisterBase<DOORBELL, uint32_t> { |
| public: |
| DEF_FIELD(4, 0, db_target); |
| static auto Get() { return hwreg::RegisterAddr<DOORBELL>(CRG_UCCR_OFFSET + 0x40); } |
| }; |
| |
| class MFINDEX : public hwreg::RegisterBase<MFINDEX, uint32_t> { |
| public: |
| DEF_BIT(0, sync_en); |
| DEF_BIT(1, sync_interrupt_en); |
| DEF_BIT(2, in_sync); |
| DEF_BIT(3, sync_detected); |
| DEF_FIELD(17, 4, mfindex); |
| DEF_FIELD(30, 18, mfoffset); |
| static auto Get() { return hwreg::RegisterAddr<MFINDEX>(CRG_UCCR_OFFSET + 0x44); } |
| }; |
| |
| class PTMCR : public hwreg::RegisterBase<PTMCR, uint32_t> { |
| public: |
| DEF_FIELD(13, 0, ptm_delay); |
| static auto Get() { return hwreg::RegisterAddr<PTMCR>(CRG_UCCR_OFFSET + 0x48); } |
| }; |
| |
| class PTMSR : public hwreg::RegisterBase<PTMSR, uint32_t> { |
| public: |
| DEF_BIT(2, in_sync); |
| DEF_FIELD(17, 4, mfindex); |
| DEF_FIELD(30, 18, mfoffset); |
| static auto Get() { return hwreg::RegisterAddr<PTMSR>(CRG_UCCR_OFFSET + 0x4c); } |
| }; |
| |
| class EPENABLED : public hwreg::RegisterBase<EPENABLED, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, ep_enabled); |
| static auto Get() { return hwreg::RegisterAddr<EPENABLED>(CRG_UCCR_OFFSET + 0x60); } |
| }; |
| |
| class EPRUN : public hwreg::RegisterBase<EPRUN, uint32_t> { |
| public: |
| DEF_FIELD(31, 2, ep_running); |
| static auto Get() { return hwreg::RegisterAddr<EPRUN>(CRG_UCCR_OFFSET + 0x64); } |
| }; |
| |
| class CMDPARA0 : public hwreg::RegisterBase<CMDPARA0, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, cmd_para0); |
| static auto Get() { return hwreg::RegisterAddr<CMDPARA0>(CRG_UCCR_OFFSET + 0x70); } |
| }; |
| |
| class CMDPARA1 : public hwreg::RegisterBase<CMDPARA1, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, cmd_para1); |
| static auto Get() { return hwreg::RegisterAddr<CMDPARA1>(CRG_UCCR_OFFSET + 0x74); } |
| }; |
| |
| class CMDCTRL : public hwreg::RegisterBase<CMDCTRL, uint32_t> { |
| public: |
| DEF_BIT(0, cmd_active); |
| DEF_BIT(1, cmd_ioc); |
| DEF_FIELD(7, 4, cmd_type); |
| DEF_FIELD(19, 16, cmd_status); |
| static auto Get() { return hwreg::RegisterAddr<CMDCTRL>(CRG_UCCR_OFFSET + 0x78); } |
| }; |
| |
| // ODB Capability Register |
| class ODBCAP : public hwreg::RegisterBase<ODBCAP, uint32_t> { |
| public: |
| DEF_FIELD(10, 0, odb_ram_size); |
| static auto Get() { return hwreg::RegisterAddr<ODBCAP>(CRG_UCCR_OFFSET + 0x80); } |
| }; |
| |
| class ODBCFG : public hwreg::RegisterBase<ODBCFG, uint32_t> { |
| public: |
| DEF_FIELD(9, 0, epn_offset); |
| DEF_FIELD(12, 10, epn_size); |
| DEF_FIELD(25, 16, epn_add1_offset); |
| DEF_FIELD(28, 26, epn_add1_size); |
| static auto Get() { return hwreg::RegisterAddr<ODBCFG>(CRG_UCCR_OFFSET + 0x90); } |
| }; |
| |
| class DEBUG0 : public hwreg::RegisterBase<DEBUG0, uint32_t> { |
| public: |
| DEF_FIELD(6, 0, dev_addr); |
| DEF_FIELD(11, 8, nump_limit); |
| static auto Get() { return hwreg::RegisterAddr<DEBUG0>(CRG_UCCR_OFFSET + 0xb0); } |
| }; |
| |
| class IMAN : public hwreg::RegisterBase<IMAN, uint32_t> { |
| public: |
| DEF_BIT(0, ip); |
| DEF_BIT(1, ie); |
| static auto Get() { return hwreg::RegisterAddr<IMAN>(CRG_UICR_OFFSET + 0x0); } |
| }; |
| |
| class IMOD : public hwreg::RegisterBase<IMOD, uint32_t> { |
| public: |
| DEF_FIELD(15, 0, imodi); |
| DEF_FIELD(31, 16, imodc); |
| static auto Get() { return hwreg::RegisterAddr<IMOD>(CRG_UICR_OFFSET + 0x4); } |
| }; |
| |
| class ERSTSZ : public hwreg::RegisterBase<ERSTSZ, uint32_t> { |
| public: |
| DEF_FIELD(15, 0, erstsz); |
| static auto Get() { return hwreg::RegisterAddr<ERSTSZ>(CRG_UICR_OFFSET + 0x8); } |
| }; |
| |
| class ERSTBALO : public hwreg::RegisterBase<ERSTBALO, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, erstba_lo); |
| static auto Get() { return hwreg::RegisterAddr<ERSTBALO>(CRG_UICR_OFFSET + 0x10); } |
| }; |
| |
| class ERSTBAHI : public hwreg::RegisterBase<ERSTBAHI, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, erstba_hi); |
| static auto Get() { return hwreg::RegisterAddr<ERSTBAHI>(CRG_UICR_OFFSET + 0x14); } |
| }; |
| |
| class ERDPLO : public hwreg::RegisterBase<ERDPLO, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, erdp_lo); |
| static auto Get() { return hwreg::RegisterAddr<ERDPLO>(CRG_UICR_OFFSET + 0x18); } |
| }; |
| |
| class ERDPHI : public hwreg::RegisterBase<ERDPHI, uint32_t> { |
| public: |
| DEF_FIELD(31, 0, erdp_hi); |
| static auto Get() { return hwreg::RegisterAddr<ERDPHI>(CRG_UICR_OFFSET + 0x1c); } |
| }; |
| |
| #endif // SRC_DEVICES_USB_DRIVERS_CRG_UDC_CRG_UDC_REGS_H_ |