phy: ti: phy-j721e-wiz: add support for j7200-wiz-10g
authorRoger Quadros <rogerq@kernel.org>
Tue, 28 Jun 2022 12:22:54 +0000 (15:22 +0300)
committerVinod Koul <vkoul@kernel.org>
Tue, 30 Aug 2022 05:12:58 +0000 (10:42 +0530)
j7200-wiz-10g supports 2 reference clocks. However, the
control bits for these clocks is in a separate register that
sits in the System Control register space. Handle that register.

Signed-off-by: Roger Quadros <rogerq@kernel.org>
Link: https://lore.kernel.org/r/20220628122255.24265-7-rogerq@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/ti/phy-j721e-wiz.c

index 77accea..cc2ab51 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mux/consumer.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/regmap.h>
 #include <linux/reset-controller.h>
 
+/* SCM offsets */
+#define SERDES_SUP_CTRL                0x4400
+
+/* SERDES offsets */
 #define WIZ_SERDES_CTRL                0x404
 #define WIZ_SERDES_TOP_CTRL    0x408
 #define WIZ_SERDES_RST         0x40c
@@ -85,6 +90,18 @@ static const struct reg_field pma_cmn_refclk_dig_div =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27);
 static const struct reg_field pma_cmn_refclk1_dig_div =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25);
+
+static const struct reg_field sup_pll0_refclk_mux_sel =
+                                       REG_FIELD(SERDES_SUP_CTRL, 0, 1);
+static const struct reg_field sup_pll1_refclk_mux_sel =
+                                       REG_FIELD(SERDES_SUP_CTRL, 2, 3);
+static const struct reg_field sup_pma_cmn_refclk1_int_mode =
+                                       REG_FIELD(SERDES_SUP_CTRL, 4, 5);
+static const struct reg_field sup_refclk_dig_sel_10g =
+                                       REG_FIELD(SERDES_SUP_CTRL, 6, 7);
+static const struct reg_field sup_legacy_clk_override =
+                                       REG_FIELD(SERDES_SUP_CTRL, 8, 8);
+
 static const char * const output_clk_names[] = {
        [TI_WIZ_PLL0_REFCLK] = "pll0-refclk",
        [TI_WIZ_PLL1_REFCLK] = "pll1-refclk",
@@ -248,6 +265,27 @@ static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = {
        },
 };
 
+static const struct wiz_clk_mux_sel clk_mux_sel_10g_2_refclk[] = {
+       {
+               .num_parents = 3,
+               .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK },
+               .table = { 2, 3, 0 },
+               .node_name = "pll0-refclk",
+       },
+       {
+               .num_parents = 3,
+               .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK },
+               .table = { 2, 3, 0 },
+               .node_name = "pll1-refclk",
+       },
+       {
+               .num_parents = 3,
+               .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK },
+               .table = { 2, 3, 0 },
+               .node_name = "refclk-dig",
+       },
+};
+
 static const struct clk_div_table clk_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
@@ -269,14 +307,18 @@ static const struct wiz_clk_div_sel clk_div_sel[] = {
 
 enum wiz_type {
        J721E_WIZ_16G,
-       J721E_WIZ_10G,
+       J721E_WIZ_10G,  /* Also for J7200 SR1.0 */
        AM64_WIZ_10G,
+       J7200_WIZ_10G,  /* J7200 SR2.0 */
 };
 
 struct wiz_data {
        enum wiz_type type;
+       const struct reg_field *pll0_refclk_mux_sel;
+       const struct reg_field *pll1_refclk_mux_sel;
        const struct reg_field *refclk_dig_sel;
        const struct reg_field *pma_cmn_refclk1_dig_div;
+       const struct reg_field *pma_cmn_refclk1_int_mode;
        const struct wiz_clk_mux_sel *clk_mux_sel;
        unsigned int clk_div_sel_num;
 };
@@ -286,6 +328,7 @@ struct wiz_data {
 
 struct wiz {
        struct regmap           *regmap;
+       struct regmap           *scm_regmap;
        enum wiz_type           type;
        const struct wiz_clk_mux_sel *clk_mux_sel;
        const struct wiz_clk_div_sel *clk_div_sel;
@@ -304,12 +347,14 @@ struct wiz {
        struct regmap_field     *p0_rxfclk_sel[WIZ_MAX_LANES];
        struct regmap_field     *p0_refclk_sel[WIZ_MAX_LANES];
        struct regmap_field     *pma_cmn_refclk_int_mode;
+       struct regmap_field     *pma_cmn_refclk1_int_mode;
        struct regmap_field     *pma_cmn_refclk_mode;
        struct regmap_field     *pma_cmn_refclk_dig_div;
        struct regmap_field     *pma_cmn_refclk1_dig_div;
        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     *sup_legacy_clk_override;
 
        struct device           *dev;
        u32                     num_lanes;
@@ -448,6 +493,7 @@ static int wiz_init(struct wiz *wiz)
 static int wiz_regfield_init(struct wiz *wiz)
 {
        struct regmap *regmap = wiz->regmap;
+       struct regmap *scm_regmap = wiz->regmap; /* updated later to scm_regmap if applicable */
        int num_lanes = wiz->num_lanes;
        struct device *dev = wiz->dev;
        const struct wiz_data *data = wiz->data;
@@ -497,27 +543,46 @@ static int wiz_regfield_init(struct wiz *wiz)
                }
        }
 
+       if (wiz->scm_regmap) {
+               scm_regmap = wiz->scm_regmap;
+               wiz->sup_legacy_clk_override =
+                       devm_regmap_field_alloc(dev, scm_regmap, sup_legacy_clk_override);
+               if (IS_ERR(wiz->sup_legacy_clk_override)) {
+                       dev_err(dev, "SUP_LEGACY_CLK_OVERRIDE reg field init failed\n");
+                       return PTR_ERR(wiz->sup_legacy_clk_override);
+               }
+       }
+
        wiz->mux_sel_field[PLL0_REFCLK] =
-               devm_regmap_field_alloc(dev, regmap, pll0_refclk_mux_sel);
+               devm_regmap_field_alloc(dev, scm_regmap, *data->pll0_refclk_mux_sel);
        if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) {
                dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n");
                return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]);
        }
 
        wiz->mux_sel_field[PLL1_REFCLK] =
-               devm_regmap_field_alloc(dev, regmap, pll1_refclk_mux_sel);
+               devm_regmap_field_alloc(dev, scm_regmap, *data->pll1_refclk_mux_sel);
        if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) {
                dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n");
                return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]);
        }
 
-       wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap,
+       wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, scm_regmap,
                                                                 *data->refclk_dig_sel);
        if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) {
                dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n");
                return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]);
        }
 
+       if (data->pma_cmn_refclk1_int_mode) {
+               wiz->pma_cmn_refclk1_int_mode =
+                       devm_regmap_field_alloc(dev, scm_regmap, *data->pma_cmn_refclk1_int_mode);
+               if (IS_ERR(wiz->pma_cmn_refclk1_int_mode)) {
+                       dev_err(dev, "PMA_CMN_REFCLK1_INT_MODE reg field init failed\n");
+                       return PTR_ERR(wiz->pma_cmn_refclk1_int_mode);
+               }
+       }
+
        for (i = 0; i < num_lanes; i++) {
                wiz->p_enable[i] = devm_regmap_field_alloc(dev, regmap,
                                                           p_enable[i]);
@@ -906,9 +971,13 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node)
        struct device_node *clk_node;
        int i;
 
-       if (wiz->type == AM64_WIZ_10G) {
+       switch (wiz->type) {
+       case AM64_WIZ_10G:
+       case J7200_WIZ_10G:
                of_clk_del_provider(dev->of_node);
                return;
+       default:
+               break;
        }
 
        for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
@@ -935,9 +1004,6 @@ static int wiz_clock_register(struct wiz *wiz)
        int ret;
        int i;
 
-       if (wiz->type != AM64_WIZ_10G)
-               return 0;
-
        clk_index = TI_WIZ_PLL0_REFCLK;
        for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) {
                ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index);
@@ -987,6 +1053,22 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
        else
                regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3);
 
+       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)
+                       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");
@@ -1001,11 +1083,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
        else
                regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
 
-       if (wiz->type == AM64_WIZ_10G) {
+       switch (wiz->type) {
+       case AM64_WIZ_10G:
+       case J7200_WIZ_10G:
                ret = wiz_clock_register(wiz);
                if (ret)
                        dev_err(dev, "Failed to register wiz clocks\n");
                return ret;
+       default:
+               break;
        }
 
        for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
@@ -1081,6 +1167,7 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
                        return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1);
                break;
        case J721E_WIZ_10G:
+       case J7200_WIZ_10G:
                if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII)
                        return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2);
                break;
@@ -1139,6 +1226,8 @@ static const struct regmap_config wiz_regmap_config = {
 
 static struct wiz_data j721e_16g_data = {
        .type = J721E_WIZ_16G,
+       .pll0_refclk_mux_sel = &pll0_refclk_mux_sel,
+       .pll1_refclk_mux_sel = &pll1_refclk_mux_sel,
        .refclk_dig_sel = &refclk_dig_sel_16g,
        .pma_cmn_refclk1_dig_div = &pma_cmn_refclk1_dig_div,
        .clk_mux_sel = clk_mux_sel_16g,
@@ -1147,6 +1236,8 @@ static struct wiz_data j721e_16g_data = {
 
 static struct wiz_data j721e_10g_data = {
        .type = J721E_WIZ_10G,
+       .pll0_refclk_mux_sel = &pll0_refclk_mux_sel,
+       .pll1_refclk_mux_sel = &pll1_refclk_mux_sel,
        .refclk_dig_sel = &refclk_dig_sel_10g,
        .clk_mux_sel = clk_mux_sel_10g,
        .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
@@ -1154,11 +1245,23 @@ static struct wiz_data j721e_10g_data = {
 
 static struct wiz_data am64_10g_data = {
        .type = AM64_WIZ_10G,
+       .pll0_refclk_mux_sel = &pll0_refclk_mux_sel,
+       .pll1_refclk_mux_sel = &pll1_refclk_mux_sel,
        .refclk_dig_sel = &refclk_dig_sel_10g,
        .clk_mux_sel = clk_mux_sel_10g,
        .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
 };
 
+static struct wiz_data j7200_pg2_10g_data = {
+       .type = J7200_WIZ_10G,
+       .pll0_refclk_mux_sel = &sup_pll0_refclk_mux_sel,
+       .pll1_refclk_mux_sel = &sup_pll1_refclk_mux_sel,
+       .refclk_dig_sel = &sup_refclk_dig_sel_10g,
+       .pma_cmn_refclk1_int_mode = &sup_pma_cmn_refclk1_int_mode,
+       .clk_mux_sel = clk_mux_sel_10g_2_refclk,
+       .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
+};
+
 static const struct of_device_id wiz_id_table[] = {
        {
                .compatible = "ti,j721e-wiz-16g", .data = &j721e_16g_data,
@@ -1169,6 +1272,9 @@ static const struct of_device_id wiz_id_table[] = {
        {
                .compatible = "ti,am64-wiz-10g", .data = &am64_10g_data,
        },
+       {
+               .compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, wiz_id_table);
@@ -1266,6 +1372,16 @@ static int wiz_probe(struct platform_device *pdev)
                goto err_addr_to_resource;
        }
 
+       wiz->scm_regmap = syscon_regmap_lookup_by_phandle(node, "ti,scm");
+       if (IS_ERR(wiz->scm_regmap)) {
+               if (wiz->type == J7200_WIZ_10G) {
+                       dev_err(dev, "Couldn't get ti,scm regmap\n");
+                       return -ENODEV;
+               }
+
+               wiz->scm_regmap = NULL;
+       }
+
        ret = of_property_read_u32(node, "num-lanes", &num_lanes);
        if (ret) {
                dev_err(dev, "Failed to read num-lanes property\n");
@@ -1327,6 +1443,10 @@ static int wiz_probe(struct platform_device *pdev)
                goto err_addr_to_resource;
        }
 
+       /* Enable supplemental Control override if available */
+       if (wiz->scm_regmap)
+               regmap_field_write(wiz->sup_legacy_clk_override, 1);
+
        phy_reset_dev = &wiz->wiz_phy_reset_dev;
        phy_reset_dev->dev = dev;
        phy_reset_dev->ops = &wiz_phy_reset_ops,