The patches of this series were originally in the series "Add suspend to
ram support for PCIe on J7200" [1].
They were moved in a separate series as requested by the PHY maintainer.
This series adds suspend and resume support for the phy-cadence-torrent and
phy-j721e-wiz drivers.
Compared to the PCIe series v4 [1], these PHY patches were rebased on Linux
v6.9-rc1.
The only change is for the patch "phy: cadence-torrent: extract calls to
clk_get from cdns_torrent_clk". Now the cadence-torrent driver supports
dual reference clock, so the patch was updated consequently.
[1] https://lore.kernel.org/all/[email protected]/
Regards,
Thomas
Signed-off-by: Thomas Richard <[email protected]>
---
Thomas Richard (8):
phy: ti: phy-j721e-wiz: use dev_err_probe() instead of dev_err()
phy: ti: phy-j721e-wiz: split wiz_clock_init() function
phy: ti: phy-j721e-wiz: add resume support
phy: cadence-torrent: extract calls to clk_get from cdns_torrent_clk
phy: cadence-torrent: register resets even if the phy is already configured
phy: cadence-torrent: add already_configured to struct cdns_torrent_phy
phy: cadence-torrent: remove noop_ops phy operations
phy: cadence-torrent: add suspend and resume support
drivers/phy/cadence/phy-cadence-torrent.c | 140 +++++++++++++++++++++---------
drivers/phy/ti/phy-j721e-wiz.c | 133 +++++++++++++++++-----------
2 files changed, 182 insertions(+), 91 deletions(-)
---
base-commit: b6b2d5379911df41ad51f7773ed98ef18b939258
change-id: 20240412-j7200-phy-s2r-708ea63aea78
Best regards,
--
Thomas Richard <[email protected]>
The wiz_clock_init() function mixes probe and hardware configuration.
Rename the wiz_clock_init() to wiz_clock_probe() and move the hardware
configuration part in a new function named wiz_clock_init().
This hardware configuration sequence must be called during the resume
stage of the driver.
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/ti/phy-j721e-wiz.c | 66 +++++++++++++++++++++++-------------------
1 file changed, 37 insertions(+), 29 deletions(-)
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 5fea4df9404e..ba670109e7ad 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1076,26 +1076,12 @@ static int wiz_clock_register(struct wiz *wiz)
return ret;
}
-static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
+static void wiz_clock_init(struct wiz *wiz)
{
- const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
- struct device *dev = wiz->dev;
- struct device_node *clk_node;
- const char *node_name;
unsigned long rate;
- struct clk *clk;
- int ret;
- int i;
-
- clk = devm_clk_get(dev, "core_ref_clk");
- if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk),
- "core_ref_clk clock not found\n");
- wiz->input_clks[WIZ_CORE_REFCLK] = clk;
-
- rate = clk_get_rate(clk);
- if (rate >= 100000000)
+ rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK]);
+ if (rate >= REF_CLK_100MHZ)
regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x1);
else
regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3);
@@ -1119,6 +1105,38 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
break;
}
+ if (wiz->input_clks[WIZ_CORE_REFCLK1]) {
+ rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK1]);
+ if (rate >= REF_CLK_100MHZ)
+ regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1);
+ else
+ regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3);
+ }
+
+ rate = clk_get_rate(wiz->input_clks[WIZ_EXT_REFCLK]);
+ if (rate >= REF_CLK_100MHZ)
+ regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0);
+ else
+ regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
+}
+
+static int wiz_clock_probe(struct wiz *wiz, struct device_node *node)
+{
+ const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
+ struct device *dev = wiz->dev;
+ struct device_node *clk_node;
+ const char *node_name;
+ struct clk *clk;
+ int ret;
+ int i;
+
+ clk = devm_clk_get(dev, "core_ref_clk");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "core_ref_clk clock not found\n");
+
+ wiz->input_clks[WIZ_CORE_REFCLK] = clk;
+
if (wiz->data->pma_cmn_refclk1_int_mode) {
clk = devm_clk_get(dev, "core_ref1_clk");
if (IS_ERR(clk))
@@ -1126,12 +1144,6 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
"core_ref1_clk clock not found\n");
wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
-
- rate = clk_get_rate(clk);
- if (rate >= 100000000)
- regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1);
- else
- regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3);
}
clk = devm_clk_get(dev, "ext_ref_clk");
@@ -1141,11 +1153,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
wiz->input_clks[WIZ_EXT_REFCLK] = clk;
- rate = clk_get_rate(clk);
- if (rate >= 100000000)
- regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0);
- else
- regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
+ wiz_clock_init(wiz);
switch (wiz->type) {
case AM64_WIZ_10G:
@@ -1589,7 +1597,7 @@ static int wiz_probe(struct platform_device *pdev)
goto err_get_sync;
}
- ret = wiz_clock_init(wiz, node);
+ ret = wiz_clock_probe(wiz, node);
if (ret < 0) {
dev_warn(dev, "Failed to initialize clocks\n");
goto err_get_sync;
--
2.39.2
Add resume support.
It has been tested on J7200 SR1.0 and SR2.0.
Co-developed-by: Théo Lebrun <[email protected]>
Signed-off-by: Théo Lebrun <[email protected]>
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/ti/phy-j721e-wiz.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index ba670109e7ad..7f626c597025 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1659,12 +1659,41 @@ static void wiz_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
}
+static int wiz_resume_noirq(struct device *dev)
+{
+ struct device_node *node = dev->of_node;
+ struct wiz *wiz = dev_get_drvdata(dev);
+ int ret;
+
+ /* Enable supplemental Control override if available */
+ if (wiz->sup_legacy_clk_override)
+ regmap_field_write(wiz->sup_legacy_clk_override, 1);
+
+ wiz_clock_init(wiz);
+
+ ret = wiz_init(wiz);
+ if (ret) {
+ dev_err(dev, "WIZ initialization failed\n");
+ goto err_wiz_init;
+ }
+
+ return 0;
+
+err_wiz_init:
+ wiz_clock_cleanup(wiz, node);
+
+ return ret;
+}
+
+static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq);
+
static struct platform_driver wiz_driver = {
.probe = wiz_probe,
.remove_new = wiz_remove,
.driver = {
.name = "wiz",
.of_match_table = wiz_id_table,
+ .pm = pm_sleep_ptr(&wiz_pm_ops),
},
};
module_platform_driver(wiz_driver);
--
2.39.2
Extract calls to clk_get from cdns_torrent_clk into a separate function.
It needs to call cdns_torrent_clk at resume without looking up the clock.
Co-developed-by: Théo Lebrun <[email protected]>
Signed-off-by: Théo Lebrun <[email protected]>
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/cadence/phy-cadence-torrent.c | 37 ++++++++++++++++++-------------
1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 95924a09960c..e64625859a07 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -2699,20 +2699,29 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
return 0;
}
+static int cdns_torrent_of_get_clk(struct cdns_torrent_phy *cdns_phy)
+{
+ /* refclk: Input reference clock for PLL0 */
+ cdns_phy->clk = devm_clk_get(cdns_phy->dev, "refclk");
+ if (IS_ERR(cdns_phy->clk))
+ return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk),
+ "phy ref clock not found\n");
+
+ /* refclk1: Input reference clock for PLL1 */
+ cdns_phy->clk1 = devm_clk_get_optional(cdns_phy->dev, "pll1_refclk");
+ if (IS_ERR(cdns_phy->clk1))
+ return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk1),
+ "phy PLL1 ref clock not found\n");
+
+ return 0;
+}
+
static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
{
- struct device *dev = cdns_phy->dev;
unsigned long ref_clk1_rate;
unsigned long ref_clk_rate;
int ret;
- /* refclk: Input reference clock for PLL0 */
- cdns_phy->clk = devm_clk_get(dev, "refclk");
- if (IS_ERR(cdns_phy->clk)) {
- dev_err(dev, "phy ref clock not found\n");
- return PTR_ERR(cdns_phy->clk);
- }
-
ret = clk_prepare_enable(cdns_phy->clk);
if (ret) {
dev_err(cdns_phy->dev, "Failed to prepare ref clock: %d\n", ret);
@@ -2745,14 +2754,6 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
goto disable_clk;
}
- /* refclk1: Input reference clock for PLL1 */
- cdns_phy->clk1 = devm_clk_get_optional(dev, "pll1_refclk");
- if (IS_ERR(cdns_phy->clk1)) {
- dev_err(dev, "phy PLL1 ref clock not found\n");
- ret = PTR_ERR(cdns_phy->clk1);
- goto disable_clk;
- }
-
if (cdns_phy->clk1) {
ret = clk_prepare_enable(cdns_phy->clk1);
if (ret) {
@@ -2846,6 +2847,10 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = cdns_torrent_of_get_clk(cdns_phy);
+ if (ret)
+ goto clk_cleanup;
+
regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured);
if (!already_configured) {
--
2.39.2
Use dev_err_probe() instead of dev_err() in wiz_clock_init() to simplify
the code and standardize the error output.
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/ti/phy-j721e-wiz.c | 46 +++++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 00d7e6a6de03..5fea4df9404e 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1088,11 +1088,10 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
int i;
clk = devm_clk_get(dev, "core_ref_clk");
- if (IS_ERR(clk)) {
- dev_err(dev, "core_ref_clk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "core_ref_clk clock not found\n");
+
wiz->input_clks[WIZ_CORE_REFCLK] = clk;
rate = clk_get_rate(clk);
@@ -1122,11 +1121,10 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
if (wiz->data->pma_cmn_refclk1_int_mode) {
clk = devm_clk_get(dev, "core_ref1_clk");
- if (IS_ERR(clk)) {
- dev_err(dev, "core_ref1_clk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "core_ref1_clk clock not found\n");
+
wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
rate = clk_get_rate(clk);
@@ -1137,11 +1135,10 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
}
clk = devm_clk_get(dev, "ext_ref_clk");
- if (IS_ERR(clk)) {
- dev_err(dev, "ext_ref_clk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "ext_ref_clk clock not found\n");
+
wiz->input_clks[WIZ_EXT_REFCLK] = clk;
rate = clk_get_rate(clk);
@@ -1157,8 +1154,9 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
case J721S2_WIZ_10G:
ret = wiz_clock_register(wiz);
if (ret)
- dev_err(dev, "Failed to register wiz clocks\n");
- return ret;
+ return dev_err_probe(dev, ret, "Failed to register wiz clocks\n");
+
+ return 0;
default:
break;
}
@@ -1167,16 +1165,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
node_name = clk_mux_sel[i].node_name;
clk_node = of_get_child_by_name(node, node_name);
if (!clk_node) {
- dev_err(dev, "Unable to get %s node\n", node_name);
- ret = -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name);
goto err;
}
ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i],
clk_mux_sel[i].table);
if (ret) {
- dev_err(dev, "Failed to register %s clock\n",
- node_name);
+ dev_err_probe(dev, ret, "Failed to register %s clock\n",
+ node_name);
of_node_put(clk_node);
goto err;
}
@@ -1188,16 +1185,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
node_name = clk_div_sel[i].node_name;
clk_node = of_get_child_by_name(node, node_name);
if (!clk_node) {
- dev_err(dev, "Unable to get %s node\n", node_name);
- ret = -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name);
goto err;
}
ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i],
clk_div_sel[i].table);
if (ret) {
- dev_err(dev, "Failed to register %s clock\n",
- node_name);
+ dev_err_probe(dev, ret, "Failed to register %s clock\n",
+ node_name);
of_node_put(clk_node);
goto err;
}
--
2.39.2
Resets are needed during suspend and resume stages.
So they shall be registered during the probe even the phy is already
initialized.
The function cdns_torrent_reset is renamed cdns_torrent_of_get_reset() to
make it clear.
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/cadence/phy-cadence-torrent.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index e64625859a07..7b3a409da185 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -2678,7 +2678,7 @@ static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy)
return 0;
}
-static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
+static int cdns_torrent_of_get_reset(struct cdns_torrent_phy *cdns_phy)
{
struct device *dev = cdns_phy->dev;
@@ -2847,6 +2847,10 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = cdns_torrent_of_get_reset(cdns_phy);
+ if (ret)
+ goto clk_cleanup;
+
ret = cdns_torrent_of_get_clk(cdns_phy);
if (ret)
goto clk_cleanup;
@@ -2854,10 +2858,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured);
if (!already_configured) {
- ret = cdns_torrent_reset(cdns_phy);
- if (ret)
- goto clk_cleanup;
-
ret = cdns_torrent_clk(cdns_phy);
if (ret)
goto clk_cleanup;
--
2.39.2
Add already_configured to struct cdns_torrent_phy, so it can be used at
differents stages.
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/cadence/phy-cadence-torrent.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 7b3a409da185..0636d5d04817 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -360,6 +360,7 @@ struct cdns_torrent_phy {
enum cdns_torrent_ref_clk ref_clk1_rate;
struct cdns_torrent_inst phys[MAX_NUM_LANES];
int nsubnodes;
+ int already_configured;
const struct cdns_torrent_data *init_data;
struct regmap *regmap_common_cdb;
struct regmap *regmap_phy_pcs_common_cdb;
@@ -2808,7 +2809,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
struct device_node *child;
int ret, subnodes, node = 0, i;
u32 total_num_lanes = 0;
- int already_configured;
u8 init_dp_regmap = 0;
u32 phy_type;
@@ -2855,9 +2855,9 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
if (ret)
goto clk_cleanup;
- regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured);
+ regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &cdns_phy->already_configured);
- if (!already_configured) {
+ if (!cdns_phy->already_configured) {
ret = cdns_torrent_clk(cdns_phy);
if (ret)
goto clk_cleanup;
@@ -2937,7 +2937,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
of_property_read_u32(child, "cdns,ssc-mode",
&cdns_phy->phys[node].ssc_mode);
- if (!already_configured)
+ if (!cdns_phy->already_configured)
gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
else
gphy = devm_phy_create(dev, child, &noop_ops);
@@ -3023,7 +3023,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
goto put_lnk_rst;
}
- if (cdns_phy->nsubnodes > 1 && !already_configured) {
+ if (cdns_phy->nsubnodes > 1 && !cdns_phy->already_configured) {
ret = cdns_torrent_phy_configure_multilink(cdns_phy);
if (ret)
goto put_lnk_rst;
--
2.39.2
Even if a PHY is already configured, the PHY operations are needed during
resume stage, as the PHY is in reset state.
The noop_ops PHY operations is removed to always have PHY operations.
The already_configured flag is checked at the begening of init, configure
and poweron operations to keep the already_configured behaviour.
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/cadence/phy-cadence-torrent.c | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 0636d5d04817..0e3c755e6089 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -1595,6 +1595,9 @@ static int cdns_torrent_dp_configure(struct phy *phy,
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
+ if (cdns_phy->already_configured)
+ return 0;
+
ret = cdns_torrent_dp_verify_config(inst, &opts->dp);
if (ret) {
dev_err(&phy->dev, "invalid params for phy configure\n");
@@ -1630,6 +1633,12 @@ static int cdns_torrent_phy_on(struct phy *phy)
u32 read_val;
int ret;
+ if (cdns_phy->already_configured) {
+ /* Give 5ms to 10ms delay for the PIPE clock to be stable */
+ usleep_range(5000, 10000);
+ return 0;
+ }
+
if (cdns_phy->nsubnodes == 1) {
/* Take the PHY lane group out of reset */
reset_control_deassert(inst->lnk_rst);
@@ -2308,6 +2317,9 @@ static int cdns_torrent_phy_init(struct phy *phy)
u32 num_regs;
int i, j;
+ if (cdns_phy->already_configured)
+ return 0;
+
if (cdns_phy->nsubnodes > 1) {
if (phy_type == TYPE_DP)
return cdns_torrent_dp_multilink_init(cdns_phy, inst, phy);
@@ -2445,19 +2457,6 @@ static const struct phy_ops cdns_torrent_phy_ops = {
.owner = THIS_MODULE,
};
-static int cdns_torrent_noop_phy_on(struct phy *phy)
-{
- /* Give 5ms to 10ms delay for the PIPE clock to be stable */
- usleep_range(5000, 10000);
-
- return 0;
-}
-
-static const struct phy_ops noop_ops = {
- .power_on = cdns_torrent_noop_phy_on,
- .owner = THIS_MODULE,
-};
-
static
int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
{
@@ -2937,10 +2936,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
of_property_read_u32(child, "cdns,ssc-mode",
&cdns_phy->phys[node].ssc_mode);
- if (!cdns_phy->already_configured)
- gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
- else
- gphy = devm_phy_create(dev, child, &noop_ops);
+ gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
if (IS_ERR(gphy)) {
ret = PTR_ERR(gphy);
goto put_child;
--
2.39.2
Add suspend and resume support.
The already_configured flag is cleared during the suspend stage to force
the PHY initialization during the resume stage.
Co-developed-by: Théo Lebrun <[email protected]>
Signed-off-by: Théo Lebrun <[email protected]>
Signed-off-by: Thomas Richard <[email protected]>
---
drivers/phy/cadence/phy-cadence-torrent.c | 57 +++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 0e3c755e6089..7e488788a367 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -3075,6 +3075,62 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev)
cdns_torrent_clk_cleanup(cdns_phy);
}
+static int cdns_torrent_phy_suspend_noirq(struct device *dev)
+{
+ struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev);
+ int i;
+
+ reset_control_assert(cdns_phy->phy_rst);
+ reset_control_assert(cdns_phy->apb_rst);
+ for (i = 0; i < cdns_phy->nsubnodes; i++)
+ reset_control_assert(cdns_phy->phys[i].lnk_rst);
+
+ if (cdns_phy->already_configured)
+ cdns_phy->already_configured = 0;
+ else {
+ clk_disable_unprepare(cdns_phy->clk1);
+ clk_disable_unprepare(cdns_phy->clk);
+ }
+
+ return 0;
+}
+
+static int cdns_torrent_phy_resume_noirq(struct device *dev)
+{
+ struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev);
+ int node = cdns_phy->nsubnodes;
+ int ret, i;
+
+ ret = cdns_torrent_clk(cdns_phy);
+ if (ret)
+ return ret;
+
+ /* Enable APB */
+ reset_control_deassert(cdns_phy->apb_rst);
+
+ if (cdns_phy->nsubnodes > 1) {
+ ret = cdns_torrent_phy_configure_multilink(cdns_phy);
+ if (ret)
+ goto put_lnk_rst;
+ }
+
+ return 0;
+
+put_lnk_rst:
+ for (i = 0; i < node; i++)
+ reset_control_assert(cdns_phy->phys[i].lnk_rst);
+ reset_control_assert(cdns_phy->apb_rst);
+
+ clk_disable_unprepare(cdns_phy->clk1);
+ clk_disable_unprepare(cdns_phy->clk);
+
+ return ret;
+}
+
+static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops,
+ cdns_torrent_phy_suspend_noirq,
+ cdns_torrent_phy_resume_noirq);
+
/* USB and DP link configuration */
static struct cdns_reg_pairs usb_dp_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG},
@@ -5276,6 +5332,7 @@ static struct platform_driver cdns_torrent_phy_driver = {
.driver = {
.name = "cdns-torrent-phy",
.of_match_table = cdns_torrent_phy_of_match,
+ .pm = pm_sleep_ptr(&cdns_torrent_phy_pm_ops),
}
};
module_platform_driver(cdns_torrent_phy_driver);
--
2.39.2
On 4/16/24 14:52, Thomas Richard wrote:
> The patches of this series were originally in the series "Add suspend to
> ram support for PCIe on J7200" [1].
> They were moved in a separate series as requested by the PHY maintainer.
> This series adds suspend and resume support for the phy-cadence-torrent and
> phy-j721e-wiz drivers.
>
> Compared to the PCIe series v4 [1], these PHY patches were rebased on Linux
> v6.9-rc1.
> The only change is for the patch "phy: cadence-torrent: extract calls to
> clk_get from cdns_torrent_clk". Now the cadence-torrent driver supports
> dual reference clock, so the patch was updated consequently.
>
> [1] https://lore.kernel.org/all/[email protected]/
Hello,
Gentle ping.
Do you have any comments for this series ?
Best Regards,
Thomas
--
Thomas Richard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On 4/16/24 14:52, Thomas Richard wrote:
> The patches of this series were originally in the series "Add suspend to
> ram support for PCIe on J7200" [1].
> They were moved in a separate series as requested by the PHY maintainer.
> This series adds suspend and resume support for the phy-cadence-torrent and
> phy-j721e-wiz drivers.
>
> Compared to the PCIe series v4 [1], these PHY patches were rebased on Linux
> v6.9-rc1.
> The only change is for the patch "phy: cadence-torrent: extract calls to
> clk_get from cdns_torrent_clk". Now the cadence-torrent driver supports
> dual reference clock, so the patch was updated consequently.
>
> [1] https://lore.kernel.org/all/[email protected]/
Hello,
Gentle ping.
No merge conflict with 6.10-rc1.
Best Regards,
Thomas
--
Thomas Richard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Tue, 16 Apr 2024 14:52:29 +0200, Thomas Richard wrote:
> The patches of this series were originally in the series "Add suspend to
> ram support for PCIe on J7200" [1].
> They were moved in a separate series as requested by the PHY maintainer.
> This series adds suspend and resume support for the phy-cadence-torrent and
> phy-j721e-wiz drivers.
>
> Compared to the PCIe series v4 [1], these PHY patches were rebased on Linux
> v6.9-rc1.
> The only change is for the patch "phy: cadence-torrent: extract calls to
> clk_get from cdns_torrent_clk". Now the cadence-torrent driver supports
> dual reference clock, so the patch was updated consequently.
>
> [...]
Applied, thanks!
[1/8] phy: ti: phy-j721e-wiz: use dev_err_probe() instead of dev_err()
commit: 5aa4733b1b9324e224ebe59e3672887a57d51083
[2/8] phy: ti: phy-j721e-wiz: split wiz_clock_init() function
commit: 3c4e13cf9ead79fac3b217e228c1c7d3db3e132f
[3/8] phy: ti: phy-j721e-wiz: add resume support
commit: b5539abdd013fd3f77633413848c93f8ec84b51d
[4/8] phy: cadence-torrent: extract calls to clk_get from cdns_torrent_clk
commit: c2286092424bf5f889f302669580fd6862967a49
[5/8] phy: cadence-torrent: register resets even if the phy is already configured
commit: 8512b6873461c4d31f89c3260a2d5043b3f9dbb2
[6/8] phy: cadence-torrent: add already_configured to struct cdns_torrent_phy
commit: d4f24d14f311b9a1af57c9726d5a3acbfa8282db
[7/8] phy: cadence-torrent: remove noop_ops phy operations
commit: 81472a55edce473cfc22b340c1026c6d5219ccfe
[8/8] phy: cadence-torrent: add suspend and resume support
commit: 0da27ed080b2c25680fb42105f3d85c0ebe38b0c
Best regards,
--
Vinod Koul <[email protected]>