Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rtl872x] fix usb high speed #2744

Merged
merged 3 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bootloader/src/rtl872x/usb_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ void DFU_Check_Reset(void) {
gUsbDevice.detach();
Finish_Update();
}
RtlUsbDriver::instance()->loop(RtlUsbDriver::instance());
}
114 changes: 107 additions & 7 deletions hal/src/rtl872x/usbd_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include "system_error.h"
#include "service_debug.h"
#include <mutex>
#include "scope_guard.h"
#include "timer_hal.h"
#include "rtl8721d_usb.h"

using namespace particle::usbd;

Expand Down Expand Up @@ -90,7 +93,32 @@ uint8_t usbd_pcd_ep_set_stall(void* pcd, uint8_t ep);
uint8_t usbd_pcd_ep_clear_stall(void* pcd, uint8_t ep);
uint8_t usbd_pcd_ep_flush(void* pcd, uint8_t ep);
uint8_t usb_hal_flush_tx_fifo(uint32_t num);
uint8_t usb_hal_flush_rx_fifo();
uint8_t usb_hal_write_packet(uint8_t *src, uint8_t ep_ch_num, uint16_t len);
void usb_hal_disable_global_interrupt(void);
void usbd_pcd_set_address(void* pcd, uint8_t addr);
void usbd_pcd_stop(void* pcd);
void usbd_pcd_start(void* pcd);

u32 __real_usb_hal_read_interrupts(void);
void __real_usb_hal_clear_interrupts(u32 interrupt);

u32 __wrap_usb_hal_read_interrupts(void) {
uint32_t val = __real_usb_hal_read_interrupts();
if (val & USB_OTG_GINTSTS_EPMIS) {
// XXX: The USB stack does not correctly handle this interrupt
// and we get into an endless loop of being unable to re-enumerate
// Looks like RX/TX FIFOs are not correctly re-initialized on bus reset
// or when we perform flushEndpoint()
usb_hal_disable_global_interrupt();
RtlUsbDriver::instance()->reset();
}
return val;
}

void __wrap_usb_hal_clear_interrupts(u32 interrupt) {
__real_usb_hal_clear_interrupts(interrupt);
}

// FIXME: This is a nasty workaround for the SDK USB driver
// where it fails to deliver vendor requests with recipient=interface
Expand All @@ -99,6 +127,7 @@ int usb_hal_read_packet(void* ptr, uint32_t size, void* unknown);
int __real_usb_hal_read_packet(void* ptr, uint32_t size, void* unknown);

int __wrap_usb_hal_read_packet(void* ptr, uint32_t size, void* unknown) {
std::lock_guard<RtlUsbDriver> lk(*RtlUsbDriver::instance());
int r = __real_usb_hal_read_packet(ptr, size, unknown);
bool fixed = false;
if (size == sizeof(sLastUsbSetupRequest)) {
Expand Down Expand Up @@ -138,8 +167,15 @@ int RtlUsbDriver::attach() {
initialized_ = true;
// NOTE: these calls may fail
auto r = usbd_init(&usbdCfg_);
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
SCOPE_GUARD({
if (!thread_) {
os_thread_create(&thread_, "usbd_watch", RTL_USBD_ISR_PRIORITY, &RtlUsbDriver::loop, this, OS_THREAD_STACK_SIZE_DEFAULT);
SPARK_ASSERT(thread_);
}
});
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
if (r) {
// LOG(ERROR, "usbd_init failed: %d", r);
initialized_ = false;
CHECK_RTL_USB_TO_SYSTEM(r);
} else {
Expand All @@ -150,12 +186,68 @@ int RtlUsbDriver::attach() {
}

int RtlUsbDriver::detach() {
usb_hal_disable_global_interrupt();
std::lock_guard<RtlUsbDriver> lk(*this);
usbd_unregister_class();
usbd_deinit();
initialized_ = false;
return 0;
}

void RtlUsbDriver::reset() {
needsReset_ = true;
}

void RtlUsbDriver::loop(void* ctx) {
auto self = static_cast<RtlUsbDriver*>(ctx);
constexpr auto period = 1000;
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
bool error = false;
#else
static bool error = false;
static system_tick_t last = HAL_Timer_Get_Milli_Seconds();
#endif

#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
while (true) {
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
if (!self->initialized_ && !error) {
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
continue;
#else
return;
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
}
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
HAL_Delay_Milliseconds(period);
#else
if (HAL_Timer_Get_Milli_Seconds() - last >= period) {
last = HAL_Timer_Get_Milli_Seconds();
} else {
return;
}
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
if (self->needsReset_ || error) {
{
std::lock_guard<RtlUsbDriver> lk(*self);
self->detach();
}
self->needsReset_ = false;
{
std::lock_guard<RtlUsbDriver> lk(*self);
self->attach();
}
if (!self->initialized_) {
error = true;
} else {
error = false;
}
}
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
}
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
}

int RtlUsbDriver::suspend() {
return SYSTEM_ERROR_NOT_SUPPORTED;
}
Expand Down Expand Up @@ -203,12 +295,16 @@ int RtlUsbDriver::closeEndpoint(unsigned ep) {

int RtlUsbDriver::flushEndpoint(unsigned ep) {
SPARK_ASSERT(rtlDev_);
auto self = instance();
std::lock_guard<RtlUsbDriver> lk(*self);
void* pcd = *((void**)((uint8_t*)rtlDev_ + RTL_USB_DEV_PCD_OFFSET));
usb_spinlock_t* lock = *((usb_spinlock_t**)((uint8_t*)pcd + RTL_USB_PCD_SPINLOCK_OFFSET));
// FIXME: magic number, for some reason usbd_pcd_ep_flush does not work correctly
const uint32_t USBD_FLUSH_ENDPOINT_WEIRD_MAGIC_NUMBER = 0x400;
usb_os_spinlock(lock);
auto r = usb_hal_flush_tx_fifo(USBD_FLUSH_ENDPOINT_WEIRD_MAGIC_NUMBER);
auto r = usb_hal_flush_tx_fifo(ep & 0x7f);
// FIXME: USB stack may get into a weird state with EP0 endpoint.
// Additionally flushing RX fifo seems to resolve the issue.
usb_hal_flush_tx_fifo(0x00);
usb_hal_flush_rx_fifo();
usb_os_spinunlock(lock);
return CHECK_RTL_USB_TO_SYSTEM(r);
}
Expand Down Expand Up @@ -237,12 +333,14 @@ int RtlUsbDriver::setEndpointStatus(unsigned ep, EndpointStatus status) {

int RtlUsbDriver::transferIn(unsigned ep, const uint8_t* ptr, size_t size) {
SPARK_ASSERT(rtlDev_);
auto self = instance();
std::lock_guard<RtlUsbDriver> lk(*self);
if (ptr == nullptr && size == 0) {
// FIXME
void* pcd = *((void**)((uint8_t*)rtlDev_ + RTL_USB_DEV_PCD_OFFSET));
usb_spinlock_t* lock = *((usb_spinlock_t**)((uint8_t*)pcd + RTL_USB_PCD_SPINLOCK_OFFSET));
usb_os_spinlock(lock);
auto r = usb_hal_write_packet(nullptr, ep | SetupRequest::DIRECTION_DEVICE_TO_HOST, 0);
auto r = usb_hal_write_packet(nullptr, ep & 0x7f, 0);
usb_os_spinunlock(lock);
return CHECK_RTL_USB_TO_SYSTEM(r);
}
Expand All @@ -251,6 +349,8 @@ int RtlUsbDriver::transferIn(unsigned ep, const uint8_t* ptr, size_t size) {

int RtlUsbDriver::transferOut(unsigned ep, uint8_t* ptr, size_t size) {
SPARK_ASSERT(rtlDev_);
auto self = instance();
std::lock_guard<RtlUsbDriver> lk(*self);
return CHECK_RTL_USB_TO_SYSTEM(usbd_ep_receive(rtlDev_, ep & ~(SetupRequest::DIRECTION_DEVICE_TO_HOST), ptr, size));
}

Expand Down Expand Up @@ -331,16 +431,16 @@ uint8_t RtlUsbDriver::getClassDescriptorCb(usb_dev_t* dev, usb_setup_req_t* req)

uint8_t RtlUsbDriver::setConfigCb(usb_dev_t* dev, uint8_t config) {
auto self = instance();
std::lock_guard<RtlUsbDriver> lk(*self);

std::lock_guard<RtlUsbDriver> lk(*self);
self->setDevReference(dev);
return CHECK_RTL_USB(self->setConfig(config));
}

uint8_t RtlUsbDriver::clearConfigCb(usb_dev_t* dev, uint8_t config) {
auto self = instance();
std::lock_guard<RtlUsbDriver> lk(*self);

std::lock_guard<RtlUsbDriver> lk(*self);
self->setDevReference(dev);
return CHECK_RTL_USB(self->clearConfig(config));
}
Expand Down
8 changes: 7 additions & 1 deletion hal/src/rtl872x/usbd_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class RtlUsbDriver : public DeviceDriver {

void halReadPacketFixup(void* ptr);

static void loop(void* ctx);

void reset();

private:
RtlUsbDriver();
virtual ~RtlUsbDriver();
Expand Down Expand Up @@ -109,7 +113,7 @@ class RtlUsbDriver : public DeviceDriver {
.rx_fifo_size = USBD_MAX_RX_FIFO_SIZE,
.nptx_fifo_size = USBD_MAX_NPTX_FIFO_SIZE,
.ptx_fifo_size = USBD_MAX_PTX_FIFO_SIZE,
.speed = USB_SPEED_HIGH,
.speed = USB_SPEED_HIGH_IN_FULL,
.dma_enable = 0, // ?
.self_powered = 1,
.isr_priority = RTL_USBD_ISR_PRIORITY,
Expand All @@ -134,9 +138,11 @@ class RtlUsbDriver : public DeviceDriver {
void* fixupPtr_ = nullptr;
#if MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
RecursiveMutex mutex_;
os_thread_t thread_ = nullptr;
#endif // MODULE_FUNCTION != MOD_FUNC_BOOTLOADER

volatile bool initialized_ = false;
volatile bool needsReset_ = false;
};

} // namespace usbd
Expand Down
2 changes: 1 addition & 1 deletion third_party/ambd_sdk/include.mk
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ INCLUDE_DIRS += $(TARGET_AMBD_SDK_COMMON_PATH)/drivers/usb/device_new/core
INCLUDE_DIRS += $(TARGET_AMBD_SDK_COMMON_PATH)/drivers/usb/common_new

# Hack of the century!
LIBS_EXT_END += -Wl,--wrap=bt_coex_handle_specific_evt
LIBS_EXT_END += -Wl,--wrap=bt_coex_handle_specific_evt -Wl,--wrap=usb_hal_read_interrupts -Wl,--wrap=usb_hal_clear_interrupts
LIBS_EXT_END += $(TARGET_AMBD_SDK_PROJECT_LIB_PATH)/lib_wlan.a
LIBS_EXT_END += $(TARGET_AMBD_SDK_PROJECT_LIB_PATH)/lib_wps.a
ifneq ("$(MODULE)", "user-part")
Expand Down