2014-07-18 11:12:30 +04:00
/*
* drivers / ata / ahci_tegra . c
*
* Copyright ( c ) 2014 , NVIDIA CORPORATION . All rights reserved .
*
* Author :
* Mikko Perttunen < mperttunen @ nvidia . com >
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 .
*
*/
# include <linux/ahci_platform.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/regulator/consumer.h>
2014-08-26 13:00:30 +04:00
# include <linux/reset.h>
# include <soc/tegra/fuse.h>
2014-08-11 14:17:48 +04:00
# include <soc/tegra/pmc.h>
2014-08-26 13:00:30 +04:00
2014-07-18 11:12:30 +04:00
# include "ahci.h"
2015-01-29 02:30:29 +03:00
# define DRV_NAME "tegra-ahci"
2014-07-18 11:12:30 +04:00
# define SATA_CONFIGURATION_0 0x180
2018-03-12 14:40:33 +03:00
# define SATA_CONFIGURATION_0_EN_FPCI BIT(0)
# define SATA_CONFIGURATION_0_CLK_OVERRIDE BIT(31)
2014-07-18 11:12:30 +04:00
# define SCFG_OFFSET 0x1000
# define T_SATA0_CFG_1 0x04
# define T_SATA0_CFG_1_IO_SPACE BIT(0)
# define T_SATA0_CFG_1_MEMORY_SPACE BIT(1)
# define T_SATA0_CFG_1_BUS_MASTER BIT(2)
# define T_SATA0_CFG_1_SERR BIT(8)
# define T_SATA0_CFG_9 0x24
2018-03-12 14:40:33 +03:00
# define T_SATA0_CFG_9_BASE_ADDRESS 0x40020000
2014-07-18 11:12:30 +04:00
# define SATA_FPCI_BAR5 0x94
2018-03-12 14:40:33 +03:00
# define SATA_FPCI_BAR5_START_MASK (0xfffffff << 4)
# define SATA_FPCI_BAR5_START (0x0040020 << 4)
# define SATA_FPCI_BAR5_ACCESS_TYPE (0x1)
2014-07-18 11:12:30 +04:00
# define SATA_INTR_MASK 0x188
# define SATA_INTR_MASK_IP_INT_MASK BIT(16)
2018-03-12 14:40:33 +03:00
# define T_SATA0_CFG_35 0x94
# define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7ff << 2)
# define T_SATA0_CFG_35_IDP_INDEX (0x2a << 2)
# define T_SATA0_AHCI_IDP1 0x98
# define T_SATA0_AHCI_IDP1_DATA (0x400040)
# define T_SATA0_CFG_PHY_1 0x12c
# define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN BIT(23)
# define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN BIT(22)
# define T_SATA0_NVOOB 0x114
# define T_SATA0_NVOOB_COMMA_CNT_MASK (0xff << 16)
# define T_SATA0_NVOOB_COMMA_CNT (0x07 << 16)
# define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24)
# define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24)
# define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26)
# define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26)
# define T_SATA_CFG_PHY_0 0x120
# define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD BIT(11)
# define T_SATA_CFG_PHY_0_MASK_SQUELCH BIT(24)
# define T_SATA0_CFG2NVOOB_2 0x134
# define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18)
# define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18)
2014-07-18 11:12:30 +04:00
# define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
2018-03-12 14:40:33 +03:00
# define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP BIT(13)
# define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP BIT(14)
# define T_SATA0_AHCI_HBA_CAP_BKDR_SALP BIT(26)
# define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM BIT(17)
# define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ BIT(30)
2014-07-18 11:12:30 +04:00
# define T_SATA0_BKDOOR_CC 0x4a4
2018-03-12 14:40:33 +03:00
# define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK (0xffff << 16)
# define T_SATA0_BKDOOR_CC_CLASS_CODE (0x0106 << 16)
# define T_SATA0_BKDOOR_CC_PROG_IF_MASK (0xff << 8)
# define T_SATA0_BKDOOR_CC_PROG_IF (0x01 << 8)
2014-07-18 11:12:30 +04:00
# define T_SATA0_CFG_SATA 0x54c
# define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
# define T_SATA0_CFG_MISC 0x550
# define T_SATA0_INDEX 0x680
# define T_SATA0_CHX_PHY_CTRL1_GEN1 0x690
# define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK 0xff
# define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT 0
# define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK (0xff << 8)
# define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT 8
# define T_SATA0_CHX_PHY_CTRL1_GEN2 0x694
# define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK 0xff
# define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT 0
# define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK (0xff << 12)
# define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT 12
# define T_SATA0_CHX_PHY_CTRL2 0x69c
# define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 0x23
# define T_SATA0_CHX_PHY_CTRL11 0x6d0
# define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16)
2018-03-12 14:40:33 +03:00
# define T_SATA0_CHX_PHY_CTRL17_0 0x6e8
# define T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1 0x55010000
# define T_SATA0_CHX_PHY_CTRL18_0 0x6ec
# define T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2 0x55010000
# define T_SATA0_CHX_PHY_CTRL20_0 0x6f4
# define T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1 0x1
# define T_SATA0_CHX_PHY_CTRL21_0 0x6f8
# define T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2 0x1
/* AUX Registers */
# define SATA_AUX_MISC_CNTL_1_0 0x8
# define SATA_AUX_MISC_CNTL_1_0_DEVSLP_OVERRIDE BIT(17)
# define SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT BIT(13)
# define SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT BIT(15)
# define SATA_AUX_RX_STAT_INT_0 0xc
# define SATA_AUX_RX_STAT_INT_0_SATA_DEVSLP BIT(7)
# define SATA_AUX_SPARE_CFG0_0 0x18
# define SATA_AUX_SPARE_CFG0_0_MDAT_TIMER_AFTER_PG_VALID BIT(14)
2014-07-18 11:12:30 +04:00
# define FUSE_SATA_CALIB 0x124
# define FUSE_SATA_CALIB_MASK 0x3
struct sata_pad_calibration {
u8 gen1_tx_amp ;
u8 gen1_tx_peak ;
u8 gen2_tx_amp ;
u8 gen2_tx_peak ;
} ;
static const struct sata_pad_calibration tegra124_pad_calibration [ ] = {
{ 0x18 , 0x04 , 0x18 , 0x0a } ,
{ 0x0e , 0x04 , 0x14 , 0x0a } ,
{ 0x0e , 0x07 , 0x1a , 0x0e } ,
{ 0x14 , 0x0e , 0x1a , 0x0e } ,
} ;
2018-03-12 14:40:33 +03:00
struct tegra_ahci_ops {
int ( * init ) ( struct ahci_host_priv * hpriv ) ;
} ;
struct tegra_ahci_soc {
const struct tegra_ahci_ops * ops ;
} ;
2014-07-18 11:12:30 +04:00
struct tegra_ahci_priv {
struct platform_device * pdev ;
void __iomem * sata_regs ;
struct reset_control * sata_rst ;
struct reset_control * sata_oob_rst ;
struct reset_control * sata_cold_rst ;
/* Needs special handling, cannot use ahci_platform */
struct clk * sata_clk ;
struct regulator_bulk_data supplies [ 5 ] ;
2018-03-12 14:40:33 +03:00
const struct tegra_ahci_soc * soc ;
2014-07-18 11:12:30 +04:00
} ;
2018-03-12 14:40:33 +03:00
static int tegra124_ahci_init ( struct ahci_host_priv * hpriv )
{
struct tegra_ahci_priv * tegra = hpriv - > plat_data ;
struct sata_pad_calibration calib ;
int ret ;
u32 val ;
/* Pad calibration */
ret = tegra_fuse_readl ( FUSE_SATA_CALIB , & val ) ;
if ( ret )
return ret ;
calib = tegra124_pad_calibration [ val & FUSE_SATA_CALIB_MASK ] ;
writel ( BIT ( 0 ) , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_INDEX ) ;
val = readl ( tegra - > sata_regs +
SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1 ) ;
val & = ~ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK ;
val & = ~ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK ;
val | = calib . gen1_tx_amp < < T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT ;
val | = calib . gen1_tx_peak < < T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET +
T_SATA0_CHX_PHY_CTRL1_GEN1 ) ;
val = readl ( tegra - > sata_regs +
SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2 ) ;
val & = ~ T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK ;
val & = ~ T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK ;
val | = calib . gen2_tx_amp < < T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT ;
val | = calib . gen2_tx_peak < < T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET +
T_SATA0_CHX_PHY_CTRL1_GEN2 ) ;
writel ( T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ ,
tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11 ) ;
writel ( T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 ,
tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2 ) ;
writel ( 0 , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_INDEX ) ;
return 0 ;
}
2014-07-18 11:12:30 +04:00
static int tegra_ahci_power_on ( struct ahci_host_priv * hpriv )
{
struct tegra_ahci_priv * tegra = hpriv - > plat_data ;
int ret ;
ret = regulator_bulk_enable ( ARRAY_SIZE ( tegra - > supplies ) ,
tegra - > supplies ) ;
if ( ret )
return ret ;
ret = tegra_powergate_sequence_power_up ( TEGRA_POWERGATE_SATA ,
tegra - > sata_clk ,
tegra - > sata_rst ) ;
if ( ret )
goto disable_regulators ;
reset_control_assert ( tegra - > sata_oob_rst ) ;
reset_control_assert ( tegra - > sata_cold_rst ) ;
ret = ahci_platform_enable_resources ( hpriv ) ;
if ( ret )
goto disable_power ;
reset_control_deassert ( tegra - > sata_cold_rst ) ;
reset_control_deassert ( tegra - > sata_oob_rst ) ;
return 0 ;
disable_power :
clk_disable_unprepare ( tegra - > sata_clk ) ;
tegra_powergate_power_off ( TEGRA_POWERGATE_SATA ) ;
disable_regulators :
regulator_bulk_disable ( ARRAY_SIZE ( tegra - > supplies ) , tegra - > supplies ) ;
return ret ;
}
static void tegra_ahci_power_off ( struct ahci_host_priv * hpriv )
{
struct tegra_ahci_priv * tegra = hpriv - > plat_data ;
ahci_platform_disable_resources ( hpriv ) ;
reset_control_assert ( tegra - > sata_rst ) ;
reset_control_assert ( tegra - > sata_oob_rst ) ;
reset_control_assert ( tegra - > sata_cold_rst ) ;
clk_disable_unprepare ( tegra - > sata_clk ) ;
tegra_powergate_power_off ( TEGRA_POWERGATE_SATA ) ;
regulator_bulk_disable ( ARRAY_SIZE ( tegra - > supplies ) , tegra - > supplies ) ;
}
static int tegra_ahci_controller_init ( struct ahci_host_priv * hpriv )
{
struct tegra_ahci_priv * tegra = hpriv - > plat_data ;
int ret ;
2018-03-12 14:40:33 +03:00
u32 val ;
2014-07-18 11:12:30 +04:00
ret = tegra_ahci_power_on ( hpriv ) ;
if ( ret ) {
dev_err ( & tegra - > pdev - > dev ,
" failed to power on AHCI controller: %d \n " , ret ) ;
return ret ;
}
2018-03-12 14:40:33 +03:00
/*
* Program the following SATA IPFS registers to allow SW accesses to
* SATA ' s MMIO register range .
*/
val = readl ( tegra - > sata_regs + SATA_FPCI_BAR5 ) ;
val & = ~ ( SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE ) ;
val | = SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE ;
writel ( val , tegra - > sata_regs + SATA_FPCI_BAR5 ) ;
/* Program the following SATA IPFS register to enable the SATA */
2014-07-18 11:12:30 +04:00
val = readl ( tegra - > sata_regs + SATA_CONFIGURATION_0 ) ;
2018-03-12 14:40:33 +03:00
val | = SATA_CONFIGURATION_0_EN_FPCI ;
2014-07-18 11:12:30 +04:00
writel ( val , tegra - > sata_regs + SATA_CONFIGURATION_0 ) ;
2018-03-12 14:40:33 +03:00
/* Electrical settings for better link stability */
val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1 ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0 ) ;
val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2 ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0 ) ;
val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1 ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20_0 ) ;
val = T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2 ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21_0 ) ;
/* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0 ) ;
val | = T_SATA_CFG_PHY_0_MASK_SQUELCH ;
val & = ~ T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0 ) ;
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_NVOOB ) ;
val & = ~ ( T_SATA0_NVOOB_COMMA_CNT_MASK |
T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK ) ;
val | = ( T_SATA0_NVOOB_COMMA_CNT |
T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
T_SATA0_NVOOB_SQUELCH_FILTER_MODE ) ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_NVOOB ) ;
/*
* Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8 ns
*/
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2 ) ;
val & = ~ T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK ;
val | = T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2 ) ;
if ( tegra - > soc - > ops & & tegra - > soc - > ops - > init )
tegra - > soc - > ops - > init ( hpriv ) ;
/*
* Program the following SATA configuration registers to
* initialize SATA
*/
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_1 ) ;
val | = ( T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR ) ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_1 ) ;
val = T_SATA0_CFG_9_BASE_ADDRESS ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_9 ) ;
2014-07-18 11:12:30 +04:00
2018-03-12 14:40:33 +03:00
/* Program Class Code and Programming interface for SATA */
2014-07-18 11:12:30 +04:00
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA ) ;
val | = T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA ) ;
2018-03-12 14:40:33 +03:00
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC ) ;
val & =
~ ( T_SATA0_BKDOOR_CC_CLASS_CODE_MASK |
T_SATA0_BKDOOR_CC_PROG_IF_MASK ) ;
val | = T_SATA0_BKDOOR_CC_CLASS_CODE | T_SATA0_BKDOOR_CC_PROG_IF ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC ) ;
2014-07-18 11:12:30 +04:00
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA ) ;
val & = ~ T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA ) ;
2018-03-12 14:40:33 +03:00
/* Enabling LPM capabilities through Backdoor Programming */
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR ) ;
val | = ( T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM ) ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR ) ;
/* SATA Second Level Clock Gating configuration
* Enabling Gating of Tx / Rx clocks and driving Pad IDDQ and Lane
* IDDQ Signals
*/
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_35 ) ;
val & = ~ T_SATA0_CFG_35_IDP_INDEX_MASK ;
val | = T_SATA0_CFG_35_IDP_INDEX ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_35 ) ;
val = T_SATA0_AHCI_IDP1_DATA ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1 ) ;
val = readl ( tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1 ) ;
val | = ( T_SATA0_CFG_PHY_1_PADS_IDDQ_EN |
T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN ) ;
writel ( val , tegra - > sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1 ) ;
/* Enabling IPFS Clock Gating */
val = readl ( tegra - > sata_regs + SATA_CONFIGURATION_0 ) ;
val & = ~ SATA_CONFIGURATION_0_CLK_OVERRIDE ;
writel ( val , tegra - > sata_regs + SATA_CONFIGURATION_0 ) ;
2014-07-18 11:12:30 +04:00
/* Unmask SATA interrupts */
val = readl ( tegra - > sata_regs + SATA_INTR_MASK ) ;
val | = SATA_INTR_MASK_IP_INT_MASK ;
writel ( val , tegra - > sata_regs + SATA_INTR_MASK ) ;
return 0 ;
}
static void tegra_ahci_controller_deinit ( struct ahci_host_priv * hpriv )
{
tegra_ahci_power_off ( hpriv ) ;
}
static void tegra_ahci_host_stop ( struct ata_host * host )
{
struct ahci_host_priv * hpriv = host - > private_data ;
tegra_ahci_controller_deinit ( hpriv ) ;
}
static struct ata_port_operations ahci_tegra_port_ops = {
. inherits = & ahci_ops ,
. host_stop = tegra_ahci_host_stop ,
} ;
static const struct ata_port_info ahci_tegra_port_info = {
. flags = AHCI_FLAG_COMMON ,
. pio_mask = ATA_PIO4 ,
. udma_mask = ATA_UDMA6 ,
. port_ops = & ahci_tegra_port_ops ,
} ;
2018-03-12 14:40:33 +03:00
static const struct tegra_ahci_ops tegra124_ahci_ops = {
. init = tegra124_ahci_init ,
} ;
static const struct tegra_ahci_soc tegra124_ahci_soc = {
. ops = & tegra124_ahci_ops ,
} ;
2014-07-18 11:12:30 +04:00
static const struct of_device_id tegra_ahci_of_match [ ] = {
2018-03-12 14:40:33 +03:00
{
. compatible = " nvidia,tegra124-ahci " ,
. data = & tegra124_ahci_soc
} ,
2014-07-18 11:12:30 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , tegra_ahci_of_match ) ;
2015-01-29 02:30:29 +03:00
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT ( DRV_NAME ) ,
} ;
2014-07-18 11:12:30 +04:00
static int tegra_ahci_probe ( struct platform_device * pdev )
{
struct ahci_host_priv * hpriv ;
struct tegra_ahci_priv * tegra ;
struct resource * res ;
int ret ;
hpriv = ahci_platform_get_resources ( pdev ) ;
if ( IS_ERR ( hpriv ) )
return PTR_ERR ( hpriv ) ;
tegra = devm_kzalloc ( & pdev - > dev , sizeof ( * tegra ) , GFP_KERNEL ) ;
if ( ! tegra )
return - ENOMEM ;
hpriv - > plat_data = tegra ;
tegra - > pdev = pdev ;
2018-03-12 14:40:33 +03:00
tegra - > soc = of_device_get_match_data ( & pdev - > dev ) ;
2014-07-18 11:12:30 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
tegra - > sata_regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( tegra - > sata_regs ) )
return PTR_ERR ( tegra - > sata_regs ) ;
tegra - > sata_rst = devm_reset_control_get ( & pdev - > dev , " sata " ) ;
if ( IS_ERR ( tegra - > sata_rst ) ) {
dev_err ( & pdev - > dev , " Failed to get sata reset \n " ) ;
return PTR_ERR ( tegra - > sata_rst ) ;
}
tegra - > sata_oob_rst = devm_reset_control_get ( & pdev - > dev , " sata-oob " ) ;
if ( IS_ERR ( tegra - > sata_oob_rst ) ) {
dev_err ( & pdev - > dev , " Failed to get sata-oob reset \n " ) ;
return PTR_ERR ( tegra - > sata_oob_rst ) ;
}
tegra - > sata_cold_rst = devm_reset_control_get ( & pdev - > dev , " sata-cold " ) ;
if ( IS_ERR ( tegra - > sata_cold_rst ) ) {
dev_err ( & pdev - > dev , " Failed to get sata-cold reset \n " ) ;
return PTR_ERR ( tegra - > sata_cold_rst ) ;
}
tegra - > sata_clk = devm_clk_get ( & pdev - > dev , " sata " ) ;
if ( IS_ERR ( tegra - > sata_clk ) ) {
dev_err ( & pdev - > dev , " Failed to get sata clock \n " ) ;
return PTR_ERR ( tegra - > sata_clk ) ;
}
tegra - > supplies [ 0 ] . supply = " avdd " ;
tegra - > supplies [ 1 ] . supply = " hvdd " ;
tegra - > supplies [ 2 ] . supply = " vddio " ;
tegra - > supplies [ 3 ] . supply = " target-5v " ;
tegra - > supplies [ 4 ] . supply = " target-12v " ;
ret = devm_regulator_bulk_get ( & pdev - > dev , ARRAY_SIZE ( tegra - > supplies ) ,
tegra - > supplies ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to get regulators \n " ) ;
return ret ;
}
ret = tegra_ahci_controller_init ( hpriv ) ;
if ( ret )
return ret ;
2015-01-29 02:30:29 +03:00
ret = ahci_platform_init_host ( pdev , hpriv , & ahci_tegra_port_info ,
& ahci_platform_sht ) ;
2014-07-18 11:12:30 +04:00
if ( ret )
goto deinit_controller ;
return 0 ;
deinit_controller :
tegra_ahci_controller_deinit ( hpriv ) ;
return ret ;
} ;
static struct platform_driver tegra_ahci_driver = {
. probe = tegra_ahci_probe ,
. remove = ata_platform_remove_one ,
. driver = {
2015-01-29 02:30:29 +03:00
. name = DRV_NAME ,
2014-07-18 11:12:30 +04:00
. of_match_table = tegra_ahci_of_match ,
} ,
/* LP0 suspend support not implemented */
} ;
module_platform_driver ( tegra_ahci_driver ) ;
MODULE_AUTHOR ( " Mikko Perttunen <mperttunen@nvidia.com> " ) ;
MODULE_DESCRIPTION ( " Tegra124 AHCI SATA driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;