diff options
Diffstat (limited to 'drivers/phy/ti/phy-j721e-wiz.c')
| -rw-r--r-- | drivers/phy/ti/phy-j721e-wiz.c | 235 |
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", ®); 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); |
