summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2014-01-02 13:18:36 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-06-03 23:01:56 -0500
commit403f4fb1c4f529ff0733614a8129ebd9e0459dea (patch)
treee213d09528f599bc3c4a5fad38ebce50e07c0be9
parent98aa9aeae14e06ce89ec0e13201f3587e0f92c15 (diff)
ENGR00296249 sata: cr-rst workaround sata phy link issues
- add sata phy cr(offset:0x7f3f) reset in sata resume to workaround imx6q sata kinds of suspend resume link issues. - add sata phy cr reset during imx6q sata initialization, to initialize the sata phy to be an initialized state. - add about 100us delay between mpll_clk enable and cr-rst, make sure that the mpll_clk is stable. - add about 100us delay between cr-rst and waiting for rx_pll stable too, make sure that the cr-rst is finished. - make sure mpll_clk enable(bit1 of gpr13) is cleared, before set it, otherwise, the sata phy link maybe failed when some devices are used. In order to level the compatibility: - enable the ssc support(bit14 of gpr13) - change the TX boost control(bit10~7) from 0dB to be the default value 3.33dB. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--arch/arm/mach-mx6/board-mx6q_arm2.c32
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabreauto.c32
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabrelite.c32
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.c32
-rw-r--r--arch/arm/plat-mxc/ahci_sata.c13
-rwxr-xr-xarch/arm/plat-mxc/include/mach/ahci_sata.h16
-rw-r--r--drivers/ata/ahci_platform.c21
7 files changed, 135 insertions, 43 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c
index 5ca47f934681..ea42dba0e7eb 100644
--- a/arch/arm/mach-mx6/board-mx6q_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6q_arm2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -1267,10 +1267,10 @@ static struct viv_gpu_platform_data imx6_gpu_pdata __initdata = {
};
/* HW Initialization, if return 0, initialization is successful. */
-static int mx6_arm2_sata_init(struct device *dev, void __iomem *addr)
+static int mx6_arm2_sata_init(struct device *dev, void __iomem *mmio)
{
u32 tmpdata;
- int ret = 0;
+ int ret = 0, i;
struct clk *clk;
/* Enable SATA PWR CTRL_0 of MAX7310 */
@@ -1303,12 +1303,28 @@ static int mx6_arm2_sata_init(struct device *dev, void __iomem *addr)
*.tx_edgerate_0(iomuxc_gpr13[0]),
*/
tmpdata = readl(IOMUXC_GPR13);
- writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13);
+ writel(((tmpdata & ~0x07FFFFFF) | 0x0593E4C4), IOMUXC_GPR13);
/* enable SATA_PHY PLL */
tmpdata = readl(IOMUXC_GPR13);
writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13);
+ usleep_range(100, 200);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RESET, mmio);
+ sata_phy_cr_write(SATA_PHY_CR_RESET_EN, mmio);
+ usleep_range(100, 200);
+ /* waiting for the rx_pll is stable */
+ for (i = 0; i <= 5; i++) {
+ sata_phy_cr_addr(SATA_PHY_CR_LANE0_OUT_STAT, mmio);
+ sata_phy_cr_read(&ret, mmio);
+ if (ret & SATA_PHY_CR_LANE0_RX_STABLE) {
+ pr_info("sata phy rx_pll is stable!\n");
+ break;
+ } else if (i == 5)
+ pr_info("wating for sata rx_pll lock time out\n");
+ usleep_range(1000, 2000);
+ }
+
/* Get the AHB clock rate, and configure the TIMER1MS reg later */
clk = clk_get(NULL, "ahb");
if (IS_ERR(clk)) {
@@ -1320,15 +1336,15 @@ static int mx6_arm2_sata_init(struct device *dev, void __iomem *addr)
clk_put(clk);
#ifdef CONFIG_SATA_AHCI_PLATFORM
- ret = sata_init(addr, tmpdata);
+ ret = sata_init(mmio, tmpdata);
if (ret == 0)
return ret;
#else
usleep_range(1000, 2000);
/* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */
- tmpdata = readl(addr + PORT_PHY_CTL);
- writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL);
- pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL)
+ tmpdata = readl(mmio + PORT_PHY_CTL);
+ writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
+ pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(mmio + PORT_PHY_CTL)
>> 20) & 1) ? "enabled" : "disabled");
#endif
diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
index fb4fdcd41d48..adb56f88ec81 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -874,10 +874,10 @@ static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = {
};
/* HW Initialization, if return 0, initialization is successful. */
-static int mx6q_sabreauto_sata_init(struct device *dev, void __iomem *addr)
+static int mx6q_sabreauto_sata_init(struct device *dev, void __iomem *mmio)
{
u32 tmpdata;
- int ret = 0;
+ int ret = 0, i;
struct clk *clk;
sata_clk = clk_get(dev, "imx_sata_clk");
@@ -906,12 +906,28 @@ static int mx6q_sabreauto_sata_init(struct device *dev, void __iomem *addr)
*.tx_edgerate_0(iomuxc_gpr13[0]),
*/
tmpdata = readl(IOMUXC_GPR13);
- writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13);
+ writel(((tmpdata & ~0x07FFFFFF) | 0x0593E4C4), IOMUXC_GPR13);
/* enable SATA_PHY PLL */
tmpdata = readl(IOMUXC_GPR13);
writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13);
+ usleep_range(100, 200);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RESET, mmio);
+ sata_phy_cr_write(SATA_PHY_CR_RESET_EN, mmio);
+ usleep_range(100, 200);
+ /* waiting for the rx_pll is stable */
+ for (i = 0; i <= 5; i++) {
+ sata_phy_cr_addr(SATA_PHY_CR_LANE0_OUT_STAT, mmio);
+ sata_phy_cr_read(&ret, mmio);
+ if (ret & SATA_PHY_CR_LANE0_RX_STABLE) {
+ pr_info("sata phy rx_pll is stable!\n");
+ break;
+ } else if (i == 5)
+ pr_info("wating for sata rx_pll lock time out\n");
+ usleep_range(1000, 2000);
+ }
+
/* Get the AHB clock rate, and configure the TIMER1MS reg later */
clk = clk_get(NULL, "ahb");
if (IS_ERR(clk)) {
@@ -923,15 +939,15 @@ static int mx6q_sabreauto_sata_init(struct device *dev, void __iomem *addr)
clk_put(clk);
#ifdef CONFIG_SATA_AHCI_PLATFORM
- ret = sata_init(addr, tmpdata);
+ ret = sata_init(mmio, tmpdata);
if (ret == 0)
return ret;
#else
usleep_range(1000, 2000);
/* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */
- tmpdata = readl(addr + PORT_PHY_CTL);
- writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL);
- pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL)
+ tmpdata = readl(mmio + PORT_PHY_CTL);
+ writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
+ pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(mmio + PORT_PHY_CTL)
>> 20) & 1) ? "enabled" : "disabled");
#endif
diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
index c4757fbda4b7..93e3884ba03c 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabrelite.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -679,10 +679,10 @@ static void __init imx6q_sabrelite_init_usb(void)
}
/* HW Initialization, if return 0, initialization is successful. */
-static int mx6q_sabrelite_sata_init(struct device *dev, void __iomem *addr)
+static int mx6q_sabrelite_sata_init(struct device *dev, void __iomem *mmio)
{
u32 tmpdata;
- int ret = 0;
+ int ret = 0, i;
struct clk *clk;
sata_clk = clk_get(dev, "imx_sata_clk");
@@ -711,12 +711,28 @@ static int mx6q_sabrelite_sata_init(struct device *dev, void __iomem *addr)
*.tx_edgerate_0(iomuxc_gpr13[0]),
*/
tmpdata = readl(IOMUXC_GPR13);
- writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13);
+ writel(((tmpdata & ~0x07FFFFFF) | 0x0593E4C4), IOMUXC_GPR13);
/* enable SATA_PHY PLL */
tmpdata = readl(IOMUXC_GPR13);
writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13);
+ usleep_range(100, 200);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RESET, mmio);
+ sata_phy_cr_write(SATA_PHY_CR_RESET_EN, mmio);
+ usleep_range(100, 200);
+ /* waiting for the rx_pll is stable */
+ for (i = 0; i <= 5; i++) {
+ sata_phy_cr_addr(SATA_PHY_CR_LANE0_OUT_STAT, mmio);
+ sata_phy_cr_read(&ret, mmio);
+ if (ret & SATA_PHY_CR_LANE0_RX_STABLE) {
+ pr_info("sata phy rx_pll is stable!\n");
+ break;
+ } else if (i == 5)
+ pr_info("wating for sata rx_pll lock time out\n");
+ usleep_range(1000, 2000);
+ }
+
/* Get the AHB clock rate, and configure the TIMER1MS reg later */
clk = clk_get(NULL, "ahb");
if (IS_ERR(clk)) {
@@ -728,15 +744,15 @@ static int mx6q_sabrelite_sata_init(struct device *dev, void __iomem *addr)
clk_put(clk);
#ifdef CONFIG_SATA_AHCI_PLATFORM
- ret = sata_init(addr, tmpdata);
+ ret = sata_init(mmio, tmpdata);
if (ret == 0)
return ret;
#else
usleep_range(1000, 2000);
/* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */
- tmpdata = readl(addr + PORT_PHY_CTL);
- writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL);
- pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL)
+ tmpdata = readl(mmio + PORT_PHY_CTL);
+ writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
+ pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(mmio + PORT_PHY_CTL)
>> 20) & 1) ? "enabled" : "disabled");
#endif
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c
index b7b9babff034..6418025d8d4c 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -1142,10 +1142,10 @@ static void __init imx6q_sabresd_init_usb(void)
}
/* HW Initialization, if return 0, initialization is successful. */
-static int mx6q_sabresd_sata_init(struct device *dev, void __iomem *addr)
+static int mx6q_sabresd_sata_init(struct device *dev, void __iomem *mmio)
{
u32 tmpdata;
- int ret = 0;
+ int ret = 0, i;
struct clk *clk;
sata_clk = clk_get(dev, "imx_sata_clk");
@@ -1174,12 +1174,28 @@ static int mx6q_sabresd_sata_init(struct device *dev, void __iomem *addr)
*.tx_edgerate_0(iomuxc_gpr13[0]),
*/
tmpdata = readl(IOMUXC_GPR13);
- writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13);
+ writel(((tmpdata & ~0x07FFFFFF) | 0x0593E4C4), IOMUXC_GPR13);
/* enable SATA_PHY PLL */
tmpdata = readl(IOMUXC_GPR13);
writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13);
+ usleep_range(100, 200);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RESET, mmio);
+ sata_phy_cr_write(SATA_PHY_CR_RESET_EN, mmio);
+ usleep_range(100, 200);
+ /* waiting for the rx_pll is stable */
+ for (i = 0; i <= 5; i++) {
+ sata_phy_cr_addr(SATA_PHY_CR_LANE0_OUT_STAT, mmio);
+ sata_phy_cr_read(&ret, mmio);
+ if (ret & SATA_PHY_CR_LANE0_RX_STABLE) {
+ pr_info("sata phy rx_pll is stable!\n");
+ break;
+ } else if (i == 5)
+ pr_info("wating for sata rx_pll lock time out\n");
+ usleep_range(1000, 2000);
+ }
+
/* Get the AHB clock rate, and configure the TIMER1MS reg later */
clk = clk_get(NULL, "ahb");
if (IS_ERR(clk)) {
@@ -1191,15 +1207,15 @@ static int mx6q_sabresd_sata_init(struct device *dev, void __iomem *addr)
clk_put(clk);
#ifdef CONFIG_SATA_AHCI_PLATFORM
- ret = sata_init(addr, tmpdata);
+ ret = sata_init(mmio, tmpdata);
if (ret == 0)
return ret;
#else
usleep_range(1000, 2000);
/* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */
- tmpdata = readl(addr + PORT_PHY_CTL);
- writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL);
- pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL)
+ tmpdata = readl(mmio + PORT_PHY_CTL);
+ writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
+ pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(mmio + PORT_PHY_CTL)
>> 20) & 1) ? "enabled" : "disabled");
#endif
diff --git a/arch/arm/plat-mxc/ahci_sata.c b/arch/arm/plat-mxc/ahci_sata.c
index de172a9483eb..308a905abae9 100644
--- a/arch/arm/plat-mxc/ahci_sata.c
+++ b/arch/arm/plat-mxc/ahci_sata.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -27,6 +27,16 @@
#include <mach/hardware.h>
#include <mach/ahci_sata.h>
+enum {
+ HOST_CAP = 0x00,
+ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CTL = 0x04, /* global host control */
+ HOST_RESET = (1 << 0), /* reset controller; self-clear */
+ HOST_PORTS_IMPL = 0x0c,
+ HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
+ HOST_VERSIONR = 0xfc, /* host version register*/
+};
+
int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
int max_iterations, u32 exp_val)
{
@@ -79,6 +89,7 @@ int sata_phy_cr_write(u32 data, void __iomem *mmio)
/* write data */
temp_wr_data = data;
+ writel(temp_wr_data, mmio + PORT_PHY_CTL);
/* capture data */
temp_wr_data |= PORT_PHY_CTL_CAP_DAT_LOC;
diff --git a/arch/arm/plat-mxc/include/mach/ahci_sata.h b/arch/arm/plat-mxc/include/mach/ahci_sata.h
index 48b93e55eea0..d75689c8b731 100755
--- a/arch/arm/plat-mxc/include/mach/ahci_sata.h
+++ b/arch/arm/plat-mxc/include/mach/ahci_sata.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -20,14 +20,6 @@
#define __PLAT_MXC_AHCI_SATA_H__
enum {
- HOST_CAP = 0x00,
- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
- HOST_CTL = 0x04, /* global host control */
- HOST_RESET = (1 << 0), /* reset controller; self-clear */
- HOST_PORTS_IMPL = 0x0c,
- HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
- HOST_VERSIONR = 0xfc, /* host version register*/
-
/* Offest used to control the MPLL input clk */
PHY_CR_CLOCK_FREQ_OVRD = 0x12,
/* Port0 SATA Status */
@@ -51,6 +43,12 @@ enum {
SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009,
SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A,
SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017,
+
+ SATA_PHY_CR_CLOCK_RESET = 0x7F3F,
+ SATA_PHY_CR_RESET_EN = 0x0001,
+
+ SATA_PHY_CR_LANE0_OUT_STAT = 0x2003,
+ SATA_PHY_CR_LANE0_RX_STABLE = 0x0002,
};
extern int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 936babd0fb9e..7f525d97d5f1 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
+#include <mach/ahci_sata.h>
#include "ahci.h"
static struct scsi_host_template ahci_platform_sht = {
@@ -211,7 +212,9 @@ static int ahci_device_resume(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
- int rc;
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ int i, rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -219,6 +222,22 @@ static int ahci_device_resume(struct platform_device *pdev)
return rc;
}
+ usleep_range(100, 200);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RESET, mmio);
+ sata_phy_cr_write(SATA_PHY_CR_RESET_EN, mmio);
+ usleep_range(100, 200);
+ /* waiting for the rx_pll is stable */
+ for (i = 0; i <= 5; i++) {
+ sata_phy_cr_addr(SATA_PHY_CR_LANE0_OUT_STAT, mmio);
+ sata_phy_cr_read(&rc, mmio);
+ if (rc & SATA_PHY_CR_LANE0_RX_STABLE) {
+ pr_info("sata phy rx_pll is stable!\n");
+ break;
+ } else if (i == 5)
+ pr_info("wating for sata rx_pll lock time out\n");
+ usleep_range(1000, 2000);
+ }
+
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)