diff options
| author | Richard Zhu <r65037@freescale.com> | 2014-01-02 13:18:36 +0800 |
|---|---|---|
| committer | Nitin Garg <nitin.garg@freescale.com> | 2014-06-03 23:01:56 -0500 |
| commit | 403f4fb1c4f529ff0733614a8129ebd9e0459dea (patch) | |
| tree | e213d09528f599bc3c4a5fad38ebce50e07c0be9 | |
| parent | 98aa9aeae14e06ce89ec0e13201f3587e0f92c15 (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.c | 32 | ||||
| -rw-r--r-- | arch/arm/mach-mx6/board-mx6q_sabreauto.c | 32 | ||||
| -rw-r--r-- | arch/arm/mach-mx6/board-mx6q_sabrelite.c | 32 | ||||
| -rw-r--r-- | arch/arm/mach-mx6/board-mx6q_sabresd.c | 32 | ||||
| -rw-r--r-- | arch/arm/plat-mxc/ahci_sata.c | 13 | ||||
| -rwxr-xr-x | arch/arm/plat-mxc/include/mach/ahci_sata.h | 16 | ||||
| -rw-r--r-- | drivers/ata/ahci_platform.c | 21 |
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) |
