2013-02-25 20:14:33 +04:00
/*
* Universal Flash Storage Host controller PCI glue driver
*
* This code is based on drivers / scsi / ufs / ufshcd - pci . c
* Copyright ( C ) 2011 - 2013 Samsung India Software Operations
*
* Authors :
* Santosh Yaraganavi < santosh . sy @ samsung . com >
* Vinayak Holikatti < h . vinayak @ samsung . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* See the COPYING file in the top - level directory or visit
* < http : //www.gnu.org/licenses/gpl-2.0.html>
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* This program is provided " AS IS " and " WITH ALL FAULTS " and
* without warranty of any kind . You are solely responsible for
* determining the appropriateness of using and distributing
* the program and assume all risks associated with your exercise
* of rights with respect to the program , including but not limited
* to infringement of third party rights , the risks and costs of
* program errors , damage to or loss of data , programs or equipment ,
* and unavailability or interruption of operations . Under no
* circumstances will the contributor of this Program be liable for
* any damages of any kind arising from your use or distribution of
* this program .
*/
# include "ufshcd.h"
# include <linux/pci.h>
2013-07-29 23:06:00 +04:00
# include <linux/pm_runtime.h>
2013-02-25 20:14:33 +04:00
2017-06-06 14:35:31 +03:00
static int ufs_intel_disable_lcc ( struct ufs_hba * hba )
{
u32 attr = UIC_ARG_MIB ( PA_LOCAL_TX_LCC_ENABLE ) ;
u32 lcc_enable = 0 ;
ufshcd_dme_get ( hba , attr , & lcc_enable ) ;
if ( lcc_enable )
ufshcd_dme_set ( hba , attr , 0 ) ;
return 0 ;
}
static int ufs_intel_link_startup_notify ( struct ufs_hba * hba ,
enum ufs_notify_change_status status )
{
int err = 0 ;
switch ( status ) {
case PRE_CHANGE :
err = ufs_intel_disable_lcc ( hba ) ;
break ;
case POST_CHANGE :
break ;
default :
break ;
}
return err ;
}
static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = {
. name = " intel-pci " ,
. link_startup_notify = ufs_intel_link_startup_notify ,
} ;
2017-06-06 14:35:30 +03:00
# ifdef CONFIG_PM_SLEEP
2013-02-25 20:14:33 +04:00
/**
* ufshcd_pci_suspend - suspend power management function
2018-03-02 02:07:20 +03:00
* @ dev : pointer to PCI device handle
2013-02-25 20:14:33 +04:00
*
2014-09-25 16:32:30 +04:00
* Returns 0 if successful
* Returns non - zero otherwise
2013-02-25 20:14:33 +04:00
*/
2013-07-29 23:06:00 +04:00
static int ufshcd_pci_suspend ( struct device * dev )
2013-02-25 20:14:33 +04:00
{
2014-09-25 16:32:30 +04:00
return ufshcd_system_suspend ( dev_get_drvdata ( dev ) ) ;
2013-02-25 20:14:33 +04:00
}
/**
* ufshcd_pci_resume - resume power management function
2018-03-02 02:07:20 +03:00
* @ dev : pointer to PCI device handle
2013-02-25 20:14:33 +04:00
*
2014-09-25 16:32:30 +04:00
* Returns 0 if successful
* Returns non - zero otherwise
2013-02-25 20:14:33 +04:00
*/
2013-07-29 23:06:00 +04:00
static int ufshcd_pci_resume ( struct device * dev )
2013-02-25 20:14:33 +04:00
{
2014-09-25 16:32:30 +04:00
return ufshcd_system_resume ( dev_get_drvdata ( dev ) ) ;
2013-02-25 20:14:33 +04:00
}
2017-06-06 14:35:30 +03:00
# endif /* !CONFIG_PM_SLEEP */
2013-02-25 20:14:33 +04:00
2017-06-06 14:35:30 +03:00
# ifdef CONFIG_PM
2013-07-29 23:06:00 +04:00
static int ufshcd_pci_runtime_suspend ( struct device * dev )
{
2014-09-25 16:32:30 +04:00
return ufshcd_runtime_suspend ( dev_get_drvdata ( dev ) ) ;
2013-07-29 23:06:00 +04:00
}
static int ufshcd_pci_runtime_resume ( struct device * dev )
{
2014-09-25 16:32:30 +04:00
return ufshcd_runtime_resume ( dev_get_drvdata ( dev ) ) ;
2013-07-29 23:06:00 +04:00
}
static int ufshcd_pci_runtime_idle ( struct device * dev )
{
2014-09-25 16:32:30 +04:00
return ufshcd_runtime_idle ( dev_get_drvdata ( dev ) ) ;
2013-07-29 23:06:00 +04:00
}
2017-06-06 14:35:30 +03:00
# endif /* !CONFIG_PM */
2013-07-29 23:06:00 +04:00
2013-02-25 20:14:33 +04:00
/**
* ufshcd_pci_shutdown - main function to put the controller in reset state
* @ pdev : pointer to PCI device handle
*/
static void ufshcd_pci_shutdown ( struct pci_dev * pdev )
{
2014-09-25 16:32:30 +04:00
ufshcd_shutdown ( ( struct ufs_hba * ) pci_get_drvdata ( pdev ) ) ;
2013-02-25 20:14:33 +04:00
}
/**
* ufshcd_pci_remove - de - allocate PCI / SCSI host and host memory space
* data structure memory
2018-03-02 02:07:20 +03:00
* @ pdev : pointer to PCI handle
2013-02-25 20:14:33 +04:00
*/
static void ufshcd_pci_remove ( struct pci_dev * pdev )
{
struct ufs_hba * hba = pci_get_drvdata ( pdev ) ;
2013-07-29 23:06:00 +04:00
pm_runtime_forbid ( & pdev - > dev ) ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
2013-02-25 20:14:33 +04:00
ufshcd_remove ( hba ) ;
2016-10-28 03:25:58 +03:00
ufshcd_dealloc_host ( hba ) ;
2013-02-25 20:14:33 +04:00
}
/**
* ufshcd_pci_probe - probe routine of the driver
* @ pdev : pointer to PCI device handle
* @ id : PCI device id
*
* Returns 0 on success , non - zero value on failure
*/
static int
ufshcd_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
{
struct ufs_hba * hba ;
void __iomem * mmio_base ;
int err ;
2013-07-29 23:06:01 +04:00
err = pcim_enable_device ( pdev ) ;
2013-02-25 20:14:33 +04:00
if ( err ) {
2013-07-29 23:06:01 +04:00
dev_err ( & pdev - > dev , " pcim_enable_device failed \n " ) ;
return err ;
2013-02-25 20:14:33 +04:00
}
pci_set_master ( pdev ) ;
2013-07-29 23:06:01 +04:00
err = pcim_iomap_regions ( pdev , 1 < < 0 , UFSHCD ) ;
2013-02-25 20:14:33 +04:00
if ( err < 0 ) {
2013-07-29 23:06:01 +04:00
dev_err ( & pdev - > dev , " request and iomap failed \n " ) ;
return err ;
2013-02-25 20:14:33 +04:00
}
2013-07-29 23:06:01 +04:00
mmio_base = pcim_iomap_table ( pdev ) [ 0 ] ;
2013-02-25 20:14:33 +04:00
2014-09-25 16:32:21 +04:00
err = ufshcd_alloc_host ( & pdev - > dev , & hba ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Allocation failed \n " ) ;
return err ;
}
2017-06-06 14:35:31 +03:00
hba - > vops = ( struct ufs_hba_variant_ops * ) id - > driver_data ;
2014-09-25 16:32:21 +04:00
err = ufshcd_init ( hba , mmio_base , pdev - > irq ) ;
2013-02-25 20:14:33 +04:00
if ( err ) {
dev_err ( & pdev - > dev , " Initialization failed \n " ) ;
2016-10-28 03:25:58 +03:00
ufshcd_dealloc_host ( hba ) ;
2013-07-29 23:06:01 +04:00
return err ;
2013-02-25 20:14:33 +04:00
}
pci_set_drvdata ( pdev , hba ) ;
2013-07-29 23:06:00 +04:00
pm_runtime_put_noidle ( & pdev - > dev ) ;
pm_runtime_allow ( & pdev - > dev ) ;
2013-02-25 20:14:33 +04:00
return 0 ;
}
2013-07-29 23:06:00 +04:00
static const struct dev_pm_ops ufshcd_pci_pm_ops = {
2017-06-06 14:35:30 +03:00
SET_SYSTEM_SLEEP_PM_OPS ( ufshcd_pci_suspend ,
ufshcd_pci_resume )
SET_RUNTIME_PM_OPS ( ufshcd_pci_runtime_suspend ,
ufshcd_pci_runtime_resume ,
ufshcd_pci_runtime_idle )
2013-07-29 23:06:00 +04:00
} ;
2014-08-08 17:56:03 +04:00
static const struct pci_device_id ufshcd_pci_tbl [ ] = {
2013-02-25 20:14:33 +04:00
{ PCI_VENDOR_ID_SAMSUNG , 0xC00C , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2017-06-06 14:35:31 +03:00
{ PCI_VDEVICE ( INTEL , 0x9DFA ) , ( kernel_ulong_t ) & ufs_intel_cnl_hba_vops } ,
2019-06-21 15:19:42 +03:00
{ PCI_VDEVICE ( INTEL , 0x4B41 ) , ( kernel_ulong_t ) & ufs_intel_cnl_hba_vops } ,
{ PCI_VDEVICE ( INTEL , 0x4B43 ) , ( kernel_ulong_t ) & ufs_intel_cnl_hba_vops } ,
2013-02-25 20:14:33 +04:00
{ } /* terminate list */
} ;
MODULE_DEVICE_TABLE ( pci , ufshcd_pci_tbl ) ;
static struct pci_driver ufshcd_pci_driver = {
. name = UFSHCD ,
. id_table = ufshcd_pci_tbl ,
. probe = ufshcd_pci_probe ,
. remove = ufshcd_pci_remove ,
. shutdown = ufshcd_pci_shutdown ,
2013-07-29 23:06:00 +04:00
. driver = {
. pm = & ufshcd_pci_pm_ops
} ,
2013-02-25 20:14:33 +04:00
} ;
module_pci_driver ( ufshcd_pci_driver ) ;
MODULE_AUTHOR ( " Santosh Yaragnavi <santosh.sy@samsung.com> " ) ;
MODULE_AUTHOR ( " Vinayak Holikatti <h.vinayak@samsung.com> " ) ;
MODULE_DESCRIPTION ( " UFS host controller PCI glue driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( UFSHCD_DRIVER_VERSION ) ;