diff options
author | venkatajagadish <vjagadish@nvidia.com> | 2013-09-25 12:46:45 +0530 |
---|---|---|
committer | Venkata Jagadish <vjagadish@nvidia.com> | 2013-10-18 03:05:26 -0700 |
commit | 688dea3223cc049f368d113b1890dbd2b0004dab (patch) | |
tree | d9c876c434792f7bd0eb4c753f21a36aecc47c19 /drivers/ata | |
parent | 3f638fa24eece18ab788af61d17308e10b289a25 (diff) |
ARM: tegra: t12x: Sata Lp0 related changes
Bug 1357649
Change-Id: I3c2b856319d20a3da9697af5f9ccc3fae2d5b6d6
Signed-off-by: venkatajagadish <vjagadish@nvidia.com>
Reviewed-on: http://git-master/r/299817
Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ahci-tegra.c | 182 |
1 files changed, 163 insertions, 19 deletions
diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c index b3d09e3be12d..d9a769044b3e 100644 --- a/drivers/ata/ahci-tegra.c +++ b/drivers/ata/ahci-tegra.c @@ -139,14 +139,25 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME; #define TEGRA_SATA_OOB_CLOCK_FREQ_HZ (272*1000*1000) #define APB_PMC_SATA_PWRGT_0_REG 0x1ac +#define APBDEV_PMC_PWRGATE_TOGGLE_0 0x30 +#define APBDEV_PMC_PWRGATE_STATUS_0 0x38 +#define APBDEV_PMC_REMOVE_CLAMPING_CMD_0 0x34 + #define CLK_RST_SATA_PLL_CFG0_REG 0x490 #define CLK_RST_SATA_PLL_CFG1_REG 0x494 #define CLK_RST_CONTROLLER_RST_DEVICES_V_0 0x358 #define CLK_RST_CONTROLLER_RST_DEVICES_W_0 0x35c #define CLK_RST_CONTROLLER_RST_DEV_W_CLR_0 0x43c #define CLK_RST_CONTROLLER_RST_DEV_V_CLR_0 0x434 +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR_0 0x444 +#define CLK_RST_CONTROLLER_CLK_ENB_V_SET_0 0x440 + +#define CLR_CLK_ENB_SATA_OOB (1 << 27) +#define CLR_CLK_ENB_SATA (1 << 28) #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 CLK_RST_CONTROLLER_PLLE_AUX_0 0x48c #define CLK_RST_CONTROLLER_PLLE_AUX_0_MASK (1 << 1) @@ -159,6 +170,7 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME; #define DESO_SUPPORT (1 << 15) #define SATA_AUX_PAD_PLL_CNTL_1_REG 0x1100 #define SATA_AUX_MISC_CNTL_1_REG 0x1108 +#define SATA_AUX_SPARE_CFG0_0 0x1118 /* for APB_PMC_SATA_PWRGT_0_REG */ #define PG_INFO_MASK (1 << 6) @@ -180,6 +192,11 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME; #define PADPLL_IDDQ_SWCTL_ON (1 << 0) #define PADPLL_IDDQ_SWCTL_OFF (0 << 0) +#define START (1 < 8) +#define PARTID_VALUE 0x8 + +#define SAX_MASK (1 << 8) + /* for CLK_RST_SATA_PLL_CFG0_REG */ #define PADPLL_RESET_OVERRIDE_VALUE_MASK (1 << 1) #define PADPLL_RESET_OVERRIDE_VALUE_ON (1 << 1) @@ -222,6 +239,9 @@ static u32 tegra_ahci_idle_time = TEGRA_AHCI_DEFAULT_IDLE_TIME; #define AUX_ELPG_CLAMP_EN (1 << 24) #define AUX_ELPG_CLAMP_EN_EARLY (1 << 25) #define AUX_ELPG_VCORE_DOWN (1 << 26) +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL_1_0 0x148 +#define XUSB_PADCTL_IOPHY_MISC_IDDQ_OVRD (1 << 1) +#define XUSB_PADCTL_IOPHY_MISC_IDDQ (1 << 0) #define SATA_AXI_BAR5_START_0 0x54 #define SATA_AXI_BAR5_SZ_0 0x14 @@ -660,7 +680,8 @@ int tegra_ahci_power_off_rails(struct regulator *regulators[]) exit: return ret; } -static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv) +static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv, + int lp0) { int err; struct clk *clk_sata = NULL; @@ -674,12 +695,14 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv) struct tegra_ahci_platform_data *ahci_pdata = tegra_hpriv->dev->platform_data; - err = tegra_ahci_get_rails(tegra_hpriv->power_rails); - if (err) { - pr_err("%s: fails to get rails (%d)\n", __func__, err); - goto exit; - } + if (!lp0) { + err = tegra_ahci_get_rails(tegra_hpriv->power_rails); + if (err) { + pr_err("%s: fails to get rails (%d)\n", __func__, err); + goto exit; + } + } err = tegra_ahci_power_on_rails(tegra_hpriv->power_rails); if (err) { pr_err("%s: fails to power on rails (%d)\n", __func__, err); @@ -769,6 +792,7 @@ static int tegra_ahci_controller_init(struct tegra_ahci_host_priv *tegra_hpriv) 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"); @@ -779,6 +803,8 @@ 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 ****/ @@ -863,7 +889,6 @@ 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 */ @@ -1032,7 +1057,6 @@ exit: /* return regulators to system */ tegra_ahci_put_rails(tegra_hpriv->power_rails); } - return err; } @@ -1094,7 +1118,6 @@ static int tegra_ahci_controller_suspend(struct platform_device *pdev) tegra_hpriv->pg_state = SATA_OFF; dev_dbg(host->dev, "suspend: SATA is power gated\n"); } else { - dev_err(host->dev, "suspend: abort power gating\n"); tegra_ahci_abort_power_gate(host); spin_unlock_irqrestore(&host->lock, flags); return -EBUSY; @@ -1170,6 +1193,14 @@ 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); if (rc) @@ -1281,12 +1312,14 @@ static int tegra_ahci_runtime_resume(struct device *dev) err = -EBUSY; } + exit: spin_unlock_irqrestore(&host->lock, flags); return err; } -#endif +#endif +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) static u16 pg_save_bar5_registers[] = { 0x018, /* T_AHCI_HBA_CCC_PORTS */ 0x004, /* T_AHCI_HBA_GHC */ @@ -1591,7 +1624,7 @@ static void tegra_ahci_pg_restore_registers(struct ata_host *host) val &= ~TEGRA_PRIVATE_AHCI_CC_BKDR_OVERRIDE_EN; scfg_writel(val, TEGRA_PRIVATE_AHCI_CC_BKDR_OVERRIDE); } - +#endif static u32 tegra_ahci_port_error(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); @@ -1644,7 +1677,16 @@ 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) 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 @@ -1660,9 +1702,26 @@ static bool tegra_ahci_power_gate(struct ata_host *host) 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 + + /* abort PG if there are errors occurred */ if (tegra_ahci_check_errors(host)) { dev_err(host->dev, "** pg: errors; abort power gating **\n"); @@ -1702,6 +1761,17 @@ static bool tegra_ahci_power_gate(struct ata_host *host) 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; + pmc_writel(val, APBDEV_PMC_PWRGATE_TOGGLE_0); + + 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) @@ -1718,6 +1788,7 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host) 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; @@ -1741,6 +1812,17 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host) val |= (PADPHY_IDDQ_SWCTL_OFF | PADPHY_IDDQ_OVERRIDE_VALUE_OFF); 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; + pmc_writel(val, APBDEV_PMC_PWRGATE_TOGGLE_0); + + 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) dev_err(host->dev, "** failed to turn-on SATA (0x%x) **\n", @@ -1752,6 +1834,63 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host) 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 + +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) + /* restore registers */ + tegra_ahci_pg_restore_registers(host); +#endif + +#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. @@ -1770,9 +1909,6 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host) if (timeout == 0) pr_err("%s: SATA_PAD_PLL is not locked in 15us.\n", __func__); - /* restore registers */ - tegra_ahci_pg_restore_registers(host); - /* * During the restoration of the registers, the driver would now need to * restore the register T_SATA0_CFG_POWER_GATE_SSTS_RESTORED after the @@ -1785,12 +1921,15 @@ static bool tegra_ahci_power_un_gate(struct ata_host *host) val |= POWER_GATE_SSTS_RESTORED_YES; scfg_writel(val, T_SATA0_CFG_POWER_GATE); + /* * Driver needs to switch the rx_idle_t driven source back to from * 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); @@ -1845,6 +1984,7 @@ 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) { @@ -1915,7 +2055,6 @@ static void tegra_ahci_idle_timer(unsigned long arg) return; } spin_unlock_irqrestore(&host->lock, flags); - pm_runtime_put(tegra_hpriv->dev); } @@ -1985,6 +2124,7 @@ static unsigned int tegra_ahci_qc_issue(struct ata_queued_cmd *qc) return AC_ERR_SYSTEM; } 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); @@ -2076,8 +2216,11 @@ static int tegra_ahci_init_one(struct platform_device *pdev) struct resource *res, *irq_res; void __iomem *mmio; #ifdef CONFIG_PM + +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) u32 save_size; #endif +#endif irq_handler_t irq_handler = ahci_interrupt; VPRINTK("ENTER\n"); @@ -2114,11 +2257,11 @@ static int tegra_ahci_init_one(struct platform_device *pdev) } hpriv->flags |= (unsigned long)pi.private_data; tegra_hpriv = (struct tegra_ahci_host_priv *)hpriv; - g_tegra_hpriv = tegra_hpriv; tegra_hpriv->dev = dev; + g_tegra_hpriv = tegra_hpriv; /* Call tegra init routine */ - rc = tegra_ahci_controller_init(tegra_hpriv); + rc = tegra_ahci_controller_init(tegra_hpriv, 0); if (rc != 0) { dev_err(dev, "TEGRA SATA init failed\n"); goto fail; @@ -2161,7 +2304,7 @@ static int tegra_ahci_init_one(struct platform_device *pdev) if (!(hpriv->cap & HOST_CAP_SSS)) host->flags |= ATA_HOST_PARALLEL_SCAN; else - printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n"); + pr_info("ahci: SSS flag set, parallel bus scan disabled\n"); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -2187,6 +2330,7 @@ static int tegra_ahci_init_one(struct platform_device *pdev) dev_dbg(dev, "controller init okay\n"); #ifdef CONFIG_PM +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) /* Setup PG save/restore area: */ /* calculate the size */ @@ -2211,7 +2355,7 @@ static int tegra_ahci_init_one(struct platform_device *pdev) rc = -ENOMEM; goto fail; } - +#endif #ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE pm_runtime_set_active(dev); pm_suspend_ignore_children(dev, true); |