Commit c934b361 authored by Roger Quadros's avatar Roger Quadros Committed by Kishon Vijay Abraham I

phy: ti-pipe3: i783 workaround for SATA lockup after dpll unlock/relock

SATA_PLL_SOFT_RESET bit of CTRL_CORE_SMA_SW_0 must be toggled
between a SATA DPLL unlock and re-lock to prevent SATA lockup.

Introduce a new DT parameter 'syscon-pllreset' to provide the syscon
regmap access to this register which sits in the control module.

If the register is not provided we fallback to the old behaviour
i.e. SATA DPLL refclk will not be disabled and we prevent SoC low
power states.
Signed-off-by: default avatarRoger Quadros <rogerq@ti.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 7167bf8b
...@@ -82,6 +82,9 @@ Optional properties: ...@@ -82,6 +82,9 @@ Optional properties:
- id: If there are multiple instance of the same type, in order to - id: If there are multiple instance of the same type, in order to
differentiate between each instance "id" can be used (e.g., multi-lane PCIe differentiate between each instance "id" can be used (e.g., multi-lane PCIe
PHY). If "id" is not provided, it is set to default value of '1'. PHY). If "id" is not provided, it is set to default value of '1'.
- syscon-pllreset: Handle to system control region that contains the
CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
This is usually a subnode of ocp2scp to which it is connected. This is usually a subnode of ocp2scp to which it is connected.
...@@ -100,3 +103,16 @@ usb3phy@4a084400 { ...@@ -100,3 +103,16 @@ usb3phy@4a084400 {
"sysclk", "sysclk",
"refclk"; "refclk";
}; };
sata_phy: phy@4A096000 {
compatible = "ti,phy-pipe3-sata";
reg = <0x4A096000 0x80>, /* phy_rx */
<0x4A096400 0x64>, /* phy_tx */
<0x4A096800 0x40>; /* pll_ctrl */
reg-names = "phy_rx", "phy_tx", "pll_ctrl";
ctrl-module = <&omap_control_sata>;
clocks = <&sys_clkin1>, <&sata_ref_clk>;
clock-names = "sysclk", "refclk";
syscon-pllreset = <&scm_conf 0x3fc>;
#phy-cells = <0>;
};
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/phy/omap_control_phy.h> #include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#define PLL_STATUS 0x00000004 #define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008 #define PLL_GO 0x00000008
...@@ -52,6 +54,8 @@ ...@@ -52,6 +54,8 @@
#define PLL_LOCK 0x2 #define PLL_LOCK 0x2
#define PLL_IDLE 0x1 #define PLL_IDLE 0x1
#define SATA_PLL_SOFT_RESET BIT(18)
/* /*
* This is an Empirical value that works, need to confirm the actual * This is an Empirical value that works, need to confirm the actual
* value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
...@@ -82,6 +86,9 @@ struct ti_pipe3 { ...@@ -82,6 +86,9 @@ struct ti_pipe3 {
struct clk *refclk; struct clk *refclk;
struct clk *div_clk; struct clk *div_clk;
struct pipe3_dpll_map *dpll_map; struct pipe3_dpll_map *dpll_map;
struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */
unsigned int dpll_reset_reg; /* reg. index within syscon */
bool sata_refclk_enabled;
}; };
static struct pipe3_dpll_map dpll_map_usb[] = { static struct pipe3_dpll_map dpll_map_usb[] = {
...@@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x) ...@@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x)
u32 val; u32 val;
unsigned long timeout; unsigned long timeout;
/* SATA DPLL can't be powered down due to Errata i783 */ /* If dpll_reset_syscon is not present we wont power down SATA DPLL
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) * due to Errata i783
*/
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") &&
!phy->dpll_reset_syscon)
return 0; return 0;
/* PCIe doesn't have internal DPLL */ /* PCIe doesn't have internal DPLL */
...@@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x) ...@@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x)
} }
} }
/* i783: SATA needs control bit toggle after PLL unlock */
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) {
regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
SATA_PLL_SOFT_RESET, 0);
}
ti_pipe3_disable_clocks(phy); ti_pipe3_disable_clocks(phy);
return 0; return 0;
...@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
} }
} else { } else {
phy->wkupclk = ERR_PTR(-ENODEV); phy->wkupclk = ERR_PTR(-ENODEV);
phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
"syscon-pllreset");
if (IS_ERR(phy->dpll_reset_syscon)) {
dev_info(&pdev->dev,
"can't get syscon-pllreset, sata dpll won't idle\n");
phy->dpll_reset_syscon = NULL;
} else {
if (of_property_read_u32_index(node,
"syscon-pllreset", 1,
&phy->dpll_reset_reg)) {
dev_err(&pdev->dev,
"couldn't get pllreset reg. offset\n");
return -EINVAL;
}
}
} }
if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
...@@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy); platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev); pm_runtime_enable(phy->dev);
/* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */
if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) /*
if (!IS_ERR(phy->refclk)) * Prevent auto-disable of refclk for SATA PHY due to Errata i783
*/
if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
if (!IS_ERR(phy->refclk)) {
clk_prepare_enable(phy->refclk); clk_prepare_enable(phy->refclk);
phy->sata_refclk_enabled = true;
}
}
generic_phy = devm_phy_create(phy->dev, NULL, &ops); generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy)) if (IS_ERR(generic_phy))
...@@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) ...@@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{ {
if (!IS_ERR(phy->wkupclk)) if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk); clk_disable_unprepare(phy->wkupclk);
if (!IS_ERR(phy->refclk)) if (!IS_ERR(phy->refclk)) {
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
/*
* SATA refclk needs an additional disable as we left it
* on in probe to avoid Errata i783
*/
if (phy->sata_refclk_enabled) {
clk_disable_unprepare(phy->refclk);
phy->sata_refclk_enabled = false;
}
}
if (!IS_ERR(phy->div_clk)) if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk); clk_disable_unprepare(phy->div_clk);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment