summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorvenkatajagadish <vjagadish@nvidia.com>2013-09-30 12:22:30 +0530
committerVenkata Jagadish <vjagadish@nvidia.com>2013-10-24 00:45:35 -0700
commit926f5e838c0fd8612b81875978a5375b861b7cbf (patch)
treebac0db50772ffd903d8761a8372000f1cc59ef9b /drivers/ata
parent9289b72929c91cc435fd53fae3986d7fb8729146 (diff)
ARM: tegra: t12x: implent pad on/off for sata
With powergating and context save (idle powergating feature), Controller is unable to enter into DEVSLP mode, to overcome this issue a SW WAR provided with this DEVSLP is working. Bug 1327313 Bug 1357649 Bug 1391015 Change-Id: I2a93232a2e770bfe60ef83c535c3359bd848a3a2 Signed-off-by: venkatajagadish <vjagadish@nvidia.com> Reviewed-on: http://git-master/r/299821 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci-tegra.c607
1 files changed, 326 insertions, 281 deletions
diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c
index 6c555da8affd..361c84988004 100644
--- a/drivers/ata/ahci-tegra.c
+++ b/drivers/ata/ahci-tegra.c
@@ -75,6 +75,7 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME;
/* Bit 0 (EN_FPCI) to allow FPCI accesses to SATA */
#define SATA_CONFIGURATION_0_OFFSET 0x180
#define EN_FPCI (1 << 0)
+#define CLK_OVERRIDE (1 << 31)
#define SATA_INTR_MASK_0_OFFSET 0x188
#define IP_INT_MASK (1 << 16)
@@ -128,6 +129,11 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME;
/* AHCI HBA_CAP */
#define TEGRA_PRIVATE_AHCI_CAP_BKDR 0xa0
#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
+#define AHCI_HBA_PLL_CTRL_0 0xa8
+
+#define CLAMP_TXCLK_ON_SLUMBER (1 << 13)
+#define CLAMP_TXCLK_ON_DEVSLP (1 << 24)
+#define NO_CLAMP_SHUT_DOWN (1 << 3)
#define TEGRA_SATA_IO_SPACE_OFFSET 4
#define TEGRA_SATA_ENABLE_IO_SPACE (1 << 0)
@@ -158,6 +164,7 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME;
#define CLK_RST_CONTROLLER_PLLE_MISC_0 0x0ec
#define CLK_RST_CONTROLLER_PLLE_MISC_0_VALUE 0x00070300
#define CLK_RST_CONTROLLER_PLLE_BASE_0 0xe8
+#define PLLE_ENABLE (1 << 30)
#define CLK_RST_CONTROLLER_PLLE_AUX_0 0x48c
#define CLK_RST_CONTROLLER_PLLE_AUX_0_MASK (1 << 1)
@@ -264,7 +271,13 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME;
#define T124_PLLE_IDDQ_SWCTL_MASK (1 << 14)
#define PLLE_IDDQ_OVERRIDE_VALUE_MASK (1 << 13)
+#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+/* create a work for handling the async transfers */
+static void tegra_ahci_work_handler(struct work_struct *work);
+static DECLARE_WORK(tegra_ahci_work, tegra_ahci_work_handler);
+static struct workqueue_struct *tegra_ahci_work_q;
+#endif
enum {
AHCI_PCI_BAR = 5,
@@ -317,6 +330,11 @@ struct tegra_ahci_host_priv {
static int tegra_ahci_init_one(struct platform_device *pdev);
static int tegra_ahci_remove_one(struct platform_device *pdev);
+static void tegra_ahci_set_clk_rst_cnt_rst_dev(void);
+static void tegra_ahci_clr_clk_rst_cnt_rst_dev(void);
+static void tegra_ahci_pad_config(void);
+static void tegra_ahci_put_sata_in_iddq(void);
+static void tegra_ahci_iddqlane_config(void);
#ifdef CONFIG_PM
static bool tegra_ahci_power_un_gate(struct ata_host *host);
@@ -329,10 +347,9 @@ static int tegra_ahci_resume(struct platform_device *pdev);
static enum port_idle_status tegra_ahci_is_port_idle(struct ata_port *ap);
static bool tegra_ahci_are_all_ports_idle(struct ata_host *host);
#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
-#if 0
-static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap);
-static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host);
-#endif
+static bool tegra_ahci_pad_resume(struct ata_host *host);
+static bool tegra_ahci_pad_suspend(struct ata_host *host);
+static void tegra_ahci_abort_pad_suspend(struct ata_host *host);
static unsigned int tegra_ahci_qc_issue(struct ata_queued_cmd *qc);
static int tegra_ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
@@ -384,21 +401,31 @@ static struct platform_driver tegra_platform_ahci_driver = {
#ifdef CONFIG_PM
.suspend = tegra_ahci_suspend,
.resume = tegra_ahci_resume,
- .driver = {
- .name = DRV_NAME,
-#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
- .pm = &tegra_ahci_dev_rt_ops,
#endif
- }
-#else
.driver = {
.name = DRV_NAME,
}
-#endif
};
struct tegra_ahci_host_priv *g_tegra_hpriv;
+static inline u32 bar5_readl(u32 offset)
+{
+ u32 val;
+ val = readl(IO_ADDRESS(TEGRA_SATA_BAR5_BASE + offset));
+ AHCI_DBG_PRINT("[0x%x] => 0x%08x\n", TEGRA_SATA_BAR5_BASE+offset,
+ val);
+ return val;
+}
+
+static inline void bar5_writel(u32 val, u32 offset)
+{
+ AHCI_DBG_PRINT("[0x%x] <= 0x%08x\n", TEGRA_SATA_BAR5_BASE+offset,
+ val);
+ writel(val, IO_ADDRESS(TEGRA_SATA_BAR5_BASE + offset));
+}
+
+
static inline u32 xusb_readl(u32 offset)
{
u32 val;
@@ -554,6 +581,13 @@ static const struct sata_pad_cntrl sata_calib_pad_val[] = {
}
};
+#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+static void tegra_ahci_work_handler(struct work_struct *work)
+{
+ tegra_ahci_runtime_resume(g_tegra_hpriv->dev);
+}
+#endif
+
static void tegra_ahci_set_pad_cntrl_regs(
struct tegra_ahci_platform_data *ahci_pdata)
{
@@ -713,28 +747,28 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
clk_pllp = clk_get_sys(NULL, "pll_p");
if (IS_ERR_OR_NULL(clk_pllp)) {
pr_err("%s: unable to get PLL_P clock\n", __func__);
- err = -ENODEV;
+ err = PTR_ERR(clk_pllp);
goto exit;
}
clk_sata = clk_get_sys("tegra_sata", NULL);
if (IS_ERR_OR_NULL(clk_sata)) {
pr_err("%s: unable to get SATA clock\n", __func__);
- err = -ENODEV;
+ err = PTR_ERR(clk_sata);
goto exit;
}
clk_sata_oob = clk_get_sys("tegra_sata_oob", NULL);
if (IS_ERR_OR_NULL(clk_sata_oob)) {
pr_err("%s: unable to get SATA OOB clock\n", __func__);
- err = -ENODEV;
+ err = PTR_ERR(clk_sata_oob);
goto exit;
}
clk_sata_cold = clk_get_sys("tegra_sata_cold", NULL);
if (IS_ERR_OR_NULL(clk_sata_cold)) {
pr_err("%s: unable to get SATA COLD clock\n", __func__);
- err = -ENODEV;
+ err = PTR_ERR(clk_sata_cold);
goto exit;
}
@@ -775,24 +809,14 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
goto exit;
}
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
-
tegra_periph_reset_deassert(clk_sata);
tegra_periph_reset_deassert(clk_sata_oob);
tegra_periph_reset_deassert(clk_sata_cold);
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
- val |= SWR_SATA_OOB_RST;
- val |= SWR_SATA_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
- val |= SWR_SATACOLD_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
+ tegra_ahci_clr_clk_rst_cnt_rst_dev();
if (ahci_pdata->pexp_gpio) {
if (gpio_is_valid(ahci_pdata->pexp_gpio)) {
- gpio_free(ahci_pdata->pexp_gpio);
val = gpio_request(ahci_pdata->pexp_gpio, "ahci-tegra");
if (val) {
pr_err("failed to allocate Port expander gpio\n");
@@ -805,7 +829,6 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
val = 0x100;
pmc_writel(val, APBDEV_PMC_REMOVE_CLAMPING_CMD_0);
-#endif
/**** Init the SATA PAD PLL ****/
/* SATA_PADPLL_IDDQ_SWCTL=1 and SATA_PADPLL_IDDQ_OVERRIDE_VALUE=1 */
@@ -829,7 +852,6 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
/* Get SATA pad PLL out of IDDQ mode */
val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
val &= ~PADPLL_IDDQ_OVERRIDE_VALUE_MASK;
- val |= PADPLL_IDDQ_OVERRIDE_VALUE_OFF;
pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
udelay(3);
@@ -850,7 +872,6 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
/* de-assert IDDQ mode signal going to PHY */
val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
val &= ~PADPHY_IDDQ_OVERRIDE_VALUE_MASK;
- val |= PADPHY_IDDQ_OVERRIDE_VALUE_OFF;
pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
#if defined(CONFIG_TEGRA_SILICON_PLATFORM)
err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_SATA);
@@ -867,7 +888,6 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
*/
val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
val &= ~PADPLL_RESET_OVERRIDE_VALUE_MASK;
- val |= PADPLL_RESET_OVERRIDE_VALUE_OFF;
clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
/*
@@ -877,11 +897,7 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
timeout = 15;
while (timeout--) {
udelay(1);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
-#else
- val = misc_readl(SATA_AUX_PAD_PLL_CNTL_1_REG);
-#endif
if (val & LOCKDET_FIELD)
break;
}
@@ -889,29 +905,13 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
pr_err("%s: AUX_PAD_PLL_CNTL_1 (0x%x) is not locked in 15us.\n",
__func__, val);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
- /* clear SW control of SATA PADPLL, SATA PHY and PLLE */
-
- /* for SATA PHY IDDQ */
- val = xusb_readl(XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
- val &= ~(IDDQ_OVRD_MASK | IDDQ_MASK);
- xusb_writel(val, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
-
- /* for SATA PADPLL IDDQ */
- val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
- val &= ~(PLL_PWR_OVRD_MASK | PLL_IDDQ_MASK | PLL_RST_MASK);
- xusb_writel(val, XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
-
- /* PLLE related stuff*/
-
- val = clk_readl(CLK_RST_CONTROLLER_PLLE_MISC_0);
- val &= ~(T124_PLLE_IDDQ_SWCTL_MASK | PLLE_IDDQ_OVERRIDE_VALUE_MASK);
- clk_writel(val, CLK_RST_CONTROLLER_PLLE_MISC_0);
+ tegra_ahci_pad_config();
clk_cml1 = clk_get_sys(NULL, "cml1");
if (IS_ERR_OR_NULL(clk_cml1)) {
- pr_err("%s: unable to get cml1 clock\n", __func__);
- err = -ENODEV;
+ pr_err("%s: unable to get cml1 clock Errone is %d\n",
+ __func__, (int) PTR_ERR(clk_cml1));
+ err = PTR_ERR(clk_cml1);
goto exit;
}
if (clk_prepare_enable(clk_cml1)) {
@@ -919,22 +919,11 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
err = -ENODEV;
goto exit;
}
-#else
- /* clear SW control of SATA PADPLL, SATA PHY and PLLE */
- val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
- val &= ~(PADPLL_IDDQ_SWCTL_MASK | PADPHY_IDDQ_SWCTL_MASK |
- PLLE_IDDQ_SWCTL_MASK);
- val |= (PADPLL_IDDQ_SWCTL_OFF | PADPHY_IDDQ_SWCTL_OFF |
- PLLE_IDDQ_SWCTL_OFF);
- pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
-#endif
val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
val &= ~PADPLL_RESET_SWCTL_MASK;
- val |= PADPLL_RESET_SWCTL_OFF;
clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
/* PLLE Programing for SATA */
val = clk_readl(CLK_RST_CONTROLLER_PLLE_AUX_0);
@@ -954,7 +943,6 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
val = val | XUSB_PADCTL_PLL1_MODE;
xusb_writel(val, XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
-#endif
/* clear NVA2SATA_OOB_ON_POR in SATA_AUX_MISC_CNTL_1_REG */
val = misc_readl(SATA_AUX_MISC_CNTL_1_REG);
@@ -965,6 +953,10 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
val |= EN_FPCI;
sata_writel(val, SATA_CONFIGURATION_0_OFFSET);
+ val = sata_readl(SATA_CONFIGURATION_0_OFFSET);
+ val |= CLK_OVERRIDE;
+ sata_writel(val, SATA_CONFIGURATION_0_OFFSET);
+
/* program sata pad control based on the fuse */
tegra_ahci_set_pad_cntrl_regs(ahci_pdata);
@@ -1012,18 +1004,19 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv,
/* flush */
scfg_readl(AHCI_BAR5_CONFIG_LOCATION);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
sata_writel((FPCI_BAR5_0_FINAL_VALUE >> 8),
SATA_FPCI_BAR5_0_OFFSET);
-#else
- sata_writel((TEGRA_SATA_BAR5_FINAL_PROGRAM >> 8),
- SATA_FPCI_BAR5_0_OFFSET);
-#endif
val = scfg_readl(T_SATA0_AHCI_HBA_CAP_BKDR);
val |= (HOST_CAP_ALPM | HOST_CAP_SSC | HOST_CAP_PART);
scfg_writel(val, T_SATA0_AHCI_HBA_CAP_BKDR);
+ /* Second Level Clock Gating*/
+ val = bar5_readl(AHCI_HBA_PLL_CTRL_0);
+ val |= (CLAMP_TXCLK_ON_SLUMBER | CLAMP_TXCLK_ON_DEVSLP);
+ val &= ~NO_CLAMP_SHUT_DOWN;
+ bar5_writel(val, AHCI_HBA_PLL_CTRL_0);
+
/* enable Interrupt channel */
val = pictlr_readl(PRI_ICTLR_CPU_IER_SET_0_OFFSET);
val |= CPU_IER_SATA_CTL;
@@ -1093,9 +1086,11 @@ static int tegra_ahci_controller_suspend(struct platform_device *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct tegra_ahci_host_priv *tegra_hpriv;
+ struct tegra_ahci_platform_data *ahci_pdata;
unsigned long flags;
tegra_hpriv = (struct tegra_ahci_host_priv *)host->private_data;
+ ahci_pdata = tegra_hpriv->dev->platform_data;
/* stop the idle timer */
if (timer_pending(&tegra_hpriv->idle_timer))
@@ -1118,6 +1113,9 @@ static int tegra_ahci_controller_suspend(struct platform_device *pdev)
return -EBUSY;
}
}
+
+ if (ahci_pdata->pexp_gpio)
+ gpio_free(ahci_pdata->pexp_gpio);
spin_unlock_irqrestore(&host->lock, flags);
return tegra_ahci_power_off_rails(tegra_hpriv->power_rails);
@@ -1188,13 +1186,11 @@ static int tegra_ahci_resume(struct platform_device *pdev)
if (rc)
return rc;
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
rc = tegra_ahci_controller_init(g_tegra_hpriv, 1);
if (rc != 0) {
dev_err(host->dev, "TEGRA SATA init failed in resume\n");
return rc;
}
-#endif
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
@@ -1205,6 +1201,7 @@ static int tegra_ahci_resume(struct platform_device *pdev)
}
ata_host_resume(host);
+
return 0;
}
@@ -1229,7 +1226,6 @@ static int tegra_ahci_runtime_suspend(struct device *dev)
case SATA_ABORT_OFF:
dev_dbg(dev, "** rt-suspend: abort suspend **\n");
- pm_runtime_get_noresume(dev);
tegra_hpriv->pg_state = SATA_ON;
tegra_ahci_dequeue_qcs(tegra_hpriv);
err = -EBUSY;
@@ -1241,13 +1237,21 @@ static int tegra_ahci_runtime_suspend(struct device *dev)
/* if all ports are in idle, do power-gate */
dev_dbg(dev, "** rt-suspend: power-down sata (%u) **\n",
tegra_hpriv->pg_state);
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
pg_ok = tegra_ahci_power_gate(host);
+#else
+ pg_ok = tegra_ahci_pad_suspend(host);
+#endif
dev_dbg(dev, "** rt-suspend: done **\n");
if (pg_ok) {
tegra_hpriv->pg_state = SATA_OFF;
} else {
dev_err(dev, "** rt-suspend: abort pg **\n");
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
tegra_ahci_abort_power_gate(host);
+#else
+ tegra_ahci_abort_pad_suspend(host);
+#endif
tegra_hpriv->pg_state = SATA_ON;
err = -EBUSY;
}
@@ -1277,14 +1281,11 @@ static int tegra_ahci_runtime_resume(struct device *dev)
{
struct ata_host *host;
struct tegra_ahci_host_priv *tegra_hpriv;
- unsigned long flags;
int err = 0;
host = dev_get_drvdata(dev);
tegra_hpriv = (struct tegra_ahci_host_priv *)host->private_data;
- spin_lock_irqsave(&host->lock, flags);
-
if (tegra_hpriv->pg_state == SATA_ON) {
dev_dbg(dev, "** rt-resume: already power ungated **\n");
goto exit;
@@ -1294,12 +1295,17 @@ static int tegra_ahci_runtime_resume(struct device *dev)
(tegra_hpriv->pg_state == SATA_GOING_ON)) {
dev_dbg(dev, "** rt-resume: power-up sata (%u) **\n",
tegra_hpriv->pg_state);
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
tegra_ahci_power_un_gate(host);
+#else
+ tegra_ahci_pad_resume(host);
+#endif
dev_dbg(dev, "** rt-resume: done **\n");
tegra_hpriv->pg_state = SATA_ON;
/* now qc_issue all qcs in the qc_list */
tegra_ahci_dequeue_qcs(tegra_hpriv);
+
} else {
dev_err(dev, "** rt-resume: bad state (%u) **\n",
tegra_hpriv->pg_state);
@@ -1309,12 +1315,13 @@ static int tegra_ahci_runtime_resume(struct device *dev)
exit:
- spin_unlock_irqrestore(&host->lock, flags);
+
return err;
}
#endif
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
static u16 pg_save_bar5_registers[] = {
0x018, /* T_AHCI_HBA_CCC_PORTS */
0x004, /* T_AHCI_HBA_GHC */
@@ -1648,13 +1655,131 @@ static bool tegra_ahci_check_errors(struct ata_host *host)
return false;
}
-static void tegra_ahci_abort_power_gate(struct ata_host *host)
+void tegra_ahci_iddqlane_config(void)
{
u32 val;
+ u32 dat;
+
+ /* wait for SATA_PADPLL_IDDQ2LANE_SLUMBER_DLY = 3 microseconds. */
+ val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
+ val &= ~IDDQ2LANE_SLUMBER_DLY_MASK;
+ val |= IDDQ2LANE_SLUMBER_DLY_3MS;
+ clk_writel(val, CLK_RST_SATA_PLL_CFG1_REG);
+ /* get sata phy and pll out of iddq: */
+ val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
+ val &= ~(PADPLL_IDDQ_OVERRIDE_VALUE_MASK | PADPLL_IDDQ_SWCTL_MASK);
+ pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
+
+ /* wait for delay of IDDQ2LAND_SLUMBER_DLY */
+ val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
+ dat = (val & IDDQ2LANE_SLUMBER_DLY_MASK) >> IDDQ2LANE_SLUMBER_DLY_SHIFT;
+ udelay(dat);
+ val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
+ val &= ~(PADPHY_IDDQ_OVERRIDE_VALUE_MASK | PADPHY_IDDQ_SWCTL_MASK);
+ pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
+
+}
+void tegra_ahci_put_sata_in_iddq()
+{
+ u32 val;
+ u32 dat;
+
+ /*
+ * Hw wake up is not needed:
+ * Driver/RM shall place the SATA PHY and SATA PADPLL in IDDQ.
+ * SATA_PADPLL_RESET_SWCTL =1
+ * SATA_PADPLL_RESET_OVERRIDE_VALUE=1
+ * SATA_PADPHY_IDDQ_SWCTL=1
+ * SATA_PADPHY_IDDQ_OVERRIDE_VALUE=1
+ */
+
+ val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
+ val &= ~(PADPLL_RESET_SWCTL_MASK | PADPLL_RESET_OVERRIDE_VALUE_MASK);
+ val |= (PADPLL_RESET_SWCTL_ON | PADPLL_RESET_OVERRIDE_VALUE_ON);
+ clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
+
+ val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
+ val &= ~(PADPHY_IDDQ_OVERRIDE_VALUE_MASK | PADPHY_IDDQ_SWCTL_MASK);
+ val |= (PADPHY_IDDQ_SWCTL_ON | PADPHY_IDDQ_OVERRIDE_VALUE_ON);
+ pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
+
+ /* Wait for time specified in SATA_LANE_IDDQ2_PADPLL_IDDQ */
+ val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
+ dat = (val & IDDQ2LANE_IDDQ_DLY_MASK) >> IDDQ2LANE_IDDQ_DLY_SHIFT;
+ udelay(dat);
+
+ /* SATA_PADPLL_IDDQ_SWCTL=1 & SATA_PADPLL_IDDQ_OVERRIDE_VALUE=1 */
+ val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
+ val &= ~(PADPLL_IDDQ_OVERRIDE_VALUE_MASK | PADPLL_IDDQ_SWCTL_MASK);
+ val |= (PADPLL_IDDQ_SWCTL_ON | PADPLL_IDDQ_OVERRIDE_VALUE_ON);
+ pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
+
+}
+void tegra_ahci_clr_clk_rst_cnt_rst_dev(void)
+{
+ u32 val;
+
+ val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
+ val |= (SWR_SATA_OOB_RST | SWR_SATA_RST);
+ clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
+
+ val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
+ val |= SWR_SATACOLD_RST;
+ clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
+
+}
+void tegra_ahci_set_clk_rst_cnt_rst_dev(void)
+{
+
+ u32 val;
+
+ val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
+ val &= ~(SWR_SATA_OOB_RST | SWR_SATA_RST);
+ clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
+
+ val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
+ val &= ~SWR_SATACOLD_RST;
+ clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
+
+}
+
+static void tegra_ahci_pad_config(void)
+{
+ u32 val;
+
+ /* clear SW control of SATA PADPLL, SATA PHY and PLLE */
+
+ /* for SATA PHY IDDQ */
+ val = xusb_readl(XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
+ val &= ~(IDDQ_OVRD_MASK | IDDQ_MASK);
+ xusb_writel(val, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
+
+ /* for SATA PADPLL IDDQ */
+ val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
+ val &= ~(PLL_PWR_OVRD_MASK | PLL_IDDQ_MASK | PLL_RST_MASK);
+ xusb_writel(val, XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
+
+ /* PLLE related stuff*/
+
+ val = clk_readl(CLK_RST_CONTROLLER_PLLE_MISC_0);
+ val &= ~(T124_PLLE_IDDQ_SWCTL_MASK | PLLE_IDDQ_OVERRIDE_VALUE_MASK);
+ clk_writel(val, CLK_RST_CONTROLLER_PLLE_MISC_0);
+
+ clk_writel(CLK_RST_CONTROLLER_PLLE_MISC_0_VALUE,
+ CLK_RST_CONTROLLER_PLLE_MISC_0);
+
+ val = clk_readl(CLK_RST_CONTROLLER_PLLE_BASE_0);
+ val |= PLLE_ENABLE;
+ clk_writel(val, CLK_RST_CONTROLLER_PLLE_BASE_0);
+
+}
+
+static void tegra_ahci_abort_power_gate(struct ata_host *host)
+{
+ u32 val;
val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
val &= ~PG_INFO_MASK;
- val |= PG_INFO_OFF;
pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
}
@@ -1672,16 +1797,13 @@ static bool tegra_ahci_power_gate(struct ata_host *host)
val |= PG_INFO_ON;
pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
tegra_ahci_pg_save_registers(host);
#endif
-
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val = xusb_readl(XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
val |= XUSB_PADCTL_IOPHY_MISC_IDDQ |
XUSB_PADCTL_IOPHY_MISC_IDDQ_OVRD;
xusb_writel(val, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
-#endif
/*
* Read SATA_AUX_MISC_CNTL_1_0 register L0_RX_IDLE_T_SAX field and
@@ -1695,27 +1817,11 @@ static bool tegra_ahci_power_gate(struct ata_host *host)
dat <<= L0_RX_IDLE_T_NPG_SHIFT;
val &= ~L0_RX_IDLE_T_NPG_MASK;
val |= dat;
- val &= ~L0_RX_IDLE_T_MUX_MASK;
val |= L0_RX_IDLE_T_MUX_FROM_APB_MISC;
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val |= DEVSLP_OVERRIDE;
-#endif
misc_writel(val, SATA_AUX_MISC_CNTL_1_REG);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEVICES_V_0);
- val &= ~(SWR_SATA_OOB_RST | SWR_SATA_RST);
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEVICES_V_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
- val &= ~(SWR_SATA_OOB_RST | SWR_SATA_RST);
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
- val &= ~SWR_SATACOLD_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
-#endif
-
+ tegra_ahci_set_clk_rst_cnt_rst_dev();
/* abort PG if there are errors occurred */
if (tegra_ahci_check_errors(host)) {
@@ -1727,36 +1833,8 @@ static bool tegra_ahci_power_gate(struct ata_host *host)
dev_err(host->dev, "** pg: cmds; abort power gating **\n");
return false;
}
+ tegra_ahci_put_sata_in_iddq();
- /*
- * Hw wake up is not needed:
- * Driver/RM shall place the SATA PHY and SATA PADPLL in IDDQ.
- * SATA_PADPLL_RESET_SWCTL =1
- * SATA_PADPLL_RESET_OVERRIDE_VALUE=1
- * SATA_PADPHY_IDDQ_SWCTL=1
- * SATA_PADPHY_IDDQ_OVERRIDE_VALUE=1
- */
- val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
- val &= ~(PADPLL_RESET_SWCTL_MASK | PADPLL_RESET_OVERRIDE_VALUE_MASK);
- val |= (PADPLL_RESET_SWCTL_ON | PADPLL_RESET_OVERRIDE_VALUE_ON);
- clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
- val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
- val &= ~(PADPHY_IDDQ_OVERRIDE_VALUE_MASK | PADPHY_IDDQ_SWCTL_MASK);
- val |= (PADPHY_IDDQ_SWCTL_ON | PADPHY_IDDQ_OVERRIDE_VALUE_ON);
- pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
-
- /* Wait for time specified in SATA_LANE_IDDQ2_PADPLL_IDDQ */
- val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
- dat = (val & IDDQ2LANE_IDDQ_DLY_MASK) >> IDDQ2LANE_IDDQ_DLY_SHIFT;
- udelay(dat);
-
- /* SATA_PADPLL_IDDQ_SWCTL=1 & SATA_PADPLL_IDDQ_OVERRIDE_VALUE=1 */
- val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
- val &= ~(PADPLL_IDDQ_OVERRIDE_VALUE_MASK | PADPLL_IDDQ_SWCTL_MASK);
- val |= (PADPLL_IDDQ_SWCTL_ON | PADPLL_IDDQ_OVERRIDE_VALUE_ON);
- pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
-
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val = pmc_readl(APBDEV_PMC_PWRGATE_TOGGLE_0);
val |= PARTID_VALUE;
val |= START;
@@ -1765,13 +1843,14 @@ static bool tegra_ahci_power_gate(struct ata_host *host)
val = pmc_readl(APBDEV_PMC_PWRGATE_STATUS_0);
val &= ~SAX_MASK;
pmc_writel(val, APBDEV_PMC_PWRGATE_STATUS_0);
-#endif
/* power off the sata */
status = tegra_powergate_partition_with_clk_off(TEGRA_POWERGATE_SATA);
- if (status)
+ if (status) {
dev_err(host->dev, "** failed to turn-off SATA (0x%x) **\n",
status);
+ return false;
+ }
return true;
}
@@ -1779,35 +1858,14 @@ static bool tegra_ahci_power_gate(struct ata_host *host)
static bool tegra_ahci_power_un_gate(struct ata_host *host)
{
u32 val;
- u32 dat;
u32 timeout;
struct tegra_ahci_host_priv *tegra_hpriv;
int status;
- struct clk *clk_cml1 = NULL;
tegra_hpriv = (struct tegra_ahci_host_priv *)host->private_data;
- /* wait for SATA_PADPLL_IDDQ2LANE_SLUMBER_DLY = 3 microseconds. */
- val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
- val &= ~IDDQ2LANE_SLUMBER_DLY_MASK;
- val |= IDDQ2LANE_SLUMBER_DLY_3MS;
- clk_writel(val, CLK_RST_SATA_PLL_CFG1_REG);
-
- /* get sata phy and pll out of iddq: */
- val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
- val &= ~(PADPLL_IDDQ_OVERRIDE_VALUE_MASK | PADPLL_IDDQ_SWCTL_MASK);
- val |= (PADPLL_IDDQ_SWCTL_OFF | PADPLL_IDDQ_OVERRIDE_VALUE_OFF);
- pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
- /* wait for delay of IDDQ2LAND_SLUMBER_DLY */
- val = clk_readl(CLK_RST_SATA_PLL_CFG1_REG);
- dat = (val & IDDQ2LANE_SLUMBER_DLY_MASK) >> IDDQ2LANE_SLUMBER_DLY_SHIFT;
- udelay(dat);
- val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
- val &= ~(PADPHY_IDDQ_OVERRIDE_VALUE_MASK | PADPHY_IDDQ_SWCTL_MASK);
- val |= (PADPHY_IDDQ_SWCTL_OFF | PADPHY_IDDQ_OVERRIDE_VALUE_OFF);
- pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
+ tegra_ahci_iddqlane_config();
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val = pmc_readl(APBDEV_PMC_PWRGATE_TOGGLE_0);
val |= PARTID_VALUE;
val |= START;
@@ -1816,76 +1874,27 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host)
val = pmc_readl(APBDEV_PMC_PWRGATE_STATUS_0);
val |= SAX_MASK;
pmc_writel(val, APBDEV_PMC_PWRGATE_STATUS_0);
-#endif
status = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_SATA);
- if (status)
+ if (status) {
dev_err(host->dev, "** failed to turn-on SATA (0x%x) **\n",
status);
+ return false;
+ }
/* deasset PADPLL and wait until it locks. */
val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
val &= ~PADPLL_RESET_OVERRIDE_VALUE_MASK;
- val |= PADPLL_RESET_OVERRIDE_VALUE_OFF;
clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEVICES_V_0);
- val |= SWR_SATA_OOB_RST;
- val |= SWR_SATA_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEVICES_V_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
- val |= SWR_SATA_OOB_RST;
- val |= SWR_SATA_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_V_CLR_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
- val |= SWR_SATACOLD_RST;
- clk_writel(val, CLK_RST_CONTROLLER_RST_DEV_W_CLR_0);
-#endif
+ tegra_ahci_clr_clk_rst_cnt_rst_dev();
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
/* restore registers */
tegra_ahci_pg_restore_registers(host);
#endif
+ tegra_ahci_pad_config();
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
- /* clear SW control of SATA PADPLL, SATA PHY and PLLE */
-
- /* for SATA PHY IDDQ */
- val = xusb_readl(XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
- val &= ~(IDDQ_OVRD_MASK | IDDQ_MASK);
- xusb_writel(val, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
-
- /* for SATA PADPLL IDDQ */
- val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
- val &= ~(PLL_PWR_OVRD_MASK | PLL_IDDQ_MASK | PLL_RST_MASK);
- xusb_writel(val, XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
-
- /* PLLE related stuff*/
-
- val = clk_readl(CLK_RST_CONTROLLER_PLLE_MISC_0);
- val &= ~(T124_PLLE_IDDQ_SWCTL_MASK | PLLE_IDDQ_OVERRIDE_VALUE_MASK);
- clk_writel(val, CLK_RST_CONTROLLER_PLLE_MISC_0);
-
- clk_writel(CLK_RST_CONTROLLER_PLLE_MISC_0_VALUE,
- CLK_RST_CONTROLLER_PLLE_MISC_0);
-
- val = clk_readl(CLK_RST_CONTROLLER_PLLE_BASE_0);
- val |= 1 << 30 ;
- clk_writel(val, CLK_RST_CONTROLLER_PLLE_BASE_0);
-
- clk_cml1 = clk_get_sys(NULL, "cml1");
- if (IS_ERR_OR_NULL(clk_cml1)) {
- pr_err("%s: unable to get cml1 clock\n", __func__);
- return false;
- }
- if (clk_prepare_enable(clk_cml1)) {
- pr_err("%s: unable to enable cml1 clock\n", __func__);
- return false;
- }
-#endif
/*
* Wait for SATA_AUX_PAD_PLL_CNTL_1_0_LOCKDET to turn 1 with a timeout
* of 15 us.
@@ -1893,11 +1902,7 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host)
timeout = 15;
while (timeout--) {
udelay(1);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
-#else
- val = misc_readl(SATA_AUX_PAD_PLL_CNTL_1_REG);
-#endif
if (val & LOCKDET_FIELD)
break;
}
@@ -1922,9 +1927,7 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host)
* Sata controller after SAX is power-ungated.
*/
val = misc_readl(SATA_AUX_MISC_CNTL_1_REG);
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
val &= ~DEVSLP_OVERRIDE;
-#endif
val &= ~L0_RX_IDLE_T_MUX_MASK;
val |= L0_RX_IDLE_T_MUX_FROM_SATA;
misc_writel(val, SATA_AUX_MISC_CNTL_1_REG);
@@ -1940,7 +1943,6 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host)
/* Set the bits in the CAR to allow HW based low power sequencing. */
val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
val &= ~PADPLL_RESET_SWCTL_MASK;
- val |= PADPLL_RESET_SWCTL_OFF;
clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
/*
@@ -1949,7 +1951,6 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host)
*/
val = pmc_readl(APB_PMC_SATA_PWRGT_0_REG);
val &= ~PG_INFO_MASK;
- val |= PG_INFO_OFF;
pmc_writel(val, APB_PMC_SATA_PWRGT_0_REG);
return true;
@@ -1978,37 +1979,86 @@ static bool tegra_ahci_are_all_ports_idle(struct ata_host *host)
return true;
}
+
#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+static void tegra_ahci_abort_pad_suspend(struct ata_host *host)
+{
+ /*No implementation*/
+}
-#if 0
-static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap)
+static bool tegra_ahci_pad_suspend(struct ata_host *host)
{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 sstat;
+ u32 val;
+ struct tegra_ahci_host_priv *tegra_hpriv;
- if (tegra_ahci_is_port_idle(ap) == PORT_IS_NOT_IDLE)
- return PORT_IS_NOT_IDLE;
+ tegra_hpriv = (struct tegra_ahci_host_priv *)host->private_data;
+
+ val = xusb_readl(XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
+ val |= XUSB_PADCTL_IOPHY_MISC_IDDQ |
+ XUSB_PADCTL_IOPHY_MISC_IDDQ_OVRD;
+ xusb_writel(val, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0);
+
+ /* abort PG if there are errors occurred */
+ if (tegra_ahci_check_errors(host)) {
+ dev_err(host->dev, "** pg: errors; abort power gating **\n");
+ return false;
+ }
+ /* make sure all ports have no outstanding commands and are idle. */
+ if (!tegra_ahci_are_all_ports_idle(host)) {
+ dev_err(host->dev, "** pg: cmds; abort power gating **\n");
+ return false;
+ }
+ tegra_ahci_put_sata_in_iddq();
- /* return 1 if PORT_SCR_STAT is in IPM_SLUMBER_STATE */
- sstat = readl(port_mmio + PORT_SCR_STAT);
- if ((sstat & SSTAT_IPM_STATE_MASK) == SSTAT_IPM_SLUMBER_STATE)
- return PORT_IS_SLUMBER;
- return PORT_IS_IDLE_NOT_SLUMBER;
+ return true;
}
-/* check if all supported ports are in slumber */
-static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host)
-{ int i;
- struct ata_port *ap;
+static bool tegra_ahci_pad_resume(struct ata_host *host)
+{
+ u32 val;
+ u32 timeout;
+ struct tegra_ahci_host_priv *tegra_hpriv;
- for (i = 0; i < host->n_ports; i++) {
- ap = host->ports[i];
- if (ap && (tegra_ahci_is_port_slumber(ap) != PORT_IS_SLUMBER))
- return false;
+ tegra_hpriv = (struct tegra_ahci_host_priv *)host->private_data;
+
+ tegra_ahci_iddqlane_config();
+
+ /* deasset PADPLL and wait until it locks. */
+ val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
+ val &= ~PADPLL_RESET_OVERRIDE_VALUE_MASK;
+ clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
+
+ tegra_ahci_pad_config();
+
+ /*
+ * Wait for SATA_AUX_PAD_PLL_CNTL_1_0_LOCKDET to turn 1 with a timeout
+ * of 15 us.
+ */
+ timeout = 15;
+ while (timeout--) {
+ udelay(1);
+ val = xusb_readl(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_0);
+ if (val & LOCKDET_FIELD)
+ break;
}
+ if (timeout == 0)
+ pr_err("%s: SATA_PAD_PLL is not locked in 15us.\n", __func__);
+
+ /*
+ * Driver can start to use main SATA interrupt instead of the
+ * rx_stat_t interrupt.
+ */
+ val = pictlr_readl(PRI_ICTLR_CPU_IER_SET_0_OFFSET);
+ val |= CPU_IER_SATA_CTL;
+ pictlr_writel(val, PRI_ICTLR_CPU_IER_SET_0_OFFSET);
+
+ /* Set the bits in the CAR to allow HW based low power sequencing. */
+ val = clk_readl(CLK_RST_SATA_PLL_CFG0_REG);
+ val &= ~PADPLL_RESET_SWCTL_MASK;
+ clk_writel(val, CLK_RST_SATA_PLL_CFG0_REG);
+
return true;
}
-#endif
static void tegra_ahci_to_add_idle_timer(struct ata_host *host)
{
@@ -2050,7 +2100,7 @@ static void tegra_ahci_idle_timer(unsigned long arg)
return;
}
spin_unlock_irqrestore(&host->lock, flags);
- pm_runtime_put(tegra_hpriv->dev);
+ tegra_ahci_runtime_suspend(tegra_hpriv->dev);
}
static int tegra_ahci_queue_one_qc(struct tegra_ahci_host_priv *tegra_hpriv,
@@ -2091,7 +2141,6 @@ static unsigned int tegra_ahci_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ata_host *host = ap->host;
struct tegra_ahci_host_priv *tegra_hpriv = host->private_data;
- int rc;
/* stop the idle timer */
if (timer_pending(&tegra_hpriv->idle_timer))
@@ -2110,16 +2159,8 @@ static unsigned int tegra_ahci_qc_issue(struct ata_queued_cmd *qc)
return tegra_ahci_queue_one_qc(tegra_hpriv, qc);
case SATA_OFF:
dev_dbg(host->dev, "** qc_issue: request power-up sata **\n");
- rc = pm_runtime_get(tegra_hpriv->dev);
- /* rc == 0 means the request has been queued successfully */
- if (rc) {
- dev_err(host->dev, "** qc_issue: rt_get()=%d **\n",
- rc);
- WARN_ON(1);
- return AC_ERR_SYSTEM;
- }
+ queue_work(tegra_ahci_work_q, &tegra_ahci_work);
tegra_hpriv->pg_state = SATA_GOING_ON;
-
/* continue with the following code to queue the qc */
case SATA_GOING_ON:
return tegra_ahci_queue_one_qc(tegra_hpriv, qc);
@@ -2137,11 +2178,14 @@ static int tegra_ahci_hardreset(struct ata_link *link, unsigned int *class,
struct ata_port *ap = link->ap;
struct ata_host *host = ap->host;
struct tegra_ahci_host_priv *tegra_hpriv = host->private_data;
+ unsigned long flags;
int rc;
if (tegra_hpriv->pg_state == SATA_OFF) {
dev_dbg(host->dev, "** hreset: request power-up sata **\n");
- rc = pm_runtime_get_sync(tegra_hpriv->dev);
+ spin_lock_irqsave(&host->lock, flags);
+ rc = tegra_ahci_runtime_resume(tegra_hpriv->dev);
+ spin_unlock_irqrestore(&host->lock, flags);
/* rc == 0 means the request has been run successfully */
if (rc) {
dev_err(host->dev, "** hreset: rt_get()=%d **\n", rc);
@@ -2185,13 +2229,15 @@ static int tegra_ahci_remove_one(struct platform_device *pdev)
devm_iounmap(&pdev->dev, host->iomap[AHCI_PCI_BAR]);
devres_free(host);
-#ifdef CONFIG_PM
+#ifdef TEGRA_AHCI_CONTEXT_RESTORE
/* Free PG save/restore area */
devm_kfree(&pdev->dev, ((struct tegra_ahci_host_priv *)hpriv)->pg_save);
-#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
- pm_runtime_disable(&pdev->dev);
#endif
+#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+ cancel_work_sync(&tegra_ahci_work);
+ if (tegra_ahci_work_q)
+ destroy_workqueue(tegra_ahci_work_q);
#endif
devm_kfree(&pdev->dev, hpriv);
@@ -2207,15 +2253,12 @@ static int tegra_ahci_init_one(struct platform_device *pdev)
struct ahci_host_priv *hpriv = NULL;
struct tegra_ahci_host_priv *tegra_hpriv;
struct ata_host *host = NULL;
- int n_ports, i, rc;
+ int n_ports, i, rc = 0;
struct resource *res, *irq_res;
void __iomem *mmio;
-#ifdef CONFIG_PM
-
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#if defined(TEGRA_AHCI_CONTEXT_RESTORE)
u32 save_size;
#endif
-#endif
irq_handler_t irq_handler = ahci_interrupt;
VPRINTK("ENTER\n");
@@ -2250,6 +2293,16 @@ static int tegra_ahci_init_one(struct platform_device *pdev)
rc = -ENOMEM;
goto fail;
}
+
+#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+ tegra_ahci_work_q = alloc_workqueue("tegra_ahci_work_q",
+ WQ_HIGHPRI | WQ_UNBOUND, 16);
+ if (!tegra_ahci_work_q) {
+ dev_err(dev, "TEGRA WORKQUEUE SATA init failed\n");
+ goto fail;
+ }
+#endif
+
hpriv->flags |= (unsigned long)pi.private_data;
tegra_hpriv = (struct tegra_ahci_host_priv *)hpriv;
tegra_hpriv->dev = dev;
@@ -2324,8 +2377,7 @@ static int tegra_ahci_init_one(struct platform_device *pdev)
ahci_print_info(host, "TEGRA-SATA");
dev_dbg(dev, "controller init okay\n");
-#ifdef CONFIG_PM
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#if defined(TEGRA_AHCI_CONTEXT_RESTORE)
/* Setup PG save/restore area: */
/* calculate the size */
@@ -2351,11 +2403,8 @@ static int tegra_ahci_init_one(struct platform_device *pdev)
goto fail;
}
#endif
+#ifdef CONFIG_PM
#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
- pm_runtime_set_active(dev);
- pm_suspend_ignore_children(dev, true);
- pm_runtime_enable(dev);
-
tegra_hpriv->pg_state = SATA_ON;
/* setup sata idle timer */
@@ -2374,15 +2423,6 @@ static int tegra_ahci_init_one(struct platform_device *pdev)
rc = ata_host_activate(host, irq_res->start, irq_handler, 0, &ahci_sht);
if (rc == 0)
return 0;
-
- /* Free PG save/restore area */
- devm_kfree(dev, tegra_hpriv->pg_save);
-
-#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
- pm_runtime_put(dev);
- pm_runtime_enable(dev);
-#endif
-
fail:
if (host) {
if (host->iomap[AHCI_PCI_BAR])
@@ -2392,6 +2432,11 @@ fail:
if (hpriv)
devm_kfree(dev, hpriv);
+#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE
+ if (tegra_ahci_work_q)
+ destroy_workqueue(tegra_ahci_work_q);
+#endif
+
return rc;
}
@@ -2423,7 +2468,7 @@ static void dbg_ahci_dump_regs(struct seq_file *s, u32 *ptr, u32 base, u32 regs)
seq_printf(s, "0x%08x ", readl(ptr));
++ptr;
}
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
#undef REGS_PER_LINE
}
@@ -2436,21 +2481,21 @@ static int dbg_ahci_dump_show(struct seq_file *s, void *unused)
base = TEGRA_SATA_CONFIG_BASE;
ptr = (u32 *)IO_TO_VIRT(base);
- seq_printf(s, "SATA CONFIG Registers:\n");
- seq_printf(s, "----------------------\n");
+ seq_puts(s, "SATA CONFIG Registers:\n");
+ seq_puts(s, "----------------------\n");
dbg_ahci_dump_regs(s, ptr, base, 0x200);
base = TEGRA_SATA_BAR5_BASE;
ptr = (u32 *)IO_TO_VIRT(base);
- seq_printf(s, "\nAHCI HBA Registers:\n");
- seq_printf(s, "-------------------\n");
+ seq_puts(s, "\nAHCI HBA Registers:\n");
+ seq_puts(s, "-------------------\n");
dbg_ahci_dump_regs(s, ptr, base, 64);
for (i = 0; i < TEGRA_AHCI_NUM_PORTS; ++i) {
base = TEGRA_SATA_BAR5_BASE + 0x100 + (0x80*i);
ptr = (u32 *)IO_TO_VIRT(base);
seq_printf(s, "\nPort %u Registers:\n", i);
- seq_printf(s, "---------------\n");
+ seq_puts(s, "---------------\n");
dbg_ahci_dump_regs(s, ptr, base, 20);
}
@@ -2463,9 +2508,9 @@ static int dbg_ahci_dump_show(struct seq_file *s, void *unused)
#endif
if (tegra_powergate_is_powered(TEGRA_POWERGATE_SATA))
- seq_printf(s, "\n=== SATA controller is powered on ===\n\n");
+ seq_puts(s, "\n=== SATA controller is powered on ===\n\n");
else
- seq_printf(s, "\n=== SATA controller is powered off ===\n\n");
+ seq_puts(s, "\n=== SATA controller is powered off ===\n\n");
return 0;
}