2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2007-01-16 07:12:10 +03:00
/*
* PS3 OHCI Host Controller driver
*
* Copyright ( C ) 2006 Sony Computer Entertainment Inc .
* Copyright 2006 Sony Corp .
*/
2007-06-06 07:04:35 +04:00
# include <asm/firmware.h>
2007-01-16 07:12:10 +03:00
# include <asm/ps3.h>
static int ps3_ohci_hc_reset ( struct usb_hcd * hcd )
{
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
ohci - > flags | = OHCI_QUIRK_BE_MMIO ;
ohci_hcd_init ( ohci ) ;
return ohci_init ( ohci ) ;
}
2012-11-19 22:21:48 +04:00
static int ps3_ohci_hc_start ( struct usb_hcd * hcd )
2007-01-16 07:12:10 +03:00
{
int result ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
/* Handle root hub init quirk in spider south bridge. */
/* Also set PwrOn2PwrGood to 0x7f (254ms). */
ohci_writel ( ohci , 0x7f000000 | RH_A_PSM | RH_A_OCPM ,
& ohci - > regs - > roothub . a ) ;
ohci_writel ( ohci , 0x00060000 , & ohci - > regs - > roothub . b ) ;
result = ohci_run ( ohci ) ;
if ( result < 0 ) {
2012-04-27 22:24:43 +04:00
dev_err ( hcd - > self . controller , " can't start %s \n " ,
hcd - > self . bus_name ) ;
2007-01-16 07:12:10 +03:00
ohci_stop ( hcd ) ;
}
return result ;
}
static const struct hc_driver ps3_ohci_hc_driver = {
. description = hcd_name ,
. product_desc = " PS3 OHCI Host Controller " ,
. hcd_priv_size = sizeof ( struct ohci_hcd ) ,
. irq = ohci_irq ,
. flags = HCD_MEMORY | HCD_USB11 ,
. reset = ps3_ohci_hc_reset ,
. start = ps3_ohci_hc_start ,
. stop = ohci_stop ,
. shutdown = ohci_shutdown ,
. urb_enqueue = ohci_urb_enqueue ,
. urb_dequeue = ohci_urb_dequeue ,
. endpoint_disable = ohci_endpoint_disable ,
. get_frame_number = ohci_get_frame ,
. hub_status_data = ohci_hub_status_data ,
. hub_control = ohci_hub_control ,
. start_port_reset = ohci_start_port_reset ,
# if defined(CONFIG_PM)
. bus_suspend = ohci_bus_suspend ,
. bus_resume = ohci_bus_resume ,
# endif
} ;
2012-11-19 22:21:48 +04:00
static int ps3_ohci_probe ( struct ps3_system_bus_device * dev )
2007-01-16 07:12:10 +03:00
{
int result ;
struct usb_hcd * hcd ;
unsigned int virq ;
2018-07-19 01:08:33 +03:00
static u64 dummy_mask ;
2007-01-16 07:12:10 +03:00
if ( usb_disabled ( ) ) {
result = - ENODEV ;
goto fail_start ;
}
2007-06-06 07:04:35 +04:00
result = ps3_open_hv_device ( dev ) ;
if ( result ) {
dev_dbg ( & dev - > core , " %s:%d: ps3_open_hv_device failed: %s \n " ,
__func__ , __LINE__ , ps3_result ( result ) ) ;
result = - EPERM ;
goto fail_open ;
}
result = ps3_dma_region_create ( dev - > d_region ) ;
if ( result ) {
dev_dbg ( & dev - > core , " %s:%d: ps3_dma_region_create failed: "
" (%d) \n " , __func__ , __LINE__ , result ) ;
BUG_ON ( " check region type " ) ;
goto fail_dma_region ;
}
2007-01-16 07:12:10 +03:00
result = ps3_mmio_region_create ( dev - > m_region ) ;
if ( result ) {
dev_dbg ( & dev - > core , " %s:%d: ps3_map_mmio_region failed \n " ,
__func__ , __LINE__ ) ;
result = - EPERM ;
2007-06-06 07:04:35 +04:00
goto fail_mmio_region ;
2007-01-16 07:12:10 +03:00
}
dev_dbg ( & dev - > core , " %s:%d: mmio mapped_addr %lxh \n " , __func__ ,
__LINE__ , dev - > m_region - > lpar_addr ) ;
2007-05-01 01:01:01 +04:00
result = ps3_io_irq_setup ( PS3_BINDING_CPU_ANY , dev - > interrupt_id , & virq ) ;
2007-01-16 07:12:10 +03:00
if ( result ) {
dev_dbg ( & dev - > core , " %s:%d: ps3_construct_io_irq(%d) failed. \n " ,
__func__ , __LINE__ , virq ) ;
result = - EPERM ;
goto fail_irq ;
}
2018-07-19 01:08:33 +03:00
dummy_mask = DMA_BIT_MASK ( 32 ) ;
dev - > core . dma_mask = & dummy_mask ;
dma_set_coherent_mask ( & dev - > core , dummy_mask ) ;
2007-01-16 07:12:10 +03:00
2008-05-02 08:02:41 +04:00
hcd = usb_create_hcd ( & ps3_ohci_hc_driver , & dev - > core , dev_name ( & dev - > core ) ) ;
2007-01-16 07:12:10 +03:00
if ( ! hcd ) {
dev_dbg ( & dev - > core , " %s:%d: usb_create_hcd failed \n " , __func__ ,
__LINE__ ) ;
result = - ENOMEM ;
goto fail_create_hcd ;
}
hcd - > rsrc_start = dev - > m_region - > lpar_addr ;
hcd - > rsrc_len = dev - > m_region - > len ;
2007-06-06 07:04:35 +04:00
if ( ! request_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len , hcd_name ) )
dev_dbg ( & dev - > core , " %s:%d: request_mem_region failed \n " ,
__func__ , __LINE__ ) ;
2007-01-16 07:12:10 +03:00
hcd - > regs = ioremap ( dev - > m_region - > lpar_addr , dev - > m_region - > len ) ;
if ( ! hcd - > regs ) {
dev_dbg ( & dev - > core , " %s:%d: ioremap failed \n " , __func__ ,
__LINE__ ) ;
result = - EPERM ;
goto fail_ioremap ;
}
dev_dbg ( & dev - > core , " %s:%d: hcd->rsrc_start %lxh \n " , __func__ , __LINE__ ,
( unsigned long ) hcd - > rsrc_start ) ;
dev_dbg ( & dev - > core , " %s:%d: hcd->rsrc_len %lxh \n " , __func__ , __LINE__ ,
( unsigned long ) hcd - > rsrc_len ) ;
dev_dbg ( & dev - > core , " %s:%d: hcd->regs %lxh \n " , __func__ , __LINE__ ,
( unsigned long ) hcd - > regs ) ;
dev_dbg ( & dev - > core , " %s:%d: virq %lu \n " , __func__ , __LINE__ ,
( unsigned long ) virq ) ;
2009-06-10 08:38:54 +04:00
ps3_system_bus_set_drvdata ( dev , hcd ) ;
2007-01-16 07:12:10 +03:00
2011-09-07 12:10:52 +04:00
result = usb_add_hcd ( hcd , virq , 0 ) ;
2007-01-16 07:12:10 +03:00
if ( result ) {
dev_dbg ( & dev - > core , " %s:%d: usb_add_hcd failed (%d) \n " ,
__func__ , __LINE__ , result ) ;
goto fail_add_hcd ;
}
2013-11-05 06:46:02 +04:00
device_wakeup_enable ( hcd - > self . controller ) ;
2007-01-16 07:12:10 +03:00
return result ;
fail_add_hcd :
iounmap ( hcd - > regs ) ;
fail_ioremap :
2007-06-06 07:04:35 +04:00
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
2007-01-16 07:12:10 +03:00
usb_put_hcd ( hcd ) ;
fail_create_hcd :
2007-05-01 01:01:01 +04:00
ps3_io_irq_destroy ( virq ) ;
2007-01-16 07:12:10 +03:00
fail_irq :
ps3_free_mmio_region ( dev - > m_region ) ;
2007-06-06 07:04:35 +04:00
fail_mmio_region :
ps3_dma_region_free ( dev - > d_region ) ;
fail_dma_region :
ps3_close_hv_device ( dev ) ;
fail_open :
2007-01-16 07:12:10 +03:00
fail_start :
return result ;
}
2008-10-31 23:52:54 +03:00
static int ps3_ohci_remove ( struct ps3_system_bus_device * dev )
2007-01-16 07:12:10 +03:00
{
2007-06-06 07:04:35 +04:00
unsigned int tmp ;
2009-06-10 08:38:54 +04:00
struct usb_hcd * hcd = ps3_system_bus_get_drvdata ( dev ) ;
2007-01-16 07:12:10 +03:00
2007-06-06 07:04:35 +04:00
BUG_ON ( ! hcd ) ;
dev_dbg ( & dev - > core , " %s:%d: regs %p \n " , __func__ , __LINE__ , hcd - > regs ) ;
dev_dbg ( & dev - > core , " %s:%d: irq %u \n " , __func__ , __LINE__ , hcd - > irq ) ;
tmp = hcd - > irq ;
2008-10-31 23:52:54 +03:00
ohci_shutdown ( hcd ) ;
2007-06-06 07:04:35 +04:00
usb_remove_hcd ( hcd ) ;
2009-06-10 08:38:54 +04:00
ps3_system_bus_set_drvdata ( dev , NULL ) ;
2007-01-16 07:12:10 +03:00
2007-06-06 07:04:35 +04:00
BUG_ON ( ! hcd - > regs ) ;
iounmap ( hcd - > regs ) ;
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
usb_put_hcd ( hcd ) ;
ps3_io_irq_destroy ( tmp ) ;
ps3_free_mmio_region ( dev - > m_region ) ;
ps3_dma_region_free ( dev - > d_region ) ;
ps3_close_hv_device ( dev ) ;
2007-01-16 07:12:10 +03:00
return 0 ;
}
2009-06-10 08:38:59 +04:00
static int __init ps3_ohci_driver_register ( struct ps3_system_bus_driver * drv )
2007-06-06 07:04:35 +04:00
{
return firmware_has_feature ( FW_FEATURE_PS3_LV1 )
? ps3_system_bus_driver_register ( drv )
: 0 ;
}
static void ps3_ohci_driver_unregister ( struct ps3_system_bus_driver * drv )
{
if ( firmware_has_feature ( FW_FEATURE_PS3_LV1 ) )
ps3_system_bus_driver_unregister ( drv ) ;
}
MODULE_ALIAS ( PS3_MODULE_ALIAS_OHCI ) ;
2007-01-16 07:12:10 +03:00
2007-06-06 07:04:35 +04:00
static struct ps3_system_bus_driver ps3_ohci_driver = {
. core . name = " ps3-ohci-driver " ,
. core . owner = THIS_MODULE ,
2007-01-16 07:12:10 +03:00
. match_id = PS3_MATCH_ID_OHCI ,
2007-06-06 07:04:35 +04:00
. probe = ps3_ohci_probe ,
. remove = ps3_ohci_remove ,
. shutdown = ps3_ohci_remove ,
2007-01-16 07:12:10 +03:00
} ;