2017-11-06 18:34:09 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-08-16 13:32:40 +03:00
/*
* Copyright ( c ) 2016 , NVIDIA Corporation
*/
# include <linux/clk.h>
2020-12-18 15:02:42 +03:00
# include <linux/io.h>
2017-08-16 13:32:40 +03:00
# include <linux/module.h>
# include <linux/of_device.h>
2021-12-01 02:23:26 +03:00
# include <linux/pm_runtime.h>
2017-08-16 13:32:40 +03:00
# include <linux/reset.h>
2020-12-18 15:02:42 +03:00
# include <linux/usb.h>
2017-08-16 13:32:40 +03:00
# include <linux/usb/chipidea.h>
2020-12-18 15:02:42 +03:00
# include <linux/usb/hcd.h>
# include <linux/usb/of.h>
# include <linux/usb/phy.h>
2021-12-01 02:23:26 +03:00
# include <soc/tegra/common.h>
2020-12-18 15:02:42 +03:00
# include "../host/ehci.h"
2017-08-16 13:32:40 +03:00
# include "ci.h"
2020-12-18 15:02:41 +03:00
struct tegra_usb {
2017-08-16 13:32:40 +03:00
struct ci_hdrc_platform_data data ;
struct platform_device * dev ;
2020-12-18 15:02:42 +03:00
const struct tegra_usb_soc_info * soc ;
2017-08-16 13:32:40 +03:00
struct usb_phy * phy ;
struct clk * clk ;
2020-12-18 15:02:42 +03:00
bool needs_double_reset ;
2017-08-16 13:32:40 +03:00
} ;
2020-12-18 15:02:41 +03:00
struct tegra_usb_soc_info {
2017-08-16 13:32:40 +03:00
unsigned long flags ;
2020-12-18 15:02:42 +03:00
unsigned int txfifothresh ;
enum usb_dr_mode dr_mode ;
} ;
static const struct tegra_usb_soc_info tegra20_ehci_soc_info = {
. flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
2020-12-18 15:02:43 +03:00
CI_HDRC_OVERRIDE_PHY_CONTROL |
CI_HDRC_SUPPORTS_RUNTIME_PM ,
2020-12-18 15:02:42 +03:00
. dr_mode = USB_DR_MODE_HOST ,
. txfifothresh = 10 ,
} ;
static const struct tegra_usb_soc_info tegra30_ehci_soc_info = {
. flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
2020-12-18 15:02:43 +03:00
CI_HDRC_OVERRIDE_PHY_CONTROL |
CI_HDRC_SUPPORTS_RUNTIME_PM ,
2020-12-18 15:02:42 +03:00
. dr_mode = USB_DR_MODE_HOST ,
. txfifothresh = 16 ,
2017-08-16 13:32:40 +03:00
} ;
2020-12-18 15:02:44 +03:00
static const struct tegra_usb_soc_info tegra20_udc_soc_info = {
2020-12-18 15:02:42 +03:00
. flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
2020-12-18 15:02:43 +03:00
CI_HDRC_OVERRIDE_PHY_CONTROL |
CI_HDRC_SUPPORTS_RUNTIME_PM ,
2020-12-18 15:02:42 +03:00
. dr_mode = USB_DR_MODE_UNKNOWN ,
2020-12-18 15:02:44 +03:00
. txfifothresh = 10 ,
} ;
static const struct tegra_usb_soc_info tegra30_udc_soc_info = {
. flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
CI_HDRC_OVERRIDE_PHY_CONTROL |
CI_HDRC_SUPPORTS_RUNTIME_PM ,
. dr_mode = USB_DR_MODE_UNKNOWN ,
. txfifothresh = 16 ,
2017-08-16 13:32:40 +03:00
} ;
2020-12-18 15:02:41 +03:00
static const struct of_device_id tegra_usb_of_match [ ] = {
2017-08-16 13:32:40 +03:00
{
2020-12-18 15:02:42 +03:00
. compatible = " nvidia,tegra20-ehci " ,
. data = & tegra20_ehci_soc_info ,
} , {
. compatible = " nvidia,tegra30-ehci " ,
. data = & tegra30_ehci_soc_info ,
} , {
2017-08-16 13:32:40 +03:00
. compatible = " nvidia,tegra20-udc " ,
2020-12-18 15:02:44 +03:00
. data = & tegra20_udc_soc_info ,
2017-08-16 13:32:40 +03:00
} , {
. compatible = " nvidia,tegra30-udc " ,
2020-12-18 15:02:44 +03:00
. data = & tegra30_udc_soc_info ,
2017-08-16 13:32:40 +03:00
} , {
. compatible = " nvidia,tegra114-udc " ,
2020-12-18 15:02:44 +03:00
. data = & tegra30_udc_soc_info ,
2017-08-16 13:32:40 +03:00
} , {
. compatible = " nvidia,tegra124-udc " ,
2020-12-18 15:02:44 +03:00
. data = & tegra30_udc_soc_info ,
2017-08-16 13:32:40 +03:00
} , {
/* sentinel */
}
} ;
2020-12-18 15:02:41 +03:00
MODULE_DEVICE_TABLE ( of , tegra_usb_of_match ) ;
2017-08-16 13:32:40 +03:00
2020-12-18 15:02:42 +03:00
static int tegra_usb_reset_controller ( struct device * dev )
{
struct reset_control * rst , * rst_utmi ;
struct device_node * phy_np ;
int err ;
rst = devm_reset_control_get_shared ( dev , " usb " ) ;
if ( IS_ERR ( rst ) ) {
dev_err ( dev , " can't get ehci reset: %pe \n " , rst ) ;
return PTR_ERR ( rst ) ;
}
phy_np = of_parse_phandle ( dev - > of_node , " nvidia,phy " , 0 ) ;
if ( ! phy_np )
return - ENOENT ;
/*
* The 1 st USB controller contains some UTMI pad registers that are
* global for all the controllers on the chip . Those registers are
* also cleared when reset is asserted to the 1 st controller .
*/
rst_utmi = of_reset_control_get_shared ( phy_np , " utmi-pads " ) ;
if ( IS_ERR ( rst_utmi ) ) {
dev_warn ( dev , " can't get utmi-pads reset from the PHY \n " ) ;
dev_warn ( dev , " continuing, but please update your DT \n " ) ;
} else {
/*
* PHY driver performs UTMI - pads reset in a case of a
* non - legacy DT .
*/
reset_control_put ( rst_utmi ) ;
}
of_node_put ( phy_np ) ;
/* reset control is shared, hence initialize it first */
err = reset_control_deassert ( rst ) ;
if ( err )
return err ;
err = reset_control_assert ( rst ) ;
if ( err )
return err ;
udelay ( 1 ) ;
err = reset_control_deassert ( rst ) ;
if ( err )
return err ;
return 0 ;
}
static int tegra_usb_notify_event ( struct ci_hdrc * ci , unsigned int event )
{
struct tegra_usb * usb = dev_get_drvdata ( ci - > dev - > parent ) ;
struct ehci_hcd * ehci ;
switch ( event ) {
case CI_HDRC_CONTROLLER_RESET_EVENT :
if ( ci - > hcd ) {
ehci = hcd_to_ehci ( ci - > hcd ) ;
ehci - > has_tdi_phy_lpm = false ;
ehci_writel ( ehci , usb - > soc - > txfifothresh < < 16 ,
& ehci - > regs - > txfill_tuning ) ;
}
break ;
}
return 0 ;
}
static int tegra_usb_internal_port_reset ( struct ehci_hcd * ehci ,
u32 __iomem * portsc_reg ,
unsigned long * flags )
{
u32 saved_usbintr , temp ;
unsigned int i , tries ;
int retval = 0 ;
saved_usbintr = ehci_readl ( ehci , & ehci - > regs - > intr_enable ) ;
/* disable USB interrupt */
ehci_writel ( ehci , 0 , & ehci - > regs - > intr_enable ) ;
spin_unlock_irqrestore ( & ehci - > lock , * flags ) ;
/*
* Here we have to do Port Reset at most twice for
* Port Enable bit to be set .
*/
for ( i = 0 ; i < 2 ; i + + ) {
temp = ehci_readl ( ehci , portsc_reg ) ;
temp | = PORT_RESET ;
ehci_writel ( ehci , temp , portsc_reg ) ;
fsleep ( 10000 ) ;
temp & = ~ PORT_RESET ;
ehci_writel ( ehci , temp , portsc_reg ) ;
fsleep ( 1000 ) ;
tries = 100 ;
do {
fsleep ( 1000 ) ;
/*
* Up to this point , Port Enable bit is
* expected to be set after 2 ms waiting .
* USB1 usually takes extra 45 ms , for safety ,
* we take 100 ms as timeout .
*/
temp = ehci_readl ( ehci , portsc_reg ) ;
} while ( ! ( temp & PORT_PE ) & & tries - - ) ;
if ( temp & PORT_PE )
break ;
}
if ( i = = 2 )
retval = - ETIMEDOUT ;
/*
* Clear Connect Status Change bit if it ' s set .
* We can ' t clear PORT_PEC . It will also cause PORT_PE to be cleared .
*/
if ( temp & PORT_CSC )
ehci_writel ( ehci , PORT_CSC , portsc_reg ) ;
/*
* Write to clear any interrupt status bits that might be set
* during port reset .
*/
temp = ehci_readl ( ehci , & ehci - > regs - > status ) ;
ehci_writel ( ehci , temp , & ehci - > regs - > status ) ;
/* restore original interrupt-enable bits */
spin_lock_irqsave ( & ehci - > lock , * flags ) ;
ehci_writel ( ehci , saved_usbintr , & ehci - > regs - > intr_enable ) ;
return retval ;
}
static int tegra_ehci_hub_control ( struct ci_hdrc * ci , u16 typeReq , u16 wValue ,
u16 wIndex , char * buf , u16 wLength ,
bool * done , unsigned long * flags )
{
struct tegra_usb * usb = dev_get_drvdata ( ci - > dev - > parent ) ;
struct ehci_hcd * ehci = hcd_to_ehci ( ci - > hcd ) ;
u32 __iomem * status_reg ;
int retval = 0 ;
status_reg = & ehci - > regs - > port_status [ ( wIndex & 0xff ) - 1 ] ;
switch ( typeReq ) {
case SetPortFeature :
if ( wValue ! = USB_PORT_FEAT_RESET | | ! usb - > needs_double_reset )
break ;
/* for USB1 port we need to issue Port Reset twice internally */
retval = tegra_usb_internal_port_reset ( ehci , status_reg , flags ) ;
* done = true ;
break ;
}
return retval ;
}
static void tegra_usb_enter_lpm ( struct ci_hdrc * ci , bool enable )
{
/*
* Touching any register which belongs to AHB clock domain will
* hang CPU if USB controller is put into low power mode because
* AHB USB clock is gated on Tegra in the LPM .
*
* Tegra PHY has a separate register for checking the clock status
* and usb_phy_set_suspend ( ) takes care of gating / ungating the clocks
* and restoring the PHY state on Tegra . Hence DEVLC / PORTSC registers
* shouldn ' t be touched directly by the CI driver .
*/
usb_phy_set_suspend ( ci - > usb_phy , enable ) ;
}
2020-12-18 15:02:41 +03:00
static int tegra_usb_probe ( struct platform_device * pdev )
2017-08-16 13:32:40 +03:00
{
2020-12-18 15:02:41 +03:00
const struct tegra_usb_soc_info * soc ;
struct tegra_usb * usb ;
2017-08-16 13:32:40 +03:00
int err ;
2020-12-18 15:02:41 +03:00
usb = devm_kzalloc ( & pdev - > dev , sizeof ( * usb ) , GFP_KERNEL ) ;
if ( ! usb )
2017-08-16 13:32:40 +03:00
return - ENOMEM ;
2021-12-01 02:23:26 +03:00
platform_set_drvdata ( pdev , usb ) ;
2017-08-16 13:32:40 +03:00
soc = of_device_get_match_data ( & pdev - > dev ) ;
if ( ! soc ) {
dev_err ( & pdev - > dev , " failed to match OF data \n " ) ;
return - EINVAL ;
}
2020-12-18 15:02:41 +03:00
usb - > phy = devm_usb_get_phy_by_phandle ( & pdev - > dev , " nvidia,phy " , 0 ) ;
2021-03-14 23:39:27 +03:00
if ( IS_ERR ( usb - > phy ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( usb - > phy ) ,
" failed to get PHY \n " ) ;
2017-08-16 13:32:40 +03:00
2020-12-18 15:02:41 +03:00
usb - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( usb - > clk ) ) {
err = PTR_ERR ( usb - > clk ) ;
2017-08-16 13:32:40 +03:00
dev_err ( & pdev - > dev , " failed to get clock: %d \n " , err ) ;
return err ;
}
2021-12-01 02:23:26 +03:00
err = devm_tegra_core_dev_init_opp_table_common ( & pdev - > dev ) ;
if ( err )
return err ;
pm_runtime_enable ( & pdev - > dev ) ;
err = pm_runtime_resume_and_get ( & pdev - > dev ) ;
if ( err )
2017-08-16 13:32:40 +03:00
return err ;
2020-12-18 15:02:42 +03:00
if ( device_property_present ( & pdev - > dev , " nvidia,needs-double-reset " ) )
usb - > needs_double_reset = true ;
err = tegra_usb_reset_controller ( & pdev - > dev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to reset controller: %d \n " , err ) ;
goto fail_power_off ;
}
/*
* USB controller registers shouldn ' t be touched before PHY is
* initialized , otherwise CPU will hang because clocks are gated .
* PHY driver controls gating of internal USB clocks on Tegra .
*/
err = usb_phy_init ( usb - > phy ) ;
if ( err )
goto fail_power_off ;
2017-08-16 13:32:40 +03:00
/* setup and register ChipIdea HDRC device */
2020-12-18 15:02:42 +03:00
usb - > soc = soc ;
2020-12-18 15:02:41 +03:00
usb - > data . name = " tegra-usb " ;
usb - > data . flags = soc - > flags ;
usb - > data . usb_phy = usb - > phy ;
2020-12-18 15:02:42 +03:00
usb - > data . dr_mode = soc - > dr_mode ;
2020-12-18 15:02:41 +03:00
usb - > data . capoffset = DEF_CAPOFFSET ;
2020-12-18 15:02:42 +03:00
usb - > data . enter_lpm = tegra_usb_enter_lpm ;
usb - > data . hub_control = tegra_ehci_hub_control ;
usb - > data . notify_event = tegra_usb_notify_event ;
2020-12-18 15:02:41 +03:00
2020-12-18 15:02:43 +03:00
/* Tegra PHY driver currently doesn't support LPM for ULPI */
if ( of_usb_get_phy_mode ( pdev - > dev . of_node ) = = USBPHY_INTERFACE_MODE_ULPI )
usb - > data . flags & = ~ CI_HDRC_SUPPORTS_RUNTIME_PM ;
2020-12-18 15:02:41 +03:00
usb - > dev = ci_hdrc_add_device ( & pdev - > dev , pdev - > resource ,
pdev - > num_resources , & usb - > data ) ;
if ( IS_ERR ( usb - > dev ) ) {
err = PTR_ERR ( usb - > dev ) ;
2017-08-16 13:32:40 +03:00
dev_err ( & pdev - > dev , " failed to add HDRC device: %d \n " , err ) ;
2020-12-18 15:02:42 +03:00
goto phy_shutdown ;
2017-08-16 13:32:40 +03:00
}
return 0 ;
2020-12-18 15:02:42 +03:00
phy_shutdown :
usb_phy_shutdown ( usb - > phy ) ;
2017-08-16 13:32:40 +03:00
fail_power_off :
2021-12-01 02:23:26 +03:00
pm_runtime_put_sync_suspend ( & pdev - > dev ) ;
pm_runtime_force_suspend ( & pdev - > dev ) ;
2017-08-16 13:32:40 +03:00
return err ;
}
2020-12-18 15:02:41 +03:00
static int tegra_usb_remove ( struct platform_device * pdev )
2017-08-16 13:32:40 +03:00
{
2020-12-18 15:02:41 +03:00
struct tegra_usb * usb = platform_get_drvdata ( pdev ) ;
2017-08-16 13:32:40 +03:00
2020-12-18 15:02:41 +03:00
ci_hdrc_remove_device ( usb - > dev ) ;
2020-12-18 15:02:42 +03:00
usb_phy_shutdown ( usb - > phy ) ;
2021-12-01 02:23:26 +03:00
pm_runtime_put_sync_suspend ( & pdev - > dev ) ;
pm_runtime_force_suspend ( & pdev - > dev ) ;
return 0 ;
}
static int __maybe_unused tegra_usb_runtime_resume ( struct device * dev )
{
struct tegra_usb * usb = dev_get_drvdata ( dev ) ;
int err ;
err = clk_prepare_enable ( usb - > clk ) ;
if ( err < 0 ) {
dev_err ( dev , " failed to enable clock: %d \n " , err ) ;
return err ;
}
return 0 ;
}
static int __maybe_unused tegra_usb_runtime_suspend ( struct device * dev )
{
struct tegra_usb * usb = dev_get_drvdata ( dev ) ;
2020-12-18 15:02:41 +03:00
clk_disable_unprepare ( usb - > clk ) ;
2017-08-16 13:32:40 +03:00
return 0 ;
}
2021-12-01 02:23:26 +03:00
static const struct dev_pm_ops tegra_usb_pm = {
SET_RUNTIME_PM_OPS ( tegra_usb_runtime_suspend , tegra_usb_runtime_resume ,
NULL )
} ;
2020-12-18 15:02:41 +03:00
static struct platform_driver tegra_usb_driver = {
2017-08-16 13:32:40 +03:00
. driver = {
2020-12-18 15:02:41 +03:00
. name = " tegra-usb " ,
. of_match_table = tegra_usb_of_match ,
2021-12-01 02:23:26 +03:00
. pm = & tegra_usb_pm ,
2017-08-16 13:32:40 +03:00
} ,
2020-12-18 15:02:41 +03:00
. probe = tegra_usb_probe ,
. remove = tegra_usb_remove ,
2017-08-16 13:32:40 +03:00
} ;
2020-12-18 15:02:41 +03:00
module_platform_driver ( tegra_usb_driver ) ;
2017-08-16 13:32:40 +03:00
2020-12-18 15:02:41 +03:00
MODULE_DESCRIPTION ( " NVIDIA Tegra USB driver " ) ;
2017-08-16 13:32:40 +03:00
MODULE_AUTHOR ( " Thierry Reding <treding@nvidia.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;