/* * Copyright (c) 2024, sakumisu * * SPDX-License-Identifier: Apache-2.0 */ #include "usbh_core.h" #include "fsl_common.h" #include "usb_chipidea_reg.h" #define USB_DEVICE_CONFIG_EHCI 1 /*! @brief USB controller ID */ typedef enum _usb_controller_index { kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */ kUSB_ControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved to be used in the future. */ kUSB_ControllerEhci0 = 2U, /*!< EHCI 0U */ kUSB_ControllerEhci1 = 3U, /*!< EHCI 1U */ } usb_controller_index_t; /* USB PHY condfiguration */ #define BOARD_USB_PHY_D_CAL (0x04U) #define BOARD_USB_PHY_TXCAL45DP (0x07U) #define BOARD_USB_PHY_TXCAL45DM (0x07U) #define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ #if !defined(CONFIG_USB_EHCI_NXP) #error "mcx ehci must config CONFIG_USB_EHCI_NXP" #endif #if !defined(CONFIG_USB_EHCI_HCCR_OFFSET) || CONFIG_USB_EHCI_HCCR_OFFSET != 0x100 #error "mcx ehci must config CONFIG_USB_EHCI_HCCR_OFFSET to 0x100" #endif #if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) #include "usb_phy.h" #endif #if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) void USB1_HS_IRQHandler(void) { extern void USBH_IRQHandler(uint8_t busid); USBH_IRQHandler(0); } #endif void USB_ClockInit(void) { #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U) usb_phy_config_struct_t phyConfig = { BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM, }; #endif #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U) SPC0->ACTIVE_VDELAY = 0x0500; /* Change the power DCDC to 1.8v (By deafult, DCDC is 1.8V), CORELDO to 1.1v (By deafult, CORELDO is 1.0V) */ SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK; SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) | SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u); /* Wait until it is done */ while (SPC0->SC & SPC_SC_BUSY_MASK) ; if (0u == (SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK)) { SCG0->TRIM_LOCK = 0x5a5a0001U; SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK; /* wait LDO ready */ while (0U == (SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK)) ; } SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK | SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK; SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK); /* xtal = 20 ~ 30MHz */ SCG0->SOSCCFG = (1U << SCG_SOSCCFG_RANGE_SHIFT) | (1U << SCG_SOSCCFG_EREFS_SHIFT); SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK; while (1) { if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) { break; } } SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK | SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK; CLOCK_EnableClock(kCLOCK_UsbHs); CLOCK_EnableClock(kCLOCK_UsbHsPhy); CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, 24000000U); CLOCK_EnableUsbhsClock(); USB_EhciPhyInit(kUSB_ControllerEhci0, BOARD_XTAL0_CLK_HZ, &phyConfig); #endif #if defined(USB_DEVICE_CONFIG_KHCI) && (USB_DEVICE_CONFIG_KHCI > 0U) CLOCK_AttachClk(kCLK_48M_to_USB0); CLOCK_EnableClock(kCLOCK_Usb0Ram); CLOCK_EnableClock(kCLOCK_Usb0Fs); CLOCK_EnableUsbfsClock(); #endif } static void usb_host_mode_init(CHIPIDEA_TypeDef *ptr) { /* Set mode to host, must be set immediately after reset */ ptr->USBMODE &= ~USB_USBMODE_CM_MASK; ptr->USBMODE |= USB_USBMODE_CM_SET(3); /* Set the endian */ ptr->USBMODE &= ~USB_USBMODE_ES_MASK; /* Set parallel interface signal */ ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK; /* Set parallel transceiver width */ ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK; /* Not use interrupt threshold. */ ptr->USBCMD &= ~USB_USBCMD_ITC_MASK; } void usb_hc_low_level_init(struct usbh_bus *bus) { USB_ClockInit(); /* Install isr, set priority, and enable IRQ. */ NVIC_SetPriority((IRQn_Type)USB1_HS_IRQn, 3); EnableIRQ((IRQn_Type)USB1_HS_IRQn); } void usb_hc_low_level2_init(struct usbh_bus *bus) { usb_host_mode_init((CHIPIDEA_TypeDef *)(bus->hcd.reg_base)); } void usb_hc_low_level_deinit(struct usbh_bus *bus) { DisableIRQ((IRQn_Type)USB1_HS_IRQn); } uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port) { (void)port; uint8_t speed; CHIPIDEA_TypeDef *ptr = (CHIPIDEA_TypeDef *)bus->hcd.reg_base; speed = USB_PORTSC1_PSPD_GET(ptr->PORTSC1); if (speed == 0x00) { return USB_SPEED_FULL; } if (speed == 0x01) { return USB_SPEED_LOW; } if (speed == 0x02) { USB_EhcihostPhyDisconnectDetectCmd(kUSB_ControllerEhci0, 1); return USB_SPEED_HIGH; } return 0; }