mirror of
https://github.com/CTCaer/hekate
synced 2024-12-22 11:21:23 +00:00
xusb: update driver
- Better port init/status - Correct port status report - Add babble detection and rescue - Some refactoring
This commit is contained in:
parent
4914ce1d49
commit
1afb1a50c3
3 changed files with 175 additions and 89 deletions
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Enhanced & eXtensible USB device (EDCI & XDCI) driver for Tegra X1
|
* Enhanced & eXtensible USB device (EDCI & XDCI) driver for Tegra X1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 CTCaer
|
* Copyright (c) 2019-2021 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -200,6 +200,8 @@ typedef struct _t210_usb2d_t
|
||||||
#define XHCI_ST_IP BIT(4)
|
#define XHCI_ST_IP BIT(4)
|
||||||
#define XUSB_DEV_XHCI_RT_IMOD 0x38
|
#define XUSB_DEV_XHCI_RT_IMOD 0x38
|
||||||
#define XUSB_DEV_XHCI_PORTSC 0x3C
|
#define XUSB_DEV_XHCI_PORTSC 0x3C
|
||||||
|
#define XHCI_PORTSC_CCS BIT(0)
|
||||||
|
#define XHCI_PORTSC_PED BIT(1)
|
||||||
#define XHCI_PORTSC_PR BIT(4)
|
#define XHCI_PORTSC_PR BIT(4)
|
||||||
#define XHCI_PORTSC_PLS_MASK (0xF << 5)
|
#define XHCI_PORTSC_PLS_MASK (0xF << 5)
|
||||||
#define XHCI_PORTSC_PLS_U0 (0 << 5)
|
#define XHCI_PORTSC_PLS_U0 (0 << 5)
|
||||||
|
@ -226,11 +228,12 @@ typedef struct _t210_usb2d_t
|
||||||
#define XUSB_DEV_XHCI_ECPLO 0x40
|
#define XUSB_DEV_XHCI_ECPLO 0x40
|
||||||
#define XUSB_DEV_XHCI_ECPHI 0x44
|
#define XUSB_DEV_XHCI_ECPHI 0x44
|
||||||
#define XUSB_DEV_XHCI_EP_HALT 0x50
|
#define XUSB_DEV_XHCI_EP_HALT 0x50
|
||||||
#define XHCI_EP_HALT_DCI BIT(0)
|
#define XHCI_EP_HALT_DCI_EP0_IN BIT(0)
|
||||||
#define XUSB_DEV_XHCI_EP_PAUSE 0x54
|
#define XUSB_DEV_XHCI_EP_PAUSE 0x54
|
||||||
#define XUSB_DEV_XHCI_EP_RELOAD 0x58
|
#define XUSB_DEV_XHCI_EP_RELOAD 0x58
|
||||||
#define XUSB_DEV_XHCI_EP_STCHG 0x5C
|
#define XUSB_DEV_XHCI_EP_STCHG 0x5C
|
||||||
#define XUSB_DEV_XHCI_PORTHALT 0x6C
|
#define XUSB_DEV_XHCI_PORTHALT 0x6C
|
||||||
|
#define XUSB_DEV_XHCI_EP_STOPPED 0x78
|
||||||
#define XHCI_PORTHALT_HALT_LTSSM BIT(0)
|
#define XHCI_PORTHALT_HALT_LTSSM BIT(0)
|
||||||
#define XHCI_PORTHALT_STCHG_REQ BIT(20)
|
#define XHCI_PORTHALT_STCHG_REQ BIT(20)
|
||||||
#define XUSB_DEV_XHCI_CFG_DEV_FE 0x85C
|
#define XUSB_DEV_XHCI_CFG_DEV_FE 0x85C
|
||||||
|
|
|
@ -148,6 +148,7 @@ typedef enum _usb_error_t
|
||||||
XUSB_ERROR_INVALID_EP = USB_ERROR_XFER_ERROR, // From 2.
|
XUSB_ERROR_INVALID_EP = USB_ERROR_XFER_ERROR, // From 2.
|
||||||
XUSB_ERROR_XFER_BULK_IN_RESIDUE = 7,
|
XUSB_ERROR_XFER_BULK_IN_RESIDUE = 7,
|
||||||
XUSB_ERROR_INVALID_CYCLE = USB2_ERROR_XFER_EP_DISABLED, // From 8.
|
XUSB_ERROR_INVALID_CYCLE = USB2_ERROR_XFER_EP_DISABLED, // From 8.
|
||||||
|
XUSB_ERROR_BABBLE_DETECTED = 50,
|
||||||
XUSB_ERROR_SEQ_NUM = 51,
|
XUSB_ERROR_SEQ_NUM = 51,
|
||||||
XUSB_ERROR_XFER_DIR = 52,
|
XUSB_ERROR_XFER_DIR = 52,
|
||||||
XUSB_ERROR_PORT_CFG = 54
|
XUSB_ERROR_PORT_CFG = 54
|
||||||
|
|
256
bdk/usb/xusbd.c
256
bdk/usb/xusbd.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* eXtensible USB Device driver (XDCI) for Tegra X1
|
* eXtensible USB Device driver (XDCI) for Tegra X1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2020 CTCaer
|
* Copyright (c) 2020-2021 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -368,7 +368,7 @@ typedef struct _xusbd_controller_t
|
||||||
event_trb_t *event_dequeue_ptr;
|
event_trb_t *event_dequeue_ptr;
|
||||||
u32 event_ccs;
|
u32 event_ccs;
|
||||||
u32 device_state;
|
u32 device_state;
|
||||||
u32 bytes_remaining[2];
|
u32 tx_bytes[2];
|
||||||
u32 tx_count[2];
|
u32 tx_count[2];
|
||||||
u32 ctrl_seq_num;
|
u32 ctrl_seq_num;
|
||||||
u32 config_num;
|
u32 config_num;
|
||||||
|
@ -881,7 +881,7 @@ int xusb_device_init()
|
||||||
_xusbd_init_device_clocks();
|
_xusbd_init_device_clocks();
|
||||||
|
|
||||||
// Enable AHB redirect for access to IRAM for Event/EP ring buffers.
|
// Enable AHB redirect for access to IRAM for Event/EP ring buffers.
|
||||||
mc_enable_ahb_redirect(); // Can be skipped if IRAM is not used.
|
mc_enable_ahb_redirect(false); // Can be skipped if IRAM is not used.
|
||||||
|
|
||||||
// Enable XUSB device IPFS.
|
// Enable XUSB device IPFS.
|
||||||
XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI;
|
XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI;
|
||||||
|
@ -927,7 +927,7 @@ int xusb_device_init()
|
||||||
return USB_RES_OK;
|
return USB_RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _xusb_queue_trb(int ep_idx, void *trb, bool ring_doorbell)
|
static int _xusb_queue_trb(u32 ep_idx, void *trb, bool ring_doorbell)
|
||||||
{
|
{
|
||||||
int res = USB_RES_OK;
|
int res = USB_RES_OK;
|
||||||
data_trb_t *next_trb;
|
data_trb_t *next_trb;
|
||||||
|
@ -1073,7 +1073,7 @@ static int _xusb_issue_normal_trb(u8 *buf, u32 len, usb_dir_t direction)
|
||||||
normal_trb_t trb = {0};
|
normal_trb_t trb = {0};
|
||||||
|
|
||||||
_xusb_create_normal_trb(&trb, buf, len, direction);
|
_xusb_create_normal_trb(&trb, buf, len, direction);
|
||||||
int ep_idx = USB_EP_BULK_IN;
|
u32 ep_idx = USB_EP_BULK_IN;
|
||||||
if (direction == USB_DIR_OUT)
|
if (direction == USB_DIR_OUT)
|
||||||
ep_idx = USB_EP_BULK_OUT;
|
ep_idx = USB_EP_BULK_OUT;
|
||||||
int res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL);
|
int res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL);
|
||||||
|
@ -1100,19 +1100,32 @@ static int _xusb_issue_data_trb(u8 *buf, u32 len, usb_dir_t direction)
|
||||||
|
|
||||||
int xusb_set_ep_stall(u32 endpoint, int ep_stall)
|
int xusb_set_ep_stall(u32 endpoint, int ep_stall)
|
||||||
{
|
{
|
||||||
int ep_idx = BIT(endpoint);
|
u32 ep_mask = BIT(endpoint);
|
||||||
if (ep_stall)
|
if (ep_stall)
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_idx;
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask;
|
||||||
else
|
else
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_idx;
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_mask;
|
||||||
|
|
||||||
// Wait for EP status to change.
|
// Wait for EP status to change.
|
||||||
int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_idx, ep_idx, 1000);
|
int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
// Clear status change.
|
// Clear status change.
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_idx;
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask;
|
||||||
|
|
||||||
|
return USB_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _xusb_wait_ep_stopped(u32 endpoint)
|
||||||
|
{
|
||||||
|
u32 ep_mask = BIT(endpoint);
|
||||||
|
|
||||||
|
// Wait for EP status to change.
|
||||||
|
_xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STOPPED, ep_mask, ep_mask, 1000);
|
||||||
|
|
||||||
|
// Clear status change.
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STOPPED) = ep_mask;
|
||||||
|
|
||||||
return USB_RES_OK;
|
return USB_RES_OK;
|
||||||
}
|
}
|
||||||
|
@ -1158,20 +1171,27 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
|
||||||
return _xusb_issue_status_trb(USB_DIR_OUT);
|
return _xusb_issue_status_trb(USB_DIR_OUT);
|
||||||
else if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS)
|
else if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS)
|
||||||
{
|
{
|
||||||
if (usbd_xotg->device_state == XUSB_ADDRESSED_STS_WAIT)
|
switch (usbd_xotg->device_state)
|
||||||
|
{
|
||||||
|
case XUSB_ADDRESSED_STS_WAIT:
|
||||||
usbd_xotg->device_state = XUSB_ADDRESSED;
|
usbd_xotg->device_state = XUSB_ADDRESSED;
|
||||||
else if (usbd_xotg->device_state == XUSB_CONFIGURED_STS_WAIT)
|
break;
|
||||||
|
case XUSB_CONFIGURED_STS_WAIT:
|
||||||
usbd_xotg->device_state = XUSB_CONFIGURED;
|
usbd_xotg->device_state = XUSB_CONFIGURED;
|
||||||
else if (usbd_xotg->device_state == XUSB_LUN_CONFIGURED_STS_WAIT)
|
break;
|
||||||
|
case XUSB_LUN_CONFIGURED_STS_WAIT:
|
||||||
usbd_xotg->device_state = XUSB_LUN_CONFIGURED;
|
usbd_xotg->device_state = XUSB_LUN_CONFIGURED;
|
||||||
else if (usbd_xotg->device_state == XUSB_HID_CONFIGURED_STS_WAIT)
|
break;
|
||||||
|
case XUSB_HID_CONFIGURED_STS_WAIT:
|
||||||
usbd_xotg->device_state = XUSB_HID_CONFIGURED;
|
usbd_xotg->device_state = XUSB_HID_CONFIGURED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_EP_BULK_IN:
|
case USB_EP_BULK_IN:
|
||||||
usbd_xotg->bytes_remaining[USB_DIR_IN] -= trb->trb_tx_len;
|
usbd_xotg->tx_bytes[USB_DIR_IN] -= trb->trb_tx_len;
|
||||||
if (usbd_xotg->tx_count[USB_DIR_IN])///////////
|
if (usbd_xotg->tx_count[USB_DIR_IN])
|
||||||
usbd_xotg->tx_count[USB_DIR_IN]--;
|
usbd_xotg->tx_count[USB_DIR_IN]--;
|
||||||
|
|
||||||
// If bytes remaining for a Bulk IN transfer, return error.
|
// If bytes remaining for a Bulk IN transfer, return error.
|
||||||
|
@ -1181,8 +1201,8 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
|
||||||
|
|
||||||
case USB_EP_BULK_OUT:
|
case USB_EP_BULK_OUT:
|
||||||
// If short packet and Bulk OUT, it's not an error because we prime EP for 4KB.
|
// If short packet and Bulk OUT, it's not an error because we prime EP for 4KB.
|
||||||
usbd_xotg->bytes_remaining[USB_DIR_OUT] -= trb->trb_tx_len;
|
usbd_xotg->tx_bytes[USB_DIR_OUT] -= trb->trb_tx_len;
|
||||||
if (usbd_xotg->tx_count[USB_DIR_OUT])///////////
|
if (usbd_xotg->tx_count[USB_DIR_OUT])
|
||||||
usbd_xotg->tx_count[USB_DIR_OUT]--;
|
usbd_xotg->tx_count[USB_DIR_OUT]--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1196,6 +1216,11 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
|
||||||
xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL);
|
xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL);
|
||||||
return USB_RES_OK;
|
return USB_RES_OK;
|
||||||
*/
|
*/
|
||||||
|
case XUSB_COMP_BABBLE_DETECTED_ERROR:
|
||||||
|
_xusb_wait_ep_stopped(trb->ep_id);
|
||||||
|
xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL);
|
||||||
|
return XUSB_ERROR_BABBLE_DETECTED;
|
||||||
|
|
||||||
case XUSB_COMP_CTRL_DIR_ERROR:
|
case XUSB_COMP_CTRL_DIR_ERROR:
|
||||||
return XUSB_ERROR_XFER_DIR;
|
return XUSB_ERROR_XFER_DIR;
|
||||||
|
|
||||||
|
@ -1216,11 +1241,52 @@ static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
|
||||||
|
|
||||||
static int _xusb_handle_port_change()
|
static int _xusb_handle_port_change()
|
||||||
{
|
{
|
||||||
u32 res = USB_RES_OK;
|
|
||||||
u32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
u32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
||||||
u32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);
|
u32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);
|
||||||
|
u32 clear_mask = XHCI_PORTSC_CEC | XHCI_PORTSC_PLC | XHCI_PORTSC_PRC | XHCI_PORTSC_WRC | XHCI_PORTSC_CSC;
|
||||||
|
|
||||||
// Connect status change (CSC).
|
// Port reset (PR).
|
||||||
|
if (status & XHCI_PORTSC_PR)
|
||||||
|
{
|
||||||
|
//! TODO:
|
||||||
|
// XHCI_PORTSC_PR: device_state = XUSB_RESET
|
||||||
|
|
||||||
|
//_disable_usb_wdt4();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Port Reset Change (PRC).
|
||||||
|
if (status & XHCI_PORTSC_PRC)
|
||||||
|
{
|
||||||
|
// Clear PRC bit.
|
||||||
|
status &= ~clear_mask;
|
||||||
|
status |= XHCI_PORTSC_PRC;
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warm Port Reset (WPR).
|
||||||
|
if (status & XHCI_PORTSC_WPR)
|
||||||
|
{
|
||||||
|
//_disable_usb_wdt4();
|
||||||
|
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;
|
||||||
|
(void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);
|
||||||
|
|
||||||
|
//! TODO: XHCI_PORTSC_WPR: device_state = XUSB_RESET
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warm Port Reset Change (WRC).
|
||||||
|
if (status & XHCI_PORTSC_WRC)
|
||||||
|
{
|
||||||
|
// Clear WRC bit.
|
||||||
|
status &= ~clear_mask;
|
||||||
|
status |= XHCI_PORTSC_WRC;
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reread port status to handle more changes.
|
||||||
|
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
||||||
|
|
||||||
|
// Connect Status Change (CSC).
|
||||||
if (status & XHCI_PORTSC_CSC)
|
if (status & XHCI_PORTSC_CSC)
|
||||||
{
|
{
|
||||||
//! TODO: Check CCS.
|
//! TODO: Check CCS.
|
||||||
|
@ -1238,90 +1304,64 @@ static int _xusb_handle_port_change()
|
||||||
volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN];
|
volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN];
|
||||||
ep_ctxt->avg_trb_len = 8;
|
ep_ctxt->avg_trb_len = 8;
|
||||||
ep_ctxt->max_packet_size = 64;
|
ep_ctxt->max_packet_size = 64;
|
||||||
|
//! TODO: If super speed is supported, ep context reload, unpause and unhalt must happen.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear CSC bit.
|
// Clear CSC bit.
|
||||||
|
status &= ~clear_mask;
|
||||||
status |= XHCI_PORTSC_CSC;
|
status |= XHCI_PORTSC_CSC;
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port reset (PR), Port reset change (PRC).
|
|
||||||
if (status & XHCI_PORTSC_PR || status & XHCI_PORTSC_PRC)
|
|
||||||
{
|
|
||||||
//! TODO:
|
|
||||||
// XHCI_PORTSC_PR: device_state = XUSB_RESET
|
|
||||||
|
|
||||||
//_disable_usb_wdt4();
|
|
||||||
|
|
||||||
//res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // unpatched0
|
|
||||||
// if (res) return res;
|
|
||||||
_xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_PRC, XHCI_PORTSC_PRC, 50000); // patched0
|
|
||||||
|
|
||||||
// Clear PRC bit.
|
|
||||||
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PRC;
|
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PRC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warm Port Reset (WPR), Warm Port Reset Change (WRC).
|
|
||||||
if (status & XHCI_PORTSC_WPR || status & XHCI_PORTSC_WRC)
|
|
||||||
{
|
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;
|
|
||||||
(void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
|
||||||
res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_PORTSC, XHCI_PORTSC_WRC, XHCI_PORTSC_WRC, 1000);
|
|
||||||
|
|
||||||
// Clear WRC bit.
|
|
||||||
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_WRC;
|
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_WRC;
|
|
||||||
|
|
||||||
//! TODO: WPR: device_state = XUSB_RESET
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Config Request (STCHG_REQ).
|
// Handle Config Request (STCHG_REQ).
|
||||||
if (halt & XHCI_PORTHALT_STCHG_REQ)
|
if (halt & XHCI_PORTHALT_STCHG_REQ)
|
||||||
{
|
{
|
||||||
// Clear Link Training Status.
|
// Clear Link Training Status and pending request/reject.
|
||||||
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) & ~XHCI_PORTHALT_HALT_LTSSM;
|
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;
|
||||||
|
(void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reread port status to handle more changes.
|
||||||
|
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
||||||
|
|
||||||
// Port link state change (PLC).
|
// Port link state change (PLC).
|
||||||
if (status & XHCI_PORTSC_PLC)
|
if (status & XHCI_PORTSC_PLC)
|
||||||
{
|
{
|
||||||
//! WAR: Sometimes port speed changes without a CSC event. Set again.
|
// check XHCI_PORTSC_PLS_MASK
|
||||||
usbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10;
|
// if XHCI_PORTSC_PLS_U3
|
||||||
|
|
||||||
// check PLS
|
|
||||||
// if U3
|
|
||||||
// device_state = XUSB_SUSPENDED
|
// device_state = XUSB_SUSPENDED
|
||||||
// else if U0 and XUSB_SUSPENDED
|
// else if XHCI_PORTSC_PLS_U0 and XUSB_SUSPENDED
|
||||||
// val = XUSB_DEV_XHCI_EP_PAUSE
|
// val = XUSB_DEV_XHCI_EP_PAUSE
|
||||||
// XUSB_DEV_XHCI_EP_PAUSE = 0
|
// XUSB_DEV_XHCI_EP_PAUSE = 0
|
||||||
// XUSB_DEV_XHCI_EP_STCHG = val;
|
// XUSB_DEV_XHCI_EP_STCHG = val;
|
||||||
|
|
||||||
// Clear PLC bit.
|
// Clear PLC bit.
|
||||||
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) | XHCI_PORTSC_PLC;
|
status &= ~clear_mask;
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_PLC;
|
status |= XHCI_PORTSC_PLC;
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port configuration link error (CEC).
|
// Port configuration link error (CEC).
|
||||||
if (status & XHCI_PORTSC_CEC)
|
if (status & XHCI_PORTSC_CEC)
|
||||||
{
|
{
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) |= XHCI_PORTSC_CEC;
|
status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);
|
||||||
res = XUSB_ERROR_PORT_CFG;
|
status &= ~clear_mask;
|
||||||
|
status |= XHCI_PORTSC_CEC;
|
||||||
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;
|
||||||
|
|
||||||
|
return XUSB_ERROR_PORT_CFG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return USB_RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _xusb_handle_get_ep_status(usb_ctrl_setup_t *ctrl_setup)
|
static int _xusb_handle_get_ep_status(u32 ep_idx)
|
||||||
{
|
{
|
||||||
|
u32 ep_mask = BIT(ep_idx);
|
||||||
static u8 xusb_ep_status_descriptor[2] = {0};
|
static u8 xusb_ep_status_descriptor[2] = {0};
|
||||||
|
|
||||||
// Get EP context pointer.
|
xusb_ep_status_descriptor[0] =
|
||||||
volatile xusb_ep_ctx_t *ep_ctxt = (volatile xusb_ep_ctx_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) & 0xFFFFFFF0);
|
(XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) & ep_mask) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK;
|
||||||
ep_ctxt = &ep_ctxt[ctrl_setup->wIndex];
|
|
||||||
|
|
||||||
xusb_ep_status_descriptor[0] = (ep_ctxt->ep_state == EP_HALTED) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK;
|
|
||||||
return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN);
|
return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1536,8 +1576,9 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup)
|
||||||
|
|
||||||
//gfx_printf("ctrl: %02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength);
|
//gfx_printf("ctrl: %02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength);
|
||||||
|
|
||||||
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI;
|
// Unhalt EP0 IN.
|
||||||
u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI, 0, 1000);
|
XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI_EP0_IN;
|
||||||
|
u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI_EP0_IN, 0, 1000);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
@ -1557,14 +1598,33 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup)
|
||||||
case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):
|
case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):
|
||||||
if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT)
|
if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT)
|
||||||
{
|
{
|
||||||
if (_bRequest == USB_REQUEST_CLEAR_FEATURE)
|
if (_bRequest == USB_REQUEST_CLEAR_FEATURE || _bRequest == USB_REQUEST_SET_FEATURE)
|
||||||
{
|
{
|
||||||
xusb_set_ep_stall(_wIndex, USB_EP_CFG_CLEAR);
|
u32 ep = 0;
|
||||||
return _xusb_issue_status_trb(USB_DIR_IN);
|
switch (_wIndex) // endpoint
|
||||||
}
|
{
|
||||||
else if (_bRequest == USB_REQUEST_SET_FEATURE)
|
case USB_EP_ADDR_CTRL_OUT:
|
||||||
{
|
ep = XUSB_EP_CTRL_OUT;
|
||||||
xusb_set_ep_stall(_wIndex, USB_EP_CFG_STALL);
|
break;
|
||||||
|
case USB_EP_ADDR_CTRL_IN:
|
||||||
|
ep = XUSB_EP_CTRL_IN;
|
||||||
|
break;
|
||||||
|
case USB_EP_ADDR_BULK_OUT:
|
||||||
|
ep = USB_EP_BULK_OUT;
|
||||||
|
break;
|
||||||
|
case USB_EP_ADDR_BULK_IN:
|
||||||
|
ep = USB_EP_BULK_IN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);
|
||||||
|
return USB_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_bRequest == USB_REQUEST_CLEAR_FEATURE)
|
||||||
|
xusb_set_ep_stall(ep, USB_EP_CFG_CLEAR);
|
||||||
|
else if (_bRequest == USB_REQUEST_SET_FEATURE)
|
||||||
|
xusb_set_ep_stall(ep, USB_EP_CFG_STALL);
|
||||||
|
|
||||||
return _xusb_issue_status_trb(USB_DIR_IN);
|
return _xusb_issue_status_trb(USB_DIR_IN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1631,7 +1691,28 @@ static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup)
|
||||||
|
|
||||||
case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):
|
case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):
|
||||||
if (_bRequest == USB_REQUEST_GET_STATUS)
|
if (_bRequest == USB_REQUEST_GET_STATUS)
|
||||||
return _xusb_handle_get_ep_status(ctrl_setup);
|
{
|
||||||
|
u32 ep = 0;
|
||||||
|
switch (_wIndex) // endpoint
|
||||||
|
{
|
||||||
|
case USB_EP_ADDR_CTRL_OUT:
|
||||||
|
ep = XUSB_EP_CTRL_OUT;
|
||||||
|
break;
|
||||||
|
case USB_EP_ADDR_CTRL_IN:
|
||||||
|
ep = XUSB_EP_CTRL_IN;
|
||||||
|
break;
|
||||||
|
case USB_EP_ADDR_BULK_OUT:
|
||||||
|
ep = USB_EP_BULK_OUT;
|
||||||
|
break;
|
||||||
|
case USB_EP_ADDR_BULK_IN:
|
||||||
|
ep = USB_EP_BULK_IN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);
|
||||||
|
return USB_RES_OK;
|
||||||
|
}
|
||||||
|
return _xusb_handle_get_ep_status(ep);
|
||||||
|
}
|
||||||
|
|
||||||
ep_stall = true;
|
ep_stall = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1821,6 +1902,7 @@ int xusb_device_enumerate(usb_gadget_type gadget)
|
||||||
return USB_RES_OK;
|
return USB_RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! TODO: Do a full deinit.
|
||||||
void xusb_end(bool reset_ep, bool only_controller)
|
void xusb_end(bool reset_ep, bool only_controller)
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS);
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS);
|
||||||
|
@ -1855,7 +1937,7 @@ int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries)
|
||||||
|
|
||||||
int res = USB_RES_OK;
|
int res = USB_RES_OK;
|
||||||
usbd_xotg->tx_count[USB_DIR_OUT] = 0;
|
usbd_xotg->tx_count[USB_DIR_OUT] = 0;
|
||||||
usbd_xotg->bytes_remaining[USB_DIR_OUT] = len;
|
usbd_xotg->tx_bytes[USB_DIR_OUT] = len;
|
||||||
_xusb_issue_normal_trb(buf, len, USB_DIR_OUT);
|
_xusb_issue_normal_trb(buf, len, USB_DIR_OUT);
|
||||||
usbd_xotg->tx_count[USB_DIR_OUT]++;
|
usbd_xotg->tx_count[USB_DIR_OUT]++;
|
||||||
|
|
||||||
|
@ -1865,7 +1947,7 @@ int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries)
|
||||||
res = _xusb_ep_operation(sync_tries);
|
res = _xusb_ep_operation(sync_tries);
|
||||||
|
|
||||||
if (bytes_read)
|
if (bytes_read)
|
||||||
*bytes_read = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT];
|
*bytes_read = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT];
|
||||||
|
|
||||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
}
|
}
|
||||||
|
@ -1905,7 +1987,7 @@ int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_tries)
|
||||||
res = _xusb_ep_operation(sync_tries); // Infinite retries.
|
res = _xusb_ep_operation(sync_tries); // Infinite retries.
|
||||||
|
|
||||||
if (pending_bytes)
|
if (pending_bytes)
|
||||||
*pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_OUT];
|
*pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT];
|
||||||
|
|
||||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
|
|
||||||
|
@ -1921,7 +2003,7 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_trie
|
||||||
|
|
||||||
int res = USB_RES_OK;
|
int res = USB_RES_OK;
|
||||||
usbd_xotg->tx_count[USB_DIR_IN] = 0;
|
usbd_xotg->tx_count[USB_DIR_IN] = 0;
|
||||||
usbd_xotg->bytes_remaining[USB_DIR_IN] = len;
|
usbd_xotg->tx_bytes[USB_DIR_IN] = len;
|
||||||
_xusb_issue_normal_trb(buf, len, USB_DIR_IN);
|
_xusb_issue_normal_trb(buf, len, USB_DIR_IN);
|
||||||
usbd_xotg->tx_count[USB_DIR_IN]++;
|
usbd_xotg->tx_count[USB_DIR_IN]++;
|
||||||
|
|
||||||
|
@ -1931,7 +2013,7 @@ int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_trie
|
||||||
res = _xusb_ep_operation(sync_tries);
|
res = _xusb_ep_operation(sync_tries);
|
||||||
|
|
||||||
if (bytes_written)
|
if (bytes_written)
|
||||||
*bytes_written = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN];
|
*bytes_written = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1954,7 +2036,7 @@ int xusb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_tries)
|
||||||
res = _xusb_ep_operation(sync_tries); // Infinite retries.
|
res = _xusb_ep_operation(sync_tries); // Infinite retries.
|
||||||
|
|
||||||
if (pending_bytes)
|
if (pending_bytes)
|
||||||
*pending_bytes = res ? 0 : usbd_xotg->bytes_remaining[USB_DIR_IN];
|
*pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN];
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -2010,7 +2092,7 @@ void xusb_device_get_ops(usb_ops_t *ops)
|
||||||
ops->usbd_flush_endpoint = NULL;
|
ops->usbd_flush_endpoint = NULL;
|
||||||
ops->usbd_set_ep_stall = xusb_set_ep_stall;
|
ops->usbd_set_ep_stall = xusb_set_ep_stall;
|
||||||
ops->usbd_handle_ep0_ctrl_setup = xusb_handle_ep0_ctrl_setup;
|
ops->usbd_handle_ep0_ctrl_setup = xusb_handle_ep0_ctrl_setup;
|
||||||
ops->usbd_end = xusb_end;//////////////////
|
ops->usbd_end = xusb_end;
|
||||||
ops->usb_device_init = xusb_device_init;
|
ops->usb_device_init = xusb_device_init;
|
||||||
ops->usb_device_enumerate = xusb_device_enumerate;
|
ops->usb_device_enumerate = xusb_device_enumerate;
|
||||||
ops->usb_device_class_send_max_lun = xusb_device_class_send_max_lun;
|
ops->usb_device_class_send_max_lun = xusb_device_class_send_max_lun;
|
||||||
|
|
Loading…
Reference in a new issue