support bcm2711 on pi4, enhance dcd init with utmi and ulpi hs phy

This commit is contained in:
hathach
2021-10-28 12:52:18 +07:00
parent 49aa69a301
commit 7def380058
8 changed files with 242 additions and 102 deletions

View File

@@ -31,7 +31,7 @@
#include "device/dcd_attr.h"
#if TUSB_OPT_DEVICE_ENABLED && \
( defined(DCD_ATTR_DWC2_STM32) || TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103) )
( defined(DCD_ATTR_DWC2_STM32) || TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103, OPT_MCU_BCM2711) )
#include "device/dcd.h"
#include "dwc2_type.h"
@@ -42,6 +42,8 @@
#include "dwc2_esp32.h"
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#include "dwc2_gd32.h"
#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
#include "dwc2_bcm.h"
#else
#error "Unsupported MCUs"
#endif
@@ -185,7 +187,7 @@ static void bus_reset(uint8_t rhport)
_allocated_fifo_words_tx = 16;
// Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
dwc2->dieptxf0 = (16 << TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
// Fixed control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -226,47 +228,6 @@ static void set_speed(uint8_t rhport, tusb_speed_t speed)
dwc2->dcfg |= (bitvalue << DCFG_DSPD_Pos);
}
#if defined(USB_HS_PHYC)
static bool USB_HS_PHYCInit(void)
{
USB_HS_PHYC_GlobalTypeDef *usb_hs_phyc = (USB_HS_PHYC_GlobalTypeDef*) USB_HS_PHYC_CONTROLLER_BASE;
// Enable LDO
usb_hs_phyc->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
// Wait until LDO ready
while ( 0 == (usb_hs_phyc->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
uint32_t phyc_pll = 0;
// TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
switch ( HSE_VALUE )
{
case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
default:
TU_ASSERT(0);
}
usb_hs_phyc->USB_HS_PHYC_PLL = phyc_pll;
// Control the tuning interface of the High Speed PHY
// Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver
usb_hs_phyc->USB_HS_PHYC_TUNE |= 0x00000F13U;
// Enable PLL internal PHY
usb_hs_phyc->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
// Original ST code has 2 ms delay for PLL stabilization.
// Primitive test shows that more than 10 USB un/replug cycle showed no error with enumeration
return true;
}
#endif
static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes)
{
(void) rhport;
@@ -369,7 +330,7 @@ void print_dwc2_info(dwc2_regs_t * dwc2)
TU_LOG_INT(1, hw_cfg3->synch_reset );
TU_LOG_INT(1, hw_cfg3->otg_adp_support );
TU_LOG_INT(1, hw_cfg3->otg_enable_hsic );
TU_LOG_INT(1, hw_cfg3->otg_bc_support );
TU_LOG_INT(1, hw_cfg3->battery_charger_support );
TU_LOG_INT(1, hw_cfg3->lpm_mode );
TU_LOG_INT(1, hw_cfg3->total_fifo_size );
@@ -395,57 +356,103 @@ void print_dwc2_info(dwc2_regs_t * dwc2)
TU_LOG_INT(1, hw_cfg4->dma_dynamic );
}
static void reset_core(dwc2_regs_t * dwc2)
{
// reset core
dwc2->grstctl |= GRSTCTL_CSRST;
// wait for reset bit is cleared
// TODO version 4.20a should wait for RESET DONE mask
while (dwc2->grstctl & GRSTCTL_CSRST) { }
// wait for AHB master IDLE
while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { }
// wait for device mode ?
}
void dcd_init (uint8_t rhport)
{
// Programming model begins in the last section of the chapter on the USB
// peripheral in each Reference Manual.
dwc2_regs_t * dwc2 = DWC2_REG(rhport);
// Check Synopsys ID
uint32_t const gsnpsid = dwc2->gsnpsid & 0xffff0000u;
// Check Synopsys ID, failed if controller is not enabled
uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK;
TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID, );
print_dwc2_info(dwc2);
// No HNP/SRP (no OTG support), program timeout later.
if ( rhport == 1 )
// Force device mode
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
uint32_t const hs_phy_type = dwc2->ghwcfg2_bm.hs_phy_type;
if( !TUD_OPT_HIGH_SPEED || hs_phy_type == HS_PHY_TYPE_NONE)
{
// On selected MCUs HS port1 can be used with external PHY via ULPI interface
#if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED
// deactivate internal PHY
// max speed is full or core does not support highspeed
TU_LOG2("Fullspeed PHY init\r\n");
// Select FS PHY
dwc2->gusbcfg |= GUSBCFG_PHYSEL;
// Reset core after selecting PHY
reset_core(dwc2);
#if defined(DCD_ATTR_DWC2_STM32)
// activate FS PHY on stm32
dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
#endif
}else
{
// Highspeed mode
#if defined(DCD_ATTR_DWC2_STM32)
// Disable STM32 FS PHY
dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
#endif
// Init The UTMI Interface
dwc2->gusbcfg &= ~(GUSBCFG_TSDPS | GUSBCFG_ULPIFSLS | GUSBCFG_PHYSEL);
uint32_t gusbcfg = dwc2->gusbcfg;
// Select default internal VBUS Indicator and Drive for ULPI
dwc2->gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
#else
dwc2->gusbcfg |= GUSBCFG_PHYSEL;
#endif
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
#if defined(USB_HS_PHYC)
// Highspeed with embedded UTMI PHYC
if (hs_phy_type == HS_PHY_TYPE_ULPI)
{
TU_LOG2("Highspeed ULPI PHY init\r\n");
// Select UTMI Interface
dwc2->gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN;
// Select ULPI
gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
// Enables control of a High Speed USB PHY
USB_HS_PHYCInit();
#endif
} else
{
// Enable internal PHY
dwc2->gusbcfg |= GUSBCFG_PHYSEL;
// ULPI 8-bit interface, single data rate
gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
// default internal VBUS Indicator and Drive
gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
// Disable FS/LS ULPI
gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM);
}else
{
TU_LOG2("Highspeed UTMI+ PHY init\r\n");
// Select UTMI+ with 8-bit interface
gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
// Set 16-bit interface if supported
if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16;
#if defined(DCD_ATTR_DWC2_STM32) && defined(USB_HS_PHYC)
dwc2_stm32_utmi_phy_init(dwc2);
#endif
}
dwc2->gusbcfg = gusbcfg;
// Reset core after selecting PHY
reset_core(dwc2);
}
// Reset core after selecting PHYst
// Wait AHB IDLE, reset then wait until it is cleared
while ((dwc2->grstctl & GRSTCTL_AHBIDL) == 0U) {}
dwc2->grstctl |= GRSTCTL_CSRST;
while ((dwc2->grstctl & GRSTCTL_CSRST) == GRSTCTL_CSRST) {}
// Restart PHY clock
dwc2->pcgctrl = 0;
@@ -463,9 +470,6 @@ void dcd_init (uint8_t rhport)
set_speed(rhport, TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL);
// Enable internal USB transceiver, unless using HS core (port 1) with external PHY.
if (!(rhport == 1 && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED))) dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
dwc2->gintmsk |= GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_USBSUSPM |
GINTMSK_WUIM | GINTMSK_RXFLVLM;