2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2007-12-01 11:07:04 -05:00
/*
* drivers / usb / host / ehci - orion . c
*
* Tzachi Perelstein < tzachi @ marvell . com >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
2008-03-27 14:51:39 -04:00
# include <linux/mbus.h>
2012-04-15 12:53:47 +02:00
# include <linux/clk.h>
2012-08-24 15:21:54 +02:00
# include <linux/platform_data/usb-ehci-orion.h>
2012-10-20 13:10:00 +02:00
# include <linux/of.h>
2014-05-15 12:17:29 +02:00
# include <linux/phy/phy.h>
2012-10-20 13:10:00 +02:00
# include <linux/of_device.h>
# include <linux/of_irq.h>
2013-04-02 18:23:59 +02:00
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include <linux/io.h>
# include <linux/dma-mapping.h>
# include "ehci.h"
2007-12-01 11:07:04 -05:00
2014-11-13 00:49:50 +01:00
# define rdl(off) readl_relaxed(hcd->regs + (off))
# define wrl(off, val) writel_relaxed((val), hcd->regs + (off))
2007-12-01 11:07:04 -05:00
# define USB_CMD 0x140
2015-03-19 15:01:07 +01:00
# define USB_CMD_RUN BIT(0)
# define USB_CMD_RESET BIT(1)
2007-12-01 11:07:04 -05:00
# define USB_MODE 0x1a8
2015-03-19 15:01:07 +01:00
# define USB_MODE_MASK GENMASK(1, 0)
# define USB_MODE_DEVICE 0x2
# define USB_MODE_HOST 0x3
# define USB_MODE_SDIS BIT(4)
2008-03-27 14:51:39 -04:00
# define USB_CAUSE 0x310
# define USB_MASK 0x314
# define USB_WINDOW_CTRL(i) (0x320 + ((i) << 4))
# define USB_WINDOW_BASE(i) (0x324 + ((i) << 4))
2007-12-01 11:07:04 -05:00
# define USB_IPG 0x360
# define USB_PHY_PWR_CTRL 0x400
# define USB_PHY_TX_CTRL 0x420
# define USB_PHY_RX_CTRL 0x430
# define USB_PHY_IVREF_CTRL 0x440
# define USB_PHY_TST_GRP_CTRL 0x450
2017-03-09 18:52:56 +01:00
# define USB_SBUSCFG 0x90
/* BAWR = BARD = 3 : Align read/write bursts packets larger than 128 bytes */
# define USB_SBUSCFG_BAWR_ALIGN_128B (0x3 << 6)
# define USB_SBUSCFG_BARD_ALIGN_128B (0x3 << 3)
/* AHBBRST = 3 : Align AHB Burst to INCR16 (64 bytes) */
# define USB_SBUSCFG_AHBBRST_INCR16 (0x3 << 0)
# define USB_SBUSCFG_DEF_VAL (USB_SBUSCFG_BAWR_ALIGN_128B \
| USB_SBUSCFG_BARD_ALIGN_128B \
| USB_SBUSCFG_AHBBRST_INCR16 )
2013-04-02 18:23:59 +02:00
# define DRIVER_DESC "EHCI orion driver"
2014-05-15 12:17:28 +02:00
# define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv)
struct orion_ehci_hcd {
struct clk * clk ;
2014-05-15 12:17:29 +02:00
struct phy * phy ;
2014-05-15 12:17:28 +02:00
} ;
2013-04-02 18:23:59 +02:00
static const char hcd_name [ ] = " ehci-orion " ;
static struct hc_driver __read_mostly ehci_orion_hc_driver ;
2007-12-01 11:07:04 -05:00
/*
* Implement Orion USB controller specification guidelines
*/
2008-09-17 10:08:05 +03:00
static void orion_usb_phy_v1_setup ( struct usb_hcd * hcd )
2007-12-01 11:07:04 -05:00
{
2008-09-17 10:08:05 +03:00
/* The below GLs are according to the Orion Errata document */
2007-12-01 11:07:04 -05:00
/*
* Clear interrupt cause and mask
*/
wrl ( USB_CAUSE , 0 ) ;
wrl ( USB_MASK , 0 ) ;
/*
* Reset controller
*/
2015-03-19 15:01:07 +01:00
wrl ( USB_CMD , rdl ( USB_CMD ) | USB_CMD_RESET ) ;
while ( rdl ( USB_CMD ) & USB_CMD_RESET ) ;
2007-12-01 11:07:04 -05:00
/*
* GL # USB - 10 : Set IPG for non start of frame packets
* Bits [ 14 : 8 ] = 0xc
*/
wrl ( USB_IPG , ( rdl ( USB_IPG ) & ~ 0x7f00 ) | 0xc00 ) ;
/*
* GL # USB - 9 : USB 2.0 Power Control
* BG_VSEL [ 7 : 6 ] = 0x1
*/
wrl ( USB_PHY_PWR_CTRL , ( rdl ( USB_PHY_PWR_CTRL ) & ~ 0xc0 ) | 0x40 ) ;
/*
* GL # USB - 1 : USB PHY Tx Control - force calibration to ' 8 '
* TXDATA_BLOCK_EN [ 21 ] = 0x1 , EXT_RCAL_EN [ 13 ] = 0x1 , IMP_CAL [ 6 : 3 ] = 0x8
*/
wrl ( USB_PHY_TX_CTRL , ( rdl ( USB_PHY_TX_CTRL ) & ~ 0x78 ) | 0x202040 ) ;
/*
* GL # USB - 3 GL # USB - 9 : USB PHY Rx Control
* RXDATA_BLOCK_LENGHT [ 31 : 30 ] = 0x3 , EDGE_DET_SEL [ 27 : 26 ] = 0 ,
* CDR_FASTLOCK_EN [ 21 ] = 0 , DISCON_THRESHOLD [ 9 : 8 ] = 0 , SQ_THRESH [ 7 : 4 ] = 0x1
*/
wrl ( USB_PHY_RX_CTRL , ( rdl ( USB_PHY_RX_CTRL ) & ~ 0xc2003f0 ) | 0xc0000010 ) ;
/*
* GL # USB - 3 GL # USB - 9 : USB PHY IVREF Control
* PLLVDD12 [ 1 : 0 ] = 0x2 , RXVDD [ 5 : 4 ] = 0x3 , Reserved [ 19 ] = 0
*/
wrl ( USB_PHY_IVREF_CTRL , ( rdl ( USB_PHY_IVREF_CTRL ) & ~ 0x80003 ) | 0x32 ) ;
/*
* GL # USB - 3 GL # USB - 9 : USB PHY Test Group Control
* REG_FIFO_SQ_RST [ 15 ] = 0
*/
wrl ( USB_PHY_TST_GRP_CTRL , rdl ( USB_PHY_TST_GRP_CTRL ) & ~ 0x8000 ) ;
/*
* Stop and reset controller
*/
2015-03-19 15:01:07 +01:00
wrl ( USB_CMD , rdl ( USB_CMD ) & ~ USB_CMD_RUN ) ;
wrl ( USB_CMD , rdl ( USB_CMD ) | USB_CMD_RESET ) ;
while ( rdl ( USB_CMD ) & USB_CMD_RESET ) ;
2007-12-01 11:07:04 -05:00
/*
* GL # USB - 5 Streaming disable REG_USB_MODE [ 4 ] = 1
* TBD : This need to be done after each reset !
* GL # USB - 4 Setup USB Host mode
*/
2015-03-19 15:01:07 +01:00
wrl ( USB_MODE , USB_MODE_SDIS | USB_MODE_HOST ) ;
2007-12-01 11:07:04 -05:00
}
2012-11-19 13:21:48 -05:00
static void
2008-03-27 14:51:39 -04:00
ehci_orion_conf_mbus_windows ( struct usb_hcd * hcd ,
2011-12-07 21:48:07 +01:00
const struct mbus_dram_target_info * dram )
2008-03-27 14:51:39 -04:00
{
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
wrl ( USB_WINDOW_CTRL ( i ) , 0 ) ;
wrl ( USB_WINDOW_BASE ( i ) , 0 ) ;
}
for ( i = 0 ; i < dram - > num_cs ; i + + ) {
2011-12-07 21:48:07 +01:00
const struct mbus_dram_window * cs = dram - > cs + i ;
2008-03-27 14:51:39 -04:00
wrl ( USB_WINDOW_CTRL ( i ) , ( ( cs - > size - 1 ) & 0xffff0000 ) |
( cs - > mbus_attr < < 8 ) |
( dram - > mbus_dram_target_id < < 4 ) | 1 ) ;
wrl ( USB_WINDOW_BASE ( i ) , cs - > base ) ;
}
}
2017-03-09 18:52:56 +01:00
static int ehci_orion_drv_reset ( struct usb_hcd * hcd )
{
struct device * dev = hcd - > self . controller ;
int ret ;
ret = ehci_setup ( hcd ) ;
if ( ret )
return ret ;
/*
* For SoC without hlock , need to program sbuscfg value to guarantee
* AHB master ' s burst would not overrun or underrun FIFO .
*
* sbuscfg reg has to be set after usb controller reset , otherwise
* the value would be override to 0.
*/
if ( of_device_is_compatible ( dev - > of_node , " marvell,armada-3700-ehci " ) )
wrl ( USB_SBUSCFG , USB_SBUSCFG_DEF_VAL ) ;
return ret ;
}
2019-01-29 10:23:43 +01:00
static int __maybe_unused ehci_orion_drv_suspend ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
return ehci_suspend ( hcd , device_may_wakeup ( dev ) ) ;
}
static int __maybe_unused ehci_orion_drv_resume ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
return ehci_resume ( hcd , false ) ;
}
static SIMPLE_DEV_PM_OPS ( ehci_orion_pm_ops , ehci_orion_drv_suspend ,
ehci_orion_drv_resume ) ;
2014-05-15 12:17:28 +02:00
static const struct ehci_driver_overrides orion_overrides __initconst = {
. extra_priv_size = sizeof ( struct orion_ehci_hcd ) ,
2017-03-09 18:52:56 +01:00
. reset = ehci_orion_drv_reset ,
2014-05-15 12:17:28 +02:00
} ;
2012-11-19 13:21:48 -05:00
static int ehci_orion_drv_probe ( struct platform_device * pdev )
2007-12-01 11:07:04 -05:00
{
2013-07-30 19:59:40 +09:00
struct orion_ehci_data * pd = dev_get_platdata ( & pdev - > dev ) ;
2011-12-07 21:48:07 +01:00
const struct mbus_dram_target_info * dram ;
2007-12-01 11:07:04 -05:00
struct resource * res ;
struct usb_hcd * hcd ;
struct ehci_hcd * ehci ;
void __iomem * regs ;
int irq , err ;
2012-10-20 13:10:00 +02:00
enum orion_ehci_phy_ver phy_version ;
2014-05-15 12:17:28 +02:00
struct orion_ehci_hcd * priv ;
2007-12-01 11:07:04 -05:00
if ( usb_disabled ( ) )
return - ENODEV ;
pr_debug ( " Initializing Orion-SoC USB Host Controller \n " ) ;
2014-05-15 12:17:26 +02:00
irq = platform_get_irq ( pdev , 0 ) ;
2007-12-01 11:07:04 -05:00
if ( irq < = 0 ) {
err = - ENODEV ;
2014-05-15 12:17:27 +02:00
goto err ;
2007-12-01 11:07:04 -05:00
}
2012-10-20 13:10:00 +02:00
/*
* Right now device - tree probed devices don ' t get dma_mask
* set . Since shared usb code relies on it , set it here for
* now . Once we have dma capability bindings this can go away .
*/
2013-06-27 12:36:37 +01:00
err = dma_coerce_mask_and_coherent ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
2013-06-10 16:28:49 +01:00
if ( err )
2014-05-15 12:17:27 +02:00
goto err ;
2012-10-20 13:10:00 +02:00
2014-11-04 07:51:24 +05:30
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-12-11 16:16:33 +09:00
regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( regs ) ) {
err = PTR_ERR ( regs ) ;
2014-05-15 12:17:27 +02:00
goto err ;
2007-12-01 11:07:04 -05:00
}
hcd = usb_create_hcd ( & ehci_orion_hc_driver ,
2008-05-02 06:02:41 +02:00
& pdev - > dev , dev_name ( & pdev - > dev ) ) ;
2007-12-01 11:07:04 -05:00
if ( ! hcd ) {
err = - ENOMEM ;
2014-05-15 12:17:28 +02:00
goto err ;
2007-12-01 11:07:04 -05:00
}
hcd - > rsrc_start = res - > start ;
2009-12-14 18:13:00 -05:00
hcd - > rsrc_len = resource_size ( res ) ;
2007-12-01 11:07:04 -05:00
hcd - > regs = regs ;
ehci = hcd_to_ehci ( hcd ) ;
ehci - > caps = hcd - > regs + 0x100 ;
2008-05-20 16:58:11 -04:00
hcd - > has_tt = 1 ;
2007-12-01 11:07:04 -05:00
2014-05-15 12:17:28 +02:00
priv = hcd_to_orion_priv ( hcd ) ;
/*
* Not all platforms can gate the clock , so it is not an error if
* the clock does not exists .
*/
priv - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( ! IS_ERR ( priv - > clk ) )
clk_prepare_enable ( priv - > clk ) ;
2014-05-15 12:17:29 +02:00
priv - > phy = devm_phy_optional_get ( & pdev - > dev , " usb " ) ;
if ( IS_ERR ( priv - > phy ) ) {
err = PTR_ERR ( priv - > phy ) ;
2015-08-23 15:01:08 +02:00
if ( err ! = - ENOSYS )
2019-01-29 10:23:42 +01:00
goto err_dis_clk ;
2014-05-15 12:17:29 +02:00
}
2008-03-27 14:51:39 -04:00
/*
* ( Re - ) program MBUS remapping windows if we are asked to .
*/
2011-12-07 21:48:07 +01:00
dram = mv_mbus_dram_info ( ) ;
if ( dram )
ehci_orion_conf_mbus_windows ( hcd , dram ) ;
2008-03-27 14:51:39 -04:00
2007-12-01 11:07:04 -05:00
/*
2008-09-17 10:08:05 +03:00
* setup Orion USB controller .
2007-12-01 11:07:04 -05:00
*/
2012-10-20 13:10:00 +02:00
if ( pdev - > dev . of_node )
phy_version = EHCI_PHY_NA ;
else
phy_version = pd - > phy_version ;
switch ( phy_version ) {
2008-09-17 10:08:05 +03:00
case EHCI_PHY_NA : /* dont change USB phy settings */
break ;
case EHCI_PHY_ORION :
orion_usb_phy_v1_setup ( hcd ) ;
break ;
case EHCI_PHY_DD :
case EHCI_PHY_KW :
default :
2013-12-10 21:20:30 +09:00
dev_warn ( & pdev - > dev , " USB phy version isn't supported. \n " ) ;
2008-09-17 10:08:05 +03:00
}
2007-12-01 11:07:04 -05:00
2011-09-07 16:10:52 +08:00
err = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
2007-12-01 11:07:04 -05:00
if ( err )
2019-01-29 10:23:42 +01:00
goto err_dis_clk ;
2007-12-01 11:07:04 -05:00
2013-11-05 10:46:02 +08:00
device_wakeup_enable ( hcd - > self . controller ) ;
2007-12-01 11:07:04 -05:00
return 0 ;
2019-01-29 10:23:42 +01:00
err_dis_clk :
2014-05-15 12:17:28 +02:00
if ( ! IS_ERR ( priv - > clk ) )
clk_disable_unprepare ( priv - > clk ) ;
2013-12-11 16:16:33 +09:00
usb_put_hcd ( hcd ) ;
2014-05-15 12:17:27 +02:00
err :
2007-12-01 11:07:04 -05:00
dev_err ( & pdev - > dev , " init %s fail, %d \n " ,
2008-05-02 06:02:41 +02:00
dev_name ( & pdev - > dev ) , err ) ;
2007-12-01 11:07:04 -05:00
return err ;
}
2013-02-24 00:55:07 -08:00
static int ehci_orion_drv_remove ( struct platform_device * pdev )
2007-12-01 11:07:04 -05:00
{
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2014-05-15 12:17:28 +02:00
struct orion_ehci_hcd * priv = hcd_to_orion_priv ( hcd ) ;
2007-12-01 11:07:04 -05:00
usb_remove_hcd ( hcd ) ;
2014-05-15 12:17:28 +02:00
if ( ! IS_ERR ( priv - > clk ) )
clk_disable_unprepare ( priv - > clk ) ;
2007-12-01 11:07:04 -05:00
usb_put_hcd ( hcd ) ;
return 0 ;
}
2012-12-21 13:14:52 -08:00
static const struct of_device_id ehci_orion_dt_ids [ ] = {
2012-10-20 13:10:00 +02:00
{ . compatible = " marvell,orion-ehci " , } ,
2017-03-09 18:52:56 +01:00
{ . compatible = " marvell,armada-3700-ehci " , } ,
2012-10-20 13:10:00 +02:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ehci_orion_dt_ids ) ;
2007-12-01 11:07:04 -05:00
static struct platform_driver ehci_orion_driver = {
. probe = ehci_orion_drv_probe ,
2013-02-24 00:55:07 -08:00
. remove = ehci_orion_drv_remove ,
2007-12-01 11:07:04 -05:00
. shutdown = usb_hcd_platform_shutdown ,
2012-10-20 13:10:00 +02:00
. driver = {
. name = " orion-ehci " ,
2013-05-21 17:17:18 +05:30
. of_match_table = ehci_orion_dt_ids ,
2019-01-29 10:23:43 +01:00
. pm = & ehci_orion_pm_ops ,
2012-10-20 13:10:00 +02:00
} ,
2007-12-01 11:07:04 -05:00
} ;
2013-04-02 18:23:59 +02:00
static int __init ehci_orion_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
2014-05-15 12:17:28 +02:00
ehci_init_driver ( & ehci_orion_hc_driver , & orion_overrides ) ;
2013-04-02 18:23:59 +02:00
return platform_driver_register ( & ehci_orion_driver ) ;
}
module_init ( ehci_orion_init ) ;
static void __exit ehci_orion_cleanup ( void )
{
platform_driver_unregister ( & ehci_orion_driver ) ;
}
module_exit ( ehci_orion_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_ALIAS ( " platform:orion-ehci " ) ;
MODULE_AUTHOR ( " Tzachi Perelstein " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;