summaryrefslogtreecommitdiff
path: root/drivers/phy/ti/phy-j721e-wiz.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy/ti/phy-j721e-wiz.c')
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c235
1 files changed, 155 insertions, 80 deletions
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index ddce5ef7711c..a8b440c6c46b 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -58,6 +58,14 @@ enum wiz_lane_standard_mode {
LANE_MODE_GEN4,
};
+/*
+ * List of master lanes used for lane swapping
+ */
+enum wiz_typec_master_lane {
+ LANE0 = 0,
+ LANE2 = 2,
+};
+
enum wiz_refclk_mux_sel {
PLL0_REFCLK,
PLL1_REFCLK,
@@ -194,6 +202,9 @@ static const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = {
static const struct reg_field typec_ln10_swap =
REG_FIELD(WIZ_SERDES_TYPEC, 30, 30);
+static const struct reg_field typec_ln23_swap =
+ REG_FIELD(WIZ_SERDES_TYPEC, 31, 31);
+
struct wiz_clk_mux {
struct clk_hw hw;
struct regmap_field *field;
@@ -367,6 +378,7 @@ struct wiz {
struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS];
struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G];
struct regmap_field *typec_ln10_swap;
+ struct regmap_field *typec_ln23_swap;
struct regmap_field *sup_legacy_clk_override;
struct device *dev;
@@ -376,6 +388,7 @@ struct wiz {
struct gpio_desc *gpio_typec_dir;
int typec_dir_delay;
u32 lane_phy_type[WIZ_MAX_LANES];
+ u32 master_lane_num[WIZ_MAX_LANES];
struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS];
struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS];
struct clk_onecell_data clk_data;
@@ -430,18 +443,17 @@ static int wiz_mode_select(struct wiz *wiz)
int i;
for (i = 0; i < num_lanes; i++) {
- if (wiz->lane_phy_type[i] == PHY_TYPE_DP)
+ if (wiz->lane_phy_type[i] == PHY_TYPE_DP) {
mode = LANE_MODE_GEN1;
- else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII)
+ } else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) {
mode = LANE_MODE_GEN2;
- else
- continue;
-
- if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) {
+ } else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) {
ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3);
ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3);
- ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3);
- mode = LANE_MODE_GEN1;
+ ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x2);
+ mode = LANE_MODE_GEN2;
+ } else {
+ continue;
}
ret = regmap_field_write(wiz->p_standard_mode[i], mode);
@@ -675,6 +687,13 @@ static int wiz_regfield_init(struct wiz *wiz)
return PTR_ERR(wiz->typec_ln10_swap);
}
+ wiz->typec_ln23_swap = devm_regmap_field_alloc(dev, regmap,
+ typec_ln23_swap);
+ if (IS_ERR(wiz->typec_ln23_swap)) {
+ dev_err(dev, "LN23_SWAP reg field init failed\n");
+ return PTR_ERR(wiz->typec_ln23_swap);
+ }
+
wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk);
if (IS_ERR(wiz->phy_en_refclk)) {
dev_err(dev, "PHY_EN_REFCLK reg field init failed\n");
@@ -782,6 +801,7 @@ static int wiz_clk_mux_set_parent(struct clk_hw *hw, u8 index)
}
static const struct clk_ops wiz_clk_mux_ops = {
+ .determine_rate = __clk_mux_determine_rate,
.set_parent = wiz_clk_mux_set_parent,
.get_parent = wiz_clk_mux_get_parent,
};
@@ -1056,27 +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)) {
- dev_err(dev, "core_ref_clk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
- 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);
@@ -1100,35 +1105,55 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
break;
}
- 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;
- }
- wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
-
- rate = clk_get_rate(clk);
- if (rate >= 100000000)
+ 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);
}
- 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;
- }
- wiz->input_clks[WIZ_EXT_REFCLK] = clk;
-
- rate = clk_get_rate(clk);
- if (rate >= 100000000)
+ 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))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "core_ref1_clk clock not found\n");
+
+ wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
+ }
+
+ clk = devm_clk_get(dev, "ext_ref_clk");
+ 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;
+
+ wiz_clock_init(wiz);
switch (wiz->type) {
case AM64_WIZ_10G:
@@ -1137,8 +1162,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;
}
@@ -1147,42 +1173,37 @@ 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);
+ of_node_put(clk_node);
if (ret) {
- dev_err(dev, "Failed to register %s clock\n",
- node_name);
- of_node_put(clk_node);
+ dev_err_probe(dev, ret, "Failed to register %s clock\n",
+ node_name);
goto err;
}
- of_node_put(clk_node);
}
for (i = 0; i < wiz->clk_div_sel_num; i++) {
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);
+ of_node_put(clk_node);
if (ret) {
- dev_err(dev, "Failed to register %s clock\n",
- node_name);
- of_node_put(clk_node);
+ dev_err_probe(dev, ret, "Failed to register %s clock\n",
+ node_name);
goto err;
}
-
- of_node_put(clk_node);
}
return 0;
@@ -1215,9 +1236,12 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE)
return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1);
break;
+
+ case J721E_WIZ_16G:
case J721E_WIZ_10G:
case J7200_WIZ_10G:
case J721S2_WIZ_10G:
+ case J784S4_WIZ_10G:
if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII)
return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2);
break;
@@ -1234,15 +1258,39 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
struct wiz *wiz = dev_get_drvdata(dev);
int ret;
- /* if typec-dir gpio was specified, set LN10 SWAP bit based on that */
- if (id == 0 && wiz->gpio_typec_dir) {
- if (wiz->typec_dir_delay)
- msleep_interruptible(wiz->typec_dir_delay);
-
- if (gpiod_get_value_cansleep(wiz->gpio_typec_dir))
- regmap_field_write(wiz->typec_ln10_swap, 1);
- else
- regmap_field_write(wiz->typec_ln10_swap, 0);
+ if (id == 0) {
+ /* if typec-dir gpio was specified, set LN10 SWAP bit based on that */
+ if (wiz->gpio_typec_dir) {
+ if (wiz->typec_dir_delay)
+ msleep_interruptible(wiz->typec_dir_delay);
+
+ if (gpiod_get_value_cansleep(wiz->gpio_typec_dir))
+ regmap_field_write(wiz->typec_ln10_swap, 1);
+ else
+ regmap_field_write(wiz->typec_ln10_swap, 0);
+ } else {
+ /* if no typec-dir gpio is specified and PHY type is USB3
+ * with master lane number is '0' or '2', then set LN10 or
+ * LN23 SWAP bit to '1' respectively.
+ */
+ u32 num_lanes = wiz->num_lanes;
+ int i;
+
+ for (i = 0; i < num_lanes; i++) {
+ if (wiz->lane_phy_type[i] == PHY_TYPE_USB3) {
+ switch (wiz->master_lane_num[i]) {
+ case LANE0:
+ regmap_field_write(wiz->typec_ln10_swap, 1);
+ break;
+ case LANE2:
+ regmap_field_write(wiz->typec_ln23_swap, 1);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
}
if (id == 0) {
@@ -1271,7 +1319,6 @@ static const struct regmap_config wiz_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
- .fast_io = true,
};
static struct wiz_data j721e_16g_data = {
@@ -1356,7 +1403,7 @@ MODULE_DEVICE_TABLE(of, wiz_id_table);
static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
{
- struct device_node *serdes, *subnode;
+ struct device_node *serdes;
serdes = of_get_child_by_name(dev->of_node, "serdes");
if (!serdes) {
@@ -1364,7 +1411,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
return -EINVAL;
}
- for_each_child_of_node(serdes, subnode) {
+ for_each_child_of_node_scoped(serdes, subnode) {
u32 reg, num_lanes = 1, phy_type = PHY_NONE;
int ret, i;
@@ -1374,7 +1421,6 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
ret = of_property_read_u32(subnode, "reg", &reg);
if (ret) {
- of_node_put(subnode);
dev_err(dev,
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
__func__, subnode->name, ret);
@@ -1386,8 +1432,10 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
dev_dbg(dev, "%s: Lanes %u-%u have phy-type %u\n", __func__,
reg, reg + num_lanes - 1, phy_type);
- for (i = reg; i < reg + num_lanes; i++)
+ for (i = reg; i < reg + num_lanes; i++) {
+ wiz->master_lane_num[i] = reg;
wiz->lane_phy_type[i] = phy_type;
+ }
}
return 0;
@@ -1525,8 +1573,8 @@ static int wiz_probe(struct platform_device *pdev)
phy_reset_dev = &wiz->wiz_phy_reset_dev;
phy_reset_dev->dev = dev;
- phy_reset_dev->ops = &wiz_phy_reset_ops,
- phy_reset_dev->owner = THIS_MODULE,
+ phy_reset_dev->ops = &wiz_phy_reset_ops;
+ phy_reset_dev->owner = THIS_MODULE;
phy_reset_dev->of_node = node;
/* Reset for each of the lane and one for the entire SERDES */
phy_reset_dev->nr_resets = num_lanes + 1;
@@ -1544,7 +1592,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;
@@ -1590,7 +1638,7 @@ err_addr_to_resource:
return ret;
}
-static int wiz_remove(struct platform_device *pdev)
+static void wiz_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
@@ -1604,16 +1652,43 @@ static int wiz_remove(struct platform_device *pdev)
wiz_clock_cleanup(wiz, node);
pm_runtime_put(dev);
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 = wiz_remove,
.driver = {
.name = "wiz",
.of_match_table = wiz_id_table,
+ .pm = pm_sleep_ptr(&wiz_pm_ops),
},
};
module_platform_driver(wiz_driver);