feat(hal/usb): Make USB-DWC HAL&LL configuration independent

Previously, we included symbols from soc/usb_dwc_cfg.h and configured
the HAL and LL according to it. Now we get the configuration in runtime
from USB-DWC registers.

Added missing definition for USB FS peripheral on ESP32-P4.
This commit is contained in:
Tomas Rezucha
2024-10-08 12:28:46 +02:00
committed by BOT
parent 1d5a8f6952
commit 177679b74e
13 changed files with 347 additions and 260 deletions

View File

@ -1,4 +1,4 @@
[codespell] [codespell]
skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,components/wpa_supplicant/*,components/esp_wifi/* skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,components/wpa_supplicant/*,components/esp_wifi/*
ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight,ot,wel,parms ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight,ot,wel,parms,ehen
write-changes = true write-changes = true

View File

@ -9,7 +9,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "soc/usb_dwc_struct.h" #include "soc/usb_dwc_struct.h"
#include "soc/usb_dwc_cfg.h"
#include "hal/usb_dwc_types.h" #include "hal/usb_dwc_types.h"
#include "hal/misc.h" #include "hal/misc.h"
@ -20,8 +19,7 @@ extern "C" {
/* ----------------------------- Helper Macros ------------------------------ */ /* ----------------------------- Helper Macros ------------------------------ */
// Get USB hardware instance // Get USB hardware instance
// TODO: extend this macros when we have support for both FS and HS hardware on P4 #define USB_DWC_LL_GET_HW(num) (((num) == 1) ? &USB_DWC_FS : &USB_DWC_HS)
#define USB_DWC_LL_GET_HW(num) (&USB_DWC_HS)
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
--------------------------------- DWC Constants -------------------------------- --------------------------------- DWC Constants --------------------------------
@ -221,11 +219,9 @@ static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t
static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw) static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE != 0)
hw->gusbcfg_reg.phyif = 1; // 16 bits interface hw->gusbcfg_reg.phyif = 1; // 16 bits interface
hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+ hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+
hw->gusbcfg_reg.physel = 0; // HS PHY hw->gusbcfg_reg.physel = 0; // HS PHY
#endif // (OTG_HSPHY_INTERFACE != 0)
} }
// --------------------------- GRSTCTL Register -------------------------------- // --------------------------- GRSTCTL Register --------------------------------
@ -352,24 +348,19 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw)
// --------------------------- GHWCFGx Register -------------------------------- // --------------------------- GHWCFGx Register --------------------------------
/** static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
* @brief Get the hardware configuration registers of the DWC_OTG controller
*
* The hardware configuration regitsers are read only and indicate the various
* features of the DWC_OTG core.
*
* @param hw Start address of the DWC_OTG registers
* @param[out] ghwcfg1 Hardware configuration registesr 1
* @param[out] ghwcfg2 Hardware configuration registesr 2
* @param[out] ghwcfg3 Hardware configuration registesr 3
* @param[out] ghwcfg4 Hardware configuration registesr 4
*/
static inline void usb_dwc_ll_ghwcfg_get_hw_config(usb_dwc_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
{ {
*ghwcfg1 = hw->ghwcfg1_reg.val; return hw->ghwcfg3_reg.dfifodepth;
*ghwcfg2 = hw->ghwcfg2_reg.val; }
*ghwcfg3 = hw->ghwcfg3_reg.val;
*ghwcfg4 = hw->ghwcfg4_reg.val; static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_channel_num(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.numhstchnl;
} }
// --------------------------- HPTXFSIZ Register ------------------------------- // --------------------------- HPTXFSIZ Register -------------------------------
@ -434,47 +425,44 @@ static inline void usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t *hw)
hw->hcfg_reg.fslssupp = 1; hw->hcfg_reg.fslssupp = 1;
} }
static inline void usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t *hw)
{
hw->hcfg_reg.fslspclksel = 1;
}
/** /**
* @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA * @brief Set FSLS PHY clock
* *
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers * @param[in] hw Start address of the DWC_OTG registers
* @param[in] speed Speed to initialize the host port at
*/ */
static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) static inline void usb_dwc_ll_hcfg_set_fsls_phy_clock(usb_dwc_dev_t *hw)
{ {
hw->hcfg_reg.descdma = 1; //Enable scatt/gatt
#if (OTG_HSPHY_INTERFACE == 0)
/* /*
Indicate to the OTG core what speed the PHY clock is at Indicate to the OTG core what speed the PHY clock is at
Note: It seems like S2/S3 PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
#endif // (OTG_HSPHY_INTERFACE == 0) hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2;
hw->hcfg_reg.perschedena = 0; //Disable perio sched
} }
// ----------------------------- HFIR Register --------------------------------- // ----------------------------- HFIR Register ---------------------------------
static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) /**
* @brief Set Frame Interval
*
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers
*/
static inline void usb_dwc_ll_hfir_set_frame_interval(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE == 0)
usb_dwc_hfir_reg_t hfir; usb_dwc_hfir_reg_t hfir;
hfir.val = hw->hfir_reg.val; hfir.val = hw->hfir_reg.val;
hfir.hfirrldctrl = 0; //Disable dynamic loading hfir.hfirrldctrl = 0; // Disable dynamic loading
/* /*
Set frame interval to be equal to 1ms Set frame interval to be equal to 1ms
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000;
hw->hfir_reg.val = hfir.val; hw->hfir_reg.val = hfir.val;
#endif // (OTG_HSPHY_INTERFACE == 0)
} }
// ----------------------------- HFNUM Register -------------------------------- // ----------------------------- HFNUM Register --------------------------------

View File

@ -39,7 +39,7 @@ FORCE_INLINE_ATTR void usb_utmi_ll_configure_ls(usb_utmi_dev_t *hw, bool paralle
* *
* @param[in] clk_en True to enable, false to disable * @param[in] clk_en True to enable, false to disable
*/ */
FORCE_INLINE_ATTR void usb_utmi_ll_enable_bus_clock(bool clk_en) FORCE_INLINE_ATTR void _usb_utmi_ll_enable_bus_clock(bool clk_en)
{ {
// Enable/disable system clock for USB_UTMI and USB_DWC_HS // Enable/disable system clock for USB_UTMI and USB_DWC_HS
HP_SYS_CLKRST.soc_clk_ctrl1.reg_usb_otg20_sys_clk_en = clk_en; HP_SYS_CLKRST.soc_clk_ctrl1.reg_usb_otg20_sys_clk_en = clk_en;
@ -48,7 +48,7 @@ FORCE_INLINE_ATTR void usb_utmi_ll_enable_bus_clock(bool clk_en)
} }
// HP_SYS_CLKRST.soc_clk_ctrlx and LP_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way // HP_SYS_CLKRST.soc_clk_ctrlx and LP_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way
#define usb_utmi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_utmi_ll_enable_bus_clock(__VA_ARGS__) #define usb_utmi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_utmi_ll_enable_bus_clock(__VA_ARGS__)
/** /**
* @brief Reset the USB UTMI PHY and USB_DWC_HS controller * @brief Reset the USB UTMI PHY and USB_DWC_HS controller

View File

@ -220,11 +220,9 @@ static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t
static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw) static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE != 0)
hw->gusbcfg_reg.phyif = 1; // 16 bits interface hw->gusbcfg_reg.phyif = 1; // 16 bits interface
hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+ hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+
hw->gusbcfg_reg.physel = 0; // HS PHY hw->gusbcfg_reg.physel = 0; // HS PHY
#endif // (OTG_HSPHY_INTERFACE != 0)
} }
// --------------------------- GRSTCTL Register -------------------------------- // --------------------------- GRSTCTL Register --------------------------------
@ -351,24 +349,19 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw)
// --------------------------- GHWCFGx Register -------------------------------- // --------------------------- GHWCFGx Register --------------------------------
/** static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
* @brief Get the hardware configuration registers of the DWC_OTG controller
*
* The hardware configuration regitsers are read only and indicate the various
* features of the DWC_OTG core.
*
* @param hw Start address of the DWC_OTG registers
* @param[out] ghwcfg1 Hardware configuration registesr 1
* @param[out] ghwcfg2 Hardware configuration registesr 2
* @param[out] ghwcfg3 Hardware configuration registesr 3
* @param[out] ghwcfg4 Hardware configuration registesr 4
*/
static inline void usb_dwc_ll_ghwcfg_get_hw_config(usb_dwc_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
{ {
*ghwcfg1 = hw->ghwcfg1_reg.val; return hw->ghwcfg3_reg.dfifodepth;
*ghwcfg2 = hw->ghwcfg2_reg.val; }
*ghwcfg3 = hw->ghwcfg3_reg.val;
*ghwcfg4 = hw->ghwcfg4_reg.val; static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_channel_num(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.numhstchnl;
} }
// --------------------------- HPTXFSIZ Register ------------------------------- // --------------------------- HPTXFSIZ Register -------------------------------
@ -433,47 +426,44 @@ static inline void usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t *hw)
hw->hcfg_reg.fslssupp = 1; hw->hcfg_reg.fslssupp = 1;
} }
static inline void usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t *hw)
{
hw->hcfg_reg.fslspclksel = 1;
}
/** /**
* @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA * @brief Set FSLS PHY clock
* *
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers * @param[in] hw Start address of the DWC_OTG registers
* @param[in] speed Speed to initialize the host port at
*/ */
static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) static inline void usb_dwc_ll_hcfg_set_fsls_phy_clock(usb_dwc_dev_t *hw)
{ {
hw->hcfg_reg.descdma = 1; //Enable scatt/gatt
#if (OTG_HSPHY_INTERFACE == 0)
/* /*
Indicate to the OTG core what speed the PHY clock is at Indicate to the OTG core what speed the PHY clock is at
Note: It seems like S2/S3 PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
#endif // (OTG_HSPHY_INTERFACE == 0) hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2;
hw->hcfg_reg.perschedena = 0; //Disable perio sched
} }
// ----------------------------- HFIR Register --------------------------------- // ----------------------------- HFIR Register ---------------------------------
static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) /**
* @brief Set Frame Interval
*
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers
*/
static inline void usb_dwc_ll_hfir_set_frame_interval(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE == 0)
usb_dwc_hfir_reg_t hfir; usb_dwc_hfir_reg_t hfir;
hfir.val = hw->hfir_reg.val; hfir.val = hw->hfir_reg.val;
hfir.hfirrldctrl = 0; //Disable dynamic loading hfir.hfirrldctrl = 0; // Disable dynamic loading
/* /*
Set frame interval to be equal to 1ms Set frame interval to be equal to 1ms
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000;
hw->hfir_reg.val = hfir.val; hw->hfir_reg.val = hfir.val;
#endif // (OTG_HSPHY_INTERFACE == 0)
} }
// ----------------------------- HFNUM Register -------------------------------- // ----------------------------- HFNUM Register --------------------------------

View File

@ -220,11 +220,9 @@ static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t
static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw) static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE != 0)
hw->gusbcfg_reg.phyif = 1; // 16 bits interface hw->gusbcfg_reg.phyif = 1; // 16 bits interface
hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+ hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+
hw->gusbcfg_reg.physel = 0; // HS PHY hw->gusbcfg_reg.physel = 0; // HS PHY
#endif // (OTG_HSPHY_INTERFACE != 0)
} }
// --------------------------- GRSTCTL Register -------------------------------- // --------------------------- GRSTCTL Register --------------------------------
@ -351,24 +349,19 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw)
// --------------------------- GHWCFGx Register -------------------------------- // --------------------------- GHWCFGx Register --------------------------------
/** static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
* @brief Get the hardware configuration registers of the DWC_OTG controller
*
* The hardware configuration regitsers are read only and indicate the various
* features of the DWC_OTG core.
*
* @param hw Start address of the DWC_OTG registers
* @param[out] ghwcfg1 Hardware configuration registesr 1
* @param[out] ghwcfg2 Hardware configuration registesr 2
* @param[out] ghwcfg3 Hardware configuration registesr 3
* @param[out] ghwcfg4 Hardware configuration registesr 4
*/
static inline void usb_dwc_ll_ghwcfg_get_hw_config(usb_dwc_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
{ {
*ghwcfg1 = hw->ghwcfg1_reg.val; return hw->ghwcfg3_reg.dfifodepth;
*ghwcfg2 = hw->ghwcfg2_reg.val; }
*ghwcfg3 = hw->ghwcfg3_reg.val;
*ghwcfg4 = hw->ghwcfg4_reg.val; static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_channel_num(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.numhstchnl;
} }
// --------------------------- HPTXFSIZ Register ------------------------------- // --------------------------- HPTXFSIZ Register -------------------------------
@ -433,47 +426,44 @@ static inline void usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t *hw)
hw->hcfg_reg.fslssupp = 1; hw->hcfg_reg.fslssupp = 1;
} }
static inline void usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t *hw)
{
hw->hcfg_reg.fslspclksel = 1;
}
/** /**
* @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA * @brief Set FSLS PHY clock
* *
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers * @param[in] hw Start address of the DWC_OTG registers
* @param[in] speed Speed to initialize the host port at
*/ */
static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) static inline void usb_dwc_ll_hcfg_set_fsls_phy_clock(usb_dwc_dev_t *hw)
{ {
hw->hcfg_reg.descdma = 1; //Enable scatt/gatt
#if (OTG_HSPHY_INTERFACE == 0)
/* /*
Indicate to the OTG core what speed the PHY clock is at Indicate to the OTG core what speed the PHY clock is at
Note: It seems like S2/S3 PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
#endif // (OTG_HSPHY_INTERFACE == 0) hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2;
hw->hcfg_reg.perschedena = 0; //Disable perio sched
} }
// ----------------------------- HFIR Register --------------------------------- // ----------------------------- HFIR Register ---------------------------------
static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) /**
* @brief Set Frame Interval
*
* @attention This function should only be called if FSLS PHY is selected
* @param[in] hw Start address of the DWC_OTG registers
*/
static inline void usb_dwc_ll_hfir_set_frame_interval(usb_dwc_dev_t *hw)
{ {
#if (OTG_HSPHY_INTERFACE == 0)
usb_dwc_hfir_reg_t hfir; usb_dwc_hfir_reg_t hfir;
hfir.val = hw->hfir_reg.val; hfir.val = hw->hfir_reg.val;
hfir.hfirrldctrl = 0; //Disable dynamic loading hfir.hfirrldctrl = 0; // Disable dynamic loading
/* /*
Set frame interval to be equal to 1ms Set frame interval to be equal to 1ms
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode, Note: FSLS PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/ */
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd;
hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000;
hw->hfir_reg.val = hfir.val; hw->hfir_reg.val = hfir.val;
#endif // (OTG_HSPHY_INTERFACE == 0)
} }
// ----------------------------- HFNUM Register -------------------------------- // ----------------------------- HFNUM Register --------------------------------

View File

@ -171,13 +171,23 @@ typedef struct {
* @brief HAL context structure * @brief HAL context structure
*/ */
typedef struct { typedef struct {
//Context // HW context
usb_dwc_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */ usb_dwc_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */
//Host Port related
uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */ // Host Port related
usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */ uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */
//FIFO related usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */
usb_dwc_hal_fifo_config_t fifo_config; /**< FIFO sizes configuration */
// FIFO related
usb_dwc_hal_fifo_config_t fifo_config; /**< FIFO sizes configuration */
// Configuration of the USB-DWC core. Read from read-only HW registers
struct {
unsigned chan_num_total; /**< Total number of channels for this configuration */
unsigned hsphy_type; /**< HS PHY type of this configuration */
unsigned fifo_size; /**< Total FIFO size [in lines] in this configuration */
} constant_config;
union { union {
struct { struct {
uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */ uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */
@ -188,11 +198,12 @@ typedef struct {
}; };
uint32_t val; uint32_t val;
} flags; } flags;
//Channel related
// Channel related
struct { struct {
int num_allocd; /**< Number of channels currently allocated */ int num_allocated; /**< Number of channels currently allocated */
uint32_t chan_pend_intrs_msk; /**< Bit mask of channels with pending interrupts */ uint32_t chan_pend_intrs_msk; /**< Bit mask of channels with pending interrupts */
usb_dwc_hal_chan_t *hdls[OTG_NUM_HOST_CHAN]; /**< Handles of each channel. Set to NULL if channel has not been allocated */ usb_dwc_hal_chan_t **hdls; /**< Handles of each channel. Set to NULL if channel has not been allocated */
} channels; } channels;
} usb_dwc_hal_context_t; } usb_dwc_hal_context_t;
@ -208,16 +219,20 @@ typedef struct {
* - Interrupt allocated but DISABLED (in case of an unknown interrupt state) * - Interrupt allocated but DISABLED (in case of an unknown interrupt state)
* Exit: * Exit:
* - Checks to see if DWC_OTG is alive, and if HW version/config is correct * - Checks to see if DWC_OTG is alive, and if HW version/config is correct
* - HAl context initialized * - HAL context initialized
* - Read and save relevant USB-DWC configuration parameters
* - Sets default values to some global and OTG registers (GAHBCFG and GUSBCFG) * - Sets default values to some global and OTG registers (GAHBCFG and GUSBCFG)
* - Umask global interrupt signal * - Umask global interrupt signal
* - Put DWC_OTG into host mode. Require 25ms delay before this takes effect. * - Put DWC_OTG into host mode. Require 25ms delay before this takes effect.
* - State -> USB_DWC_HAL_PORT_STATE_OTG * - State -> USB_DWC_HAL_PORT_STATE_OTG
* - Interrupts cleared. Users can now enable their ISR * - Interrupts cleared. Users can now enable their ISR
* *
* @param[inout] hal Context of the HAL layer * @attention The user must allocate memory for channel handlers with
* `hal->channels.hdls = malloc(hal->constant_config.chan_num_total * sizeof(usb_dwc_hal_chan_t*))`
* @param[inout] hal Context of the HAL layer
* @param[in] port_id USB port ID
*/ */
void usb_dwc_hal_init(usb_dwc_hal_context_t *hal); void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id);
/** /**
* @brief Deinitialize the HAL context * @brief Deinitialize the HAL context
@ -241,7 +256,7 @@ void usb_dwc_hal_deinit(usb_dwc_hal_context_t *hal);
* *
* @note This has nothing to do with a USB bus reset. It simply resets the peripheral * @note This has nothing to do with a USB bus reset. It simply resets the peripheral
* *
* @param hal Context of the HAL layer * @param[in] hal Context of the HAL layer
*/ */
void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal); void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal);

View File

@ -10,7 +10,6 @@
#include <stdlib.h> // For abort() #include <stdlib.h> // For abort()
#include "sdkconfig.h" #include "sdkconfig.h"
#include "soc/chip_revision.h" #include "soc/chip_revision.h"
#include "soc/usb_dwc_cfg.h"
#include "soc/usb_dwc_periph.h" #include "soc/usb_dwc_periph.h"
#include "hal/usb_dwc_hal.h" #include "hal/usb_dwc_hal.h"
#include "hal/usb_dwc_ll.h" #include "hal/usb_dwc_ll.h"
@ -112,10 +111,8 @@ static void set_defaults(usb_dwc_hal_context_t *hal)
usb_dwc_ll_gusbcfg_dis_hnp_cap(hal->dev); //Disable HNP usb_dwc_ll_gusbcfg_dis_hnp_cap(hal->dev); //Disable HNP
usb_dwc_ll_gusbcfg_dis_srp_cap(hal->dev); //Disable SRP usb_dwc_ll_gusbcfg_dis_srp_cap(hal->dev); //Disable SRP
// Check if this USB-DWC supports HS PHY, if yes, use it // If this USB-DWC supports HS PHY, use it
uint32_t ghwcfg[4]; if (hal->constant_config.hsphy_type != 0) {
usb_dwc_ll_ghwcfg_get_hw_config(hal->dev, &ghwcfg[0], &ghwcfg[1], &ghwcfg[2], &ghwcfg[3]);
if (((usb_dwc_ghwcfg2_reg_t)ghwcfg[1]).hsphytype != 0) {
usb_dwc_ll_gusbcfg_set_timeout_cal(hal->dev, 5); // 5 PHY clocks for our HS PHY usb_dwc_ll_gusbcfg_set_timeout_cal(hal->dev, 5); // 5 PHY clocks for our HS PHY
usb_dwc_ll_gusbcfg_set_utmi_phy(hal->dev); usb_dwc_ll_gusbcfg_set_utmi_phy(hal->dev);
} }
@ -128,16 +125,29 @@ static void set_defaults(usb_dwc_hal_context_t *hal)
usb_dwc_ll_gusbcfg_force_host_mode(hal->dev); usb_dwc_ll_gusbcfg_force_host_mode(hal->dev);
} }
void usb_dwc_hal_init(usb_dwc_hal_context_t *hal) void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id)
{ {
//Check if a peripheral is alive by reading the core ID registers // Check if a peripheral is alive by reading the core ID registers
usb_dwc_dev_t *dev = USB_DWC_LL_GET_HW(0); HAL_ASSERT(port_id < SOC_USB_OTG_PERIPH_NUM);
usb_dwc_dev_t *dev = USB_DWC_LL_GET_HW(port_id);
uint32_t core_id = usb_dwc_ll_gsnpsid_get_id(dev); uint32_t core_id = usb_dwc_ll_gsnpsid_get_id(dev);
HAL_ASSERT(core_id == CORE_REG_GSNPSID); HAL_ASSERT(core_id == CORE_REG_GSNPSID);
(void) core_id; //Suppress unused variable warning if asserts are disabled (void) core_id; //Suppress unused variable warning if asserts are disabled
//Initialize HAL context
// Initialize HAL context
memset(hal, 0, sizeof(usb_dwc_hal_context_t)); memset(hal, 0, sizeof(usb_dwc_hal_context_t));
hal->dev = dev; hal->dev = dev;
// Save constant configuration of this USB-DWC instance
/*
* EPINFO_CTL is located at the end of FIFO, its size is fixed in HW.
* The reserved size is always the worst-case, which is device mode that requires 4 locations per EP direction (including EP0).
* Here we just read the FIFO size from HW register, to avoid any ambivalence
*/
hal->constant_config.fifo_size = usb_dwc_ll_ghwcfg_get_fifo_depth(dev);
hal->constant_config.hsphy_type = usb_dwc_ll_ghwcfg_get_hsphy_type(dev);
hal->constant_config.chan_num_total = usb_dwc_ll_ghwcfg_get_channel_num(dev);
set_defaults(hal); set_defaults(hal);
} }
@ -154,32 +164,31 @@ void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal)
{ {
usb_dwc_ll_grstctl_core_soft_reset(hal->dev); usb_dwc_ll_grstctl_core_soft_reset(hal->dev);
while (usb_dwc_ll_grstctl_is_core_soft_reset_in_progress(hal->dev)) { while (usb_dwc_ll_grstctl_is_core_soft_reset_in_progress(hal->dev)) {
; //Wait until core reset is done ; // Wait until core reset is done
} }
while (!usb_dwc_ll_grstctl_is_ahb_idle(hal->dev)) { while (!usb_dwc_ll_grstctl_is_ahb_idle(hal->dev)) {
; //Wait until AHB Master bus is idle before doing any other operations ; // Wait until AHB Master bus is idle before doing any other operations
} }
//Set the default bits
// Set the default bits in USB-DWC registers
set_defaults(hal); set_defaults(hal);
//Clear all the flags and channels
// Clear all the flags and channels
hal->periodic_frame_list = NULL; hal->periodic_frame_list = NULL;
hal->flags.val = 0; hal->flags.val = 0;
hal->channels.num_allocd = 0; hal->channels.num_allocated = 0;
hal->channels.chan_pend_intrs_msk = 0; hal->channels.chan_pend_intrs_msk = 0;
memset(hal->channels.hdls, 0, sizeof(usb_dwc_hal_chan_t *) * OTG_NUM_HOST_CHAN); if (hal->channels.hdls) {
for (int i = 0; i < hal->constant_config.chan_num_total; i++) {
hal->channels.hdls[i] = NULL;
}
}
} }
void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias) void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias)
{ {
/* HAL_ASSERT(hal->channels.hdls);
* EPINFO_CTL is located at the end of FIFO, its size is fixed in HW. const uint16_t fifo_size_lines = hal->constant_config.fifo_size;
* The reserved size is always the worst-case, which is device mode that requires 4 locations per EP direction (including EP0).
* Here we just read the FIFO size from HW register, to avoid any ambivalence
*/
uint32_t ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4;
usb_dwc_ll_ghwcfg_get_hw_config(hal->dev, &ghwcfg1, &ghwcfg2, &ghwcfg3, &ghwcfg4);
const uint16_t fifo_size_lines = ((usb_dwc_ghwcfg3_reg_t)ghwcfg3).dfifodepth;
/* /*
* Recommended FIFO sizes (see 2.1.2.4 for programming guide) * Recommended FIFO sizes (see 2.1.2.4 for programming guide)
* *
@ -190,23 +199,28 @@ void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bi
* Recommended sizes fit 2 packets of each type. For S2 and S3 we can't fit even one MPS ISOC packet (1023 FS and 1024 HS). * Recommended sizes fit 2 packets of each type. For S2 and S3 we can't fit even one MPS ISOC packet (1023 FS and 1024 HS).
* So the calculations below are compromises between the available FIFO size and optimal performance. * So the calculations below are compromises between the available FIFO size and optimal performance.
*/ */
// Information for maintainers: this calculation is here for backward compatibility
// It should be removed when we allow HAL users to configure the FIFO sizes IDF-9042
const int otg_dfifo_depth = hal->constant_config.hsphy_type ? 1024 : 256;
usb_dwc_hal_fifo_config_t fifo_config; usb_dwc_hal_fifo_config_t fifo_config;
switch (fifo_bias) { switch (fifo_bias) {
// Define minimum viable (fits at least 1 MPS) FIFO sizes for non-biased FIFO types // Define minimum viable (fits at least 1 MPS) FIFO sizes for non-biased FIFO types
// Allocate the remaining size to the biased FIFO type // Allocate the remaining size to the biased FIFO type
case USB_HAL_FIFO_BIAS_DEFAULT: case USB_HAL_FIFO_BIAS_DEFAULT:
fifo_config.nptx_fifo_lines = OTG_DFIFO_DEPTH / 4; fifo_config.nptx_fifo_lines = otg_dfifo_depth / 4;
fifo_config.ptx_fifo_lines = OTG_DFIFO_DEPTH / 8; fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines; fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines;
break; break;
case USB_HAL_FIFO_BIAS_RX: case USB_HAL_FIFO_BIAS_RX:
fifo_config.nptx_fifo_lines = OTG_DFIFO_DEPTH / 16; fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
fifo_config.ptx_fifo_lines = OTG_DFIFO_DEPTH / 8; fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines; fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines;
break; break;
case USB_HAL_FIFO_BIAS_PTX: case USB_HAL_FIFO_BIAS_PTX:
fifo_config.rx_fifo_lines = OTG_DFIFO_DEPTH / 8 + 2; // 2 extra lines are allocated for status information. See USB-OTG Programming Guide, chapter 2.1.2.1 fifo_config.rx_fifo_lines = otg_dfifo_depth / 8 + 2; // 2 extra lines are allocated for status information. See USB-OTG Programming Guide, chapter 2.1.2.1
fifo_config.nptx_fifo_lines = OTG_DFIFO_DEPTH / 16; fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
fifo_config.ptx_fifo_lines = fifo_size_lines - fifo_config.nptx_fifo_lines - fifo_config.rx_fifo_lines; fifo_config.ptx_fifo_lines = fifo_size_lines - fifo_config.nptx_fifo_lines - fifo_config.rx_fifo_lines;
break; break;
default: default:
@ -215,7 +229,7 @@ void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bi
HAL_ASSERT((fifo_config.rx_fifo_lines + fifo_config.nptx_fifo_lines + fifo_config.ptx_fifo_lines) <= fifo_size_lines); HAL_ASSERT((fifo_config.rx_fifo_lines + fifo_config.nptx_fifo_lines + fifo_config.ptx_fifo_lines) <= fifo_size_lines);
//Check that none of the channels are active //Check that none of the channels are active
for (int i = 0; i < OTG_NUM_HOST_CHAN; i++) { for (int i = 0; i < hal->constant_config.chan_num_total; i++) {
if (hal->channels.hdls[i] != NULL) { if (hal->channels.hdls[i] != NULL) {
HAL_ASSERT(!hal->channels.hdls[i]->flags.active); HAL_ASSERT(!hal->channels.hdls[i]->flags.active);
} }
@ -254,11 +268,15 @@ static inline void debounce_lock_enable(usb_dwc_hal_context_t *hal)
void usb_dwc_hal_port_enable(usb_dwc_hal_context_t *hal) void usb_dwc_hal_port_enable(usb_dwc_hal_context_t *hal)
{ {
usb_dwc_speed_t speed = usb_dwc_ll_hprt_get_speed(hal->dev); // Host Configuration
//Host Configuration usb_dwc_ll_hcfg_en_scatt_gatt_dma(hal->dev); // Enable Scatther-Gather DMA mode
usb_dwc_ll_hcfg_set_defaults(hal->dev, speed); usb_dwc_ll_hcfg_dis_perio_sched(hal->dev); // Disable Periodic Scheduler (for now)
//Configure HFIR
usb_dwc_ll_hfir_set_defaults(hal->dev, speed); // Configure PHY clock: Only for USB-DWC with FSLS PHY
if (hal->constant_config.hsphy_type == 0) {
usb_dwc_ll_hcfg_set_fsls_phy_clock(hal->dev);
usb_dwc_ll_hfir_set_frame_interval(hal->dev);
}
} }
// ----------------------------------------------------- Channel ------------------------------------------------------- // ----------------------------------------------------- Channel -------------------------------------------------------
@ -267,17 +285,18 @@ void usb_dwc_hal_port_enable(usb_dwc_hal_context_t *hal)
bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_obj, void *chan_ctx) bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_obj, void *chan_ctx)
{ {
HAL_ASSERT(hal->channels.hdls);
HAL_ASSERT(hal->flags.fifo_sizes_set); //FIFO sizes should be set before attempting to allocate a channel HAL_ASSERT(hal->flags.fifo_sizes_set); //FIFO sizes should be set before attempting to allocate a channel
//Attempt to allocate channel //Attempt to allocate channel
if (hal->channels.num_allocd == OTG_NUM_HOST_CHAN) { if (hal->channels.num_allocated == hal->constant_config.chan_num_total) {
return false; //Out of free channels return false; //Out of free channels
} }
int chan_idx = -1; int chan_idx = -1;
for (int i = 0; i < OTG_NUM_HOST_CHAN; i++) { for (int i = 0; i < hal->constant_config.chan_num_total; i++) {
if (hal->channels.hdls[i] == NULL) { if (hal->channels.hdls[i] == NULL) {
hal->channels.hdls[i] = chan_obj; hal->channels.hdls[i] = chan_obj;
chan_idx = i; chan_idx = i;
hal->channels.num_allocd++; hal->channels.num_allocated++;
break; break;
} }
} }
@ -299,6 +318,7 @@ bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan
void usb_dwc_hal_chan_free(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_obj) void usb_dwc_hal_chan_free(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_obj)
{ {
HAL_ASSERT(hal->channels.hdls);
if (chan_obj->type == USB_DWC_XFER_TYPE_INTR || chan_obj->type == USB_DWC_XFER_TYPE_ISOCHRONOUS) { if (chan_obj->type == USB_DWC_XFER_TYPE_INTR || chan_obj->type == USB_DWC_XFER_TYPE_ISOCHRONOUS) {
//Unschedule this channel //Unschedule this channel
for (int i = 0; i < hal->frame_list_len; i++) { for (int i = 0; i < hal->frame_list_len; i++) {
@ -311,8 +331,8 @@ void usb_dwc_hal_chan_free(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_
usb_dwc_ll_haintmsk_dis_chan_intr(hal->dev, 1 << chan_obj->flags.chan_idx); usb_dwc_ll_haintmsk_dis_chan_intr(hal->dev, 1 << chan_obj->flags.chan_idx);
//Deallocate channel //Deallocate channel
hal->channels.hdls[chan_obj->flags.chan_idx] = NULL; hal->channels.hdls[chan_obj->flags.chan_idx] = NULL;
hal->channels.num_allocd--; hal->channels.num_allocated--;
HAL_ASSERT(hal->channels.num_allocd >= 0); HAL_ASSERT(hal->channels.num_allocated >= 0);
} }
// ---------------- Channel Configuration ------------------ // ---------------- Channel Configuration ------------------
@ -464,6 +484,7 @@ usb_dwc_hal_port_event_t usb_dwc_hal_decode_intr(usb_dwc_hal_context_t *hal)
usb_dwc_hal_chan_t *usb_dwc_hal_get_chan_pending_intr(usb_dwc_hal_context_t *hal) usb_dwc_hal_chan_t *usb_dwc_hal_get_chan_pending_intr(usb_dwc_hal_context_t *hal)
{ {
HAL_ASSERT(hal->channels.hdls);
int chan_num = __builtin_ffs(hal->channels.chan_pend_intrs_msk); int chan_num = __builtin_ffs(hal->channels.chan_pend_intrs_msk);
if (chan_num) { if (chan_num) {
hal->channels.chan_pend_intrs_msk &= ~(1 << (chan_num - 1)); //Clear the pending bit for that channel hal->channels.chan_pend_intrs_msk &= ~(1 << (chan_num - 1)); //Clear the pending bit for that channel

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -11,94 +11,170 @@ extern "C" {
#endif #endif
/* /*
HS Instance:
Configuration Set ID: 11 Configuration Set ID: 11
*/ */
/* 3.1 Basic Config Parameters */ /* 3.1 Basic Config Parameters */
#define OTG_MODE 0 #define OTG20_MODE 0
#define OTG_ARCHITECTURE 2 #define OTG20_ARCHITECTURE 2
#define OTG_SINGLE_POINT 1 #define OTG20_SINGLE_POINT 1
#define OTG_ENABLE_LPM 0 #define OTG20_ENABLE_LPM 0
#define OTG_EN_DED_TX_FIFO 1 #define OTG20_EN_DED_TX_FIFO 1
#define OTG_EN_DESC_DMA 1 #define OTG20_EN_DESC_DMA 1
#define OTG_MULTI_PROC_INTRPT 1 #define OTG20_MULTI_PROC_INTRPT 1
/* 3.2 USB Physical Layer Interface Parameters */ /* 3.2 USB Physical Layer Interface Parameters */
#define OTG_HSPHY_INTERFACE 3 #define OTG20_HSPHY_INTERFACE 3
#define OTG_HSPHY_DWIDTH 2 #define OTG20_HSPHY_DWIDTH 2
#define OTG_FSPHY_INTERFACE 2 #define OTG20_FSPHY_INTERFACE 2
#define OTG_ENABLE_IC_USB 0 #define OTG20_ENABLE_IC_USB 0
#define OTG_ENABLE_HSIC 0 #define OTG20_ENABLE_HSIC 0
#define OTG_I2C_INTERFACE 0 #define OTG20_I2C_INTERFACE 0
#define OTG_ULPI_CARKIT 1 #define OTG20_ULPI_CARKIT 1
#define OTG_ADP_SUPPORT 1 #define OTG20_ADP_SUPPORT 1
#define OTG_BC_SUPPORT 0 #define OTG20_BC_SUPPORT 0
#define OTG_VENDOR_CTL_INTERFACE 1 #define OTG20_VENDOR_CTL_INTERFACE 1
/* 3.3 Device Endpoint Configuration Parameters */ /* 3.3 Device Endpoint Configuration Parameters */
#define OTG_NUM_EPS 15 #define OTG20_NUM_EPS 15
#define OTG_NUM_IN_EPS 8 #define OTG20_NUM_IN_EPS 8
#define OTG_NUM_CRL_EPS 1 #define OTG20_NUM_CRL_EPS 1
/* 3.4 Host Endpoint Configuration Parameters */ /* 3.4 Host Endpoint Configuration Parameters */
#define OTG_NUM_HOST_CHAN 16 #define OTG20_NUM_HOST_CHAN 16
#define OTG_EN_PERIO_HOST 1 #define OTG20_EN_PERIO_HOST 1
/* 3.5 Endpoint Channel FIFO Configuration Parameters */ /* 3.5 Endpoint Channel FIFO Configuration Parameters */
#define OTG_DFIFO_DEPTH 1024 #define OTG20_DFIFO_DEPTH 1024
#define OTG_DFIFO_DYNAMIC 1 #define OTG20_DFIFO_DYNAMIC 1
#define OTG_RX_DFIFO_DEPTH 1024 #define OTG20_RX_DFIFO_DEPTH 1024
#define OTG_TX_HNPERIO_DFIFO_DEPTH 1024 #define OTG20_TX_HNPERIO_DFIFO_DEPTH 1024
#define OTG_TX_HPERIO_DFIFO_DEPTH 1024 #define OTG20_TX_HPERIO_DFIFO_DEPTH 1024
#define OTG_NPERIO_TX_QUEUE_DEPTH 4 #define OTG20_NPERIO_TX_QUEUE_DEPTH 4
#define OTG_PERIO_TX_QUEUE_DEPTH 4 #define OTG20_PERIO_TX_QUEUE_DEPTH 4
/* 3.6 Additional Configuration Options Parameters */ /* 3.6 Additional Configuration Options Parameters */
#define OTG_TRANS_COUNT_WIDTH 17 #define OTG20_TRANS_COUNT_WIDTH 17
#define OTG_PACKET_COUNT_WIDTH 8 #define OTG20_PACKET_COUNT_WIDTH 8
#define OTG_RM_OPT_FEATURES 1 #define OTG20_RM_OPT_FEATURES 1
#define OTG_EN_PWROPT 1 #define OTG20_EN_PWROPT 1
#define OTG_SYNC_RESET_TYPE 0 #define OTG20_SYNC_RESET_TYPE 0
#define OTG_EN_IDDIG_FILTER 1 #define OTG20_EN_IDDIG_FILTER 1
#define OTG_EN_VBUSVALID_FILTER 1 #define OTG20_EN_VBUSVALID_FILTER 1
#define OTG_EN_A_VALID_FILTER 1 #define OTG20_EN_A_VALID_FILTER 1
#define OTG_EN_B_VALID_FILTER 1 #define OTG20_EN_B_VALID_FILTER 1
#define OTG_EN_SESSIONEND_FILTER 1 #define OTG20_EN_SESSIONEND_FILTER 1
#define OTG_EXCP_CNTL_XFER_FLOW 1 #define OTG20_EXCP_CNTL_XFER_FLOW 1
#define OTG_PWR_CLAMP 0 #define OTG20_PWR_CLAMP 0
#define OTG_PWR_SWITCH_POLARITY 0 #define OTG20_PWR_SWITCH_POLARITY 0
/* 3.7 Endpoint Direction Parameters */ /* 3.7 Endpoint Direction Parameters */
#define OTG_EP_DIR_1 0 #define OTG20_EP_DIR_1 0
#define OTG_EP_DIR_2 0 #define OTG20_EP_DIR_2 0
#define OTG_EP_DIR_3 0 #define OTG20_EP_DIR_3 0
#define OTG_EP_DIR_4 0 #define OTG20_EP_DIR_4 0
#define OTG_EP_DIR_5 0 #define OTG20_EP_DIR_5 0
#define OTG_EP_DIR_6 0 #define OTG20_EP_DIR_6 0
#define OTG_EP_DIR_7 0 #define OTG20_EP_DIR_7 0
#define OTG_EP_DIR_8 0 #define OTG20_EP_DIR_8 0
#define OTG_EP_DIR_9 0 #define OTG20_EP_DIR_9 0
#define OTG_EP_DIR_10 0 #define OTG20_EP_DIR_10 0
#define OTG_EP_DIR_11 0 #define OTG20_EP_DIR_11 0
#define OTG_EP_DIR_12 0 #define OTG20_EP_DIR_12 0
#define OTG_EP_DIR_13 0 #define OTG20_EP_DIR_13 0
#define OTG_EP_DIR_14 0 #define OTG20_EP_DIR_14 0
#define OTG_EP_DIR_15 0 #define OTG20_EP_DIR_15 0
/* 3.8 Device Periodic FIFO Depth Parameters */ /* 3.8 Device Periodic FIFO Depth Parameters */
/* 3.9 Device IN Endpoint FIFO Depth Parameters */ /* 3.9 Device IN Endpoint FIFO Depth Parameters */
#define OTG_TX_DINEP_DFIFO_DEPTH_0 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_0 512
#define OTG_TX_DINEP_DFIFO_DEPTH_1 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_1 512
#define OTG_TX_DINEP_DFIFO_DEPTH_2 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_2 512
#define OTG_TX_DINEP_DFIFO_DEPTH_3 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_3 512
#define OTG_TX_DINEP_DFIFO_DEPTH_4 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_4 512
#define OTG_TX_DINEP_DFIFO_DEPTH_5 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_5 512
#define OTG_TX_DINEP_DFIFO_DEPTH_6 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_6 512
#define OTG_TX_DINEP_DFIFO_DEPTH_7 512 #define OTG20_TX_DINEP_DFIFO_DEPTH_7 512
/* 3.10 UTMI-To-UTMI Bridge Component Parameters */ /* 3.10 UTMI-To-UTMI Bridge Component Parameters */
#define DWC_U2UB_EN 0 #define OTG20_U2UB_EN 0
/*
FS Instance:
Configuration Set ID: 1
*/
/* 3.1 Basic Config Parameters */
#define OTG11_MODE 0
#define OTG11_ARCHITECTURE 2
#define OTG11_SINGLE_POINT 1
#define OTG11_ENABLE_LPM 0
#define OTG11_EN_DED_TX_FIFO 1
#define OTG11_EN_DESC_DMA 1
#define OTG11_MULTI_PROC_INTRPT 0
/* 3.2 USB Physical Layer Interface Parameters */
#define OTG11_HSPHY_INTERFACE 0
#define OTG11_FSPHY_INTERFACE 1
#define OTG11_ENABLE_IC_USB 0
#define OTG11_I2C_INTERFACE 0
#define OTG11_ADP_SUPPORT 0
#define OTG11_BC_SUPPORT 0
/* 3.3 Device Endpoint Configuration Parameters */
#define OTG11_NUM_EPS 6
#define OTG11_NUM_IN_EPS 5
#define OTG11_NUM_CRL_EPS 0
/* 3.4 Host Endpoint Configuration Parameters */
#define OTG11_NUM_HOST_CHAN 8
#define OTG11_EN_PERIO_HOST 1
/* 3.5 Endpoint Channel FIFO Configuration Parameters */
#define OTG11_DFIFO_DEPTH 256
#define OTG11_DFIFO_DYNAMIC 1
#define OTG11_RX_DFIFO_DEPTH 256
#define OTG11_TX_HNPERIO_DFIFO_DEPTH 256
#define OTG11_TX_NPERIO_DFIFO_DEPTH 256
#define OTG11_TX_HPERIO_DFIFO_DEPTH 256
#define OTG11_NPERIO_TX_QUEUE_DEPTH 4
#define OTG11_PERIO_TX_QUEUE_DEPTH 8
/* 3.6 Additional Configuration Options Parameters */
#define OTG11_TRANS_COUNT_WIDTH 16
#define OTG11_PACKET_COUNT_WIDTH 7
#define OTG11_RM_OPT_FEATURES 1
#define OTG11_EN_PWROPT 1
#define OTG11_SYNC_RESET_TYPE 0
#define OTG11_EN_IDDIG_FILTER 1
#define OTG11_EN_VBUSVALID_FILTER 1
#define OTG11_EN_A_VALID_FILTER 1
#define OTG11_EN_B_VALID_FILTER 1
#define OTG11_EN_SESSIONEND_FILTER 1
#define OTG11_EXCP_CNTL_XFER_FLOW 1
#define OTG11_PWR_CLAMP 0
#define OTG11_PWR_SWITCH_POLARITY 0
/* 3.7 Endpoint Direction Parameters */
#define OTG11_EP_DIR_1 0
#define OTG11_EP_DIR_2 0
#define OTG11_EP_DIR_3 0
#define OTG11_EP_DIR_4 0
#define OTG11_EP_DIR_5 0
#define OTG11_EP_DIR_6 0
/* 3.8 Device Periodic FIFO Depth Parameters */
/* 3.9 Device IN Endpoint FIFO Depth Parameters */
#define OTG11_TX_DINEP_DFIFO_DEPTH_1 256
#define OTG11_TX_DINEP_DFIFO_DEPTH_2 256
#define OTG11_TX_DINEP_DFIFO_DEPTH_3 256
#define OTG11_TX_DINEP_DFIFO_DEPTH_4 256
/* 3.10 UTMI-To-UTMI Bridge Component Parameters */
#define OTG11_U2UB_EN 0
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,7 +13,10 @@ extern "C" {
#endif #endif
/* /*
Registers and fields were generated based on a set of configuration options. Registers and fields were generated based on a set of USB-DWC configuration options.
ESP32-P4 contains 2 instances of USB-DWC with different configurations, the structure below corresponds to the HS instance.
The FS instance contains a subset of registers from HS instance, the user (HAL) is responsible for accessing only existing fields.
See ESP32-P4 "usb_dwc_cfg.h" for more details. See ESP32-P4 "usb_dwc_cfg.h" for more details.
*/ */
@ -1368,6 +1371,7 @@ _Static_assert(sizeof(usb_dwc_dev_t) == 0xe08, "Invalid size of usb_dwc_dev_t st
#endif #endif
extern usb_dwc_dev_t USB_DWC_HS; extern usb_dwc_dev_t USB_DWC_HS;
extern usb_dwc_dev_t USB_DWC_FS;
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -88,7 +88,7 @@ typedef union {
struct { struct {
uint32_t toutcal: 3; uint32_t toutcal: 3;
uint32_t phyif: 1; uint32_t phyif: 1;
uint32_t reserved_4: 1; uint32_t ulpiutmisel: 1;
uint32_t fsintf: 1; uint32_t fsintf: 1;
uint32_t physel: 1; uint32_t physel: 1;
uint32_t reserved_7: 1; uint32_t reserved_7: 1;

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -88,7 +88,7 @@ typedef union {
struct { struct {
uint32_t toutcal: 3; uint32_t toutcal: 3;
uint32_t phyif: 1; uint32_t phyif: 1;
uint32_t reserved_4: 1; uint32_t ulpiutmisel: 1;
uint32_t fsintf: 1; uint32_t fsintf: 1;
uint32_t physel: 1; uint32_t physel: 1;
uint32_t reserved_7: 1; uint32_t reserved_7: 1;

View File

@ -1274,7 +1274,9 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
port_obj->callback = port_config->callback; port_obj->callback = port_config->callback;
port_obj->callback_arg = port_config->callback_arg; port_obj->callback_arg = port_config->callback_arg;
port_obj->context = port_config->context; port_obj->context = port_config->context;
usb_dwc_hal_init(port_obj->hal); usb_dwc_hal_init(port_obj->hal, 0);
port_obj->hal->channels.hdls = calloc(port_obj->hal->constant_config.chan_num_total, sizeof(usb_dwc_hal_chan_t*));
HCD_CHECK_FROM_CRIT(port_obj->hal->channels.hdls != NULL, ESP_ERR_NO_MEM);
port_obj->initialized = true; port_obj->initialized = true;
// Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset // Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset
memset(port_obj->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); memset(port_obj->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t));
@ -1298,6 +1300,7 @@ esp_err_t hcd_port_deinit(hcd_port_handle_t port_hdl)
ESP_ERR_INVALID_STATE); ESP_ERR_INVALID_STATE);
port->initialized = false; port->initialized = false;
esp_intr_disable(s_hcd_obj->isr_hdl); esp_intr_disable(s_hcd_obj->isr_hdl);
free(port->hal->channels.hdls);
usb_dwc_hal_deinit(port->hal); usb_dwc_hal_deinit(port->hal);
HCD_EXIT_CRITICAL(); HCD_EXIT_CRITICAL();
@ -1410,14 +1413,14 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl)
&& port->num_pipes_idle == 0 && port->num_pipes_queued == 0 && port->num_pipes_idle == 0 && port->num_pipes_queued == 0
&& port->flags.val == 0 && port->task_waiting_port_notif == NULL, && port->flags.val == 0 && port->task_waiting_port_notif == NULL,
ESP_ERR_INVALID_STATE); ESP_ERR_INVALID_STATE);
// We are about to do a soft reset on the peripheral. Disable the peripheral throughout // We are about to do a soft reset on the peripheral. Disable the peripheral throughout
esp_intr_disable(s_hcd_obj->isr_hdl); esp_intr_disable(s_hcd_obj->isr_hdl);
usb_dwc_hal_core_soft_reset(port->hal); usb_dwc_hal_core_soft_reset(port->hal);
port->state = HCD_PORT_STATE_NOT_POWERED; port->state = HCD_PORT_STATE_NOT_POWERED;
port->last_event = HCD_PORT_EVENT_NONE; port->last_event = HCD_PORT_EVENT_NONE;
port->flags.val = 0; port->flags.val = 0;
// Soft reset wipes all registers so we need to reinitialize the HAL
usb_dwc_hal_init(port->hal);
// Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset // Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset
memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t));
esp_intr_enable(s_hcd_obj->isr_hdl); esp_intr_enable(s_hcd_obj->isr_hdl);

View File

@ -6,7 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "soc/usb_dwc_cfg.h" #include "hal/usb_dwc_ll.h" // For USB-DWC configuration
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "unity.h" #include "unity.h"
@ -17,7 +17,7 @@
#define NUM_URBS 3 #define NUM_URBS 3
#define NUM_PACKETS_PER_URB 3 #define NUM_PACKETS_PER_URB 3
#define POST_ENQUEUE_DELAY_US 20 #define POST_ENQUEUE_DELAY_US 20
#define ENQUEUE_DELAY (OTG_HSPHY_INTERFACE ? 100 : 500) // With this delay we want to enqueue the URBs at different times #define ENQUEUE_DELAY (usb_dwc_ll_ghwcfg_get_hsphy_type(USB_DWC_LL_GET_HW(0)) ? 100 : 500) // With this delay we want to enqueue the URBs at different times
/* /*
Test HCD ISOC pipe URBs Test HCD ISOC pipe URBs
@ -126,12 +126,12 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed][high_speed]"
uint8_t dev_addr = test_hcd_enum_device(default_pipe); uint8_t dev_addr = test_hcd_enum_device(default_pipe);
urb_t *urb_list[NUM_URBS]; urb_t *urb_list[NUM_URBS];
hcd_pipe_handle_t unused_pipes[OTG_NUM_HOST_CHAN]; hcd_pipe_handle_t unused_pipes[16];
const usb_ep_desc_t *out_ep_desc = dev_isoc_get_out_ep_desc(port_speed); const usb_ep_desc_t *out_ep_desc = dev_isoc_get_out_ep_desc(port_speed);
const int isoc_packet_size = USB_EP_DESC_GET_MPS(out_ep_desc); const int isoc_packet_size = USB_EP_DESC_GET_MPS(out_ep_desc);
// For all channels // For all channels (except channel allocated for EP0)
for (int channel = 0; channel < OTG_NUM_HOST_CHAN - 1; channel++) { for (int channel = 0; channel < usb_dwc_ll_ghwcfg_get_channel_num(USB_DWC_LL_GET_HW(0)) - 1; channel++) {
// Allocate unused pipes, so the active isoc_out_pipe uses different channel index // Allocate unused pipes, so the active isoc_out_pipe uses different channel index
for (int ch = 0; ch < channel; ch++) { for (int ch = 0; ch < channel; ch++) {
unused_pipes[ch] = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr + 1, port_speed); unused_pipes[ch] = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr + 1, port_speed);