|
@@ -48,26 +48,18 @@
|
|
|
#define MUX_CLK_NUM_PARENTS 2
|
|
|
|
|
|
struct meson8b_dwmac {
|
|
|
- struct platform_device *pdev;
|
|
|
-
|
|
|
+ struct device *dev;
|
|
|
void __iomem *regs;
|
|
|
-
|
|
|
phy_interface_t phy_mode;
|
|
|
+ struct clk *rgmii_tx_clk;
|
|
|
+ u32 tx_delay_ns;
|
|
|
+};
|
|
|
|
|
|
+struct meson8b_dwmac_clk_configs {
|
|
|
struct clk_mux m250_mux;
|
|
|
- struct clk *m250_mux_clk;
|
|
|
- struct clk *m250_mux_parent[MUX_CLK_NUM_PARENTS];
|
|
|
-
|
|
|
struct clk_divider m250_div;
|
|
|
- struct clk *m250_div_clk;
|
|
|
-
|
|
|
struct clk_fixed_factor fixed_div2;
|
|
|
- struct clk *fixed_div2_clk;
|
|
|
-
|
|
|
struct clk_gate rgmii_tx_en;
|
|
|
- struct clk *rgmii_tx_en_clk;
|
|
|
-
|
|
|
- u32 tx_delay_ns;
|
|
|
};
|
|
|
|
|
|
static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
|
|
@@ -82,106 +74,99 @@ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
|
|
|
writel(data, dwmac->regs + reg);
|
|
|
}
|
|
|
|
|
|
-static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
|
|
|
+static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac,
|
|
|
+ const char *name_suffix,
|
|
|
+ const char **parent_names,
|
|
|
+ int num_parents,
|
|
|
+ const struct clk_ops *ops,
|
|
|
+ struct clk_hw *hw)
|
|
|
{
|
|
|
struct clk_init_data init;
|
|
|
- int i, ret;
|
|
|
- struct device *dev = &dwmac->pdev->dev;
|
|
|
char clk_name[32];
|
|
|
- const char *clk_div_parents[1];
|
|
|
- const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
|
|
|
+
|
|
|
+ snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev),
|
|
|
+ name_suffix);
|
|
|
+
|
|
|
+ init.name = clk_name;
|
|
|
+ init.ops = ops;
|
|
|
+ init.flags = CLK_SET_RATE_PARENT;
|
|
|
+ init.parent_names = parent_names;
|
|
|
+ init.num_parents = num_parents;
|
|
|
+
|
|
|
+ hw->init = &init;
|
|
|
+
|
|
|
+ return devm_clk_register(dwmac->dev, hw);
|
|
|
+}
|
|
|
+
|
|
|
+static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
|
|
|
+{
|
|
|
+ int i, ret;
|
|
|
+ struct clk *clk;
|
|
|
+ struct device *dev = dwmac->dev;
|
|
|
+ const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
|
|
|
+ struct meson8b_dwmac_clk_configs *clk_configs;
|
|
|
+
|
|
|
+ clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
|
|
|
+ if (!clk_configs)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
/* get the mux parents from DT */
|
|
|
for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
|
|
|
char name[16];
|
|
|
|
|
|
snprintf(name, sizeof(name), "clkin%d", i);
|
|
|
- dwmac->m250_mux_parent[i] = devm_clk_get(dev, name);
|
|
|
- if (IS_ERR(dwmac->m250_mux_parent[i])) {
|
|
|
- ret = PTR_ERR(dwmac->m250_mux_parent[i]);
|
|
|
+ clk = devm_clk_get(dev, name);
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
+ ret = PTR_ERR(clk);
|
|
|
if (ret != -EPROBE_DEFER)
|
|
|
dev_err(dev, "Missing clock %s\n", name);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- mux_parent_names[i] =
|
|
|
- __clk_get_name(dwmac->m250_mux_parent[i]);
|
|
|
+ mux_parent_names[i] = __clk_get_name(clk);
|
|
|
}
|
|
|
|
|
|
- /* create the m250_mux */
|
|
|
- snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev));
|
|
|
- init.name = clk_name;
|
|
|
- init.ops = &clk_mux_ops;
|
|
|
- init.flags = CLK_SET_RATE_PARENT;
|
|
|
- init.parent_names = mux_parent_names;
|
|
|
- init.num_parents = MUX_CLK_NUM_PARENTS;
|
|
|
-
|
|
|
- dwmac->m250_mux.reg = dwmac->regs + PRG_ETH0;
|
|
|
- dwmac->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
|
|
|
- dwmac->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
|
|
|
- dwmac->m250_mux.flags = 0;
|
|
|
- dwmac->m250_mux.table = NULL;
|
|
|
- dwmac->m250_mux.hw.init = &init;
|
|
|
-
|
|
|
- dwmac->m250_mux_clk = devm_clk_register(dev, &dwmac->m250_mux.hw);
|
|
|
- if (WARN_ON(IS_ERR(dwmac->m250_mux_clk)))
|
|
|
- return PTR_ERR(dwmac->m250_mux_clk);
|
|
|
-
|
|
|
- /* create the m250_div */
|
|
|
- snprintf(clk_name, sizeof(clk_name), "%s#m250_div", dev_name(dev));
|
|
|
- init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
|
|
- init.ops = &clk_divider_ops;
|
|
|
- init.flags = CLK_SET_RATE_PARENT;
|
|
|
- clk_div_parents[0] = __clk_get_name(dwmac->m250_mux_clk);
|
|
|
- init.parent_names = clk_div_parents;
|
|
|
- init.num_parents = ARRAY_SIZE(clk_div_parents);
|
|
|
-
|
|
|
- dwmac->m250_div.reg = dwmac->regs + PRG_ETH0;
|
|
|
- dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
|
|
|
- dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
|
|
|
- dwmac->m250_div.hw.init = &init;
|
|
|
- dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED |
|
|
|
+ clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
|
|
|
+ clk_configs->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
|
|
|
+ clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
|
|
|
+ clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names,
|
|
|
+ MUX_CLK_NUM_PARENTS, &clk_mux_ops,
|
|
|
+ &clk_configs->m250_mux.hw);
|
|
|
+ if (WARN_ON(IS_ERR(clk)))
|
|
|
+ return PTR_ERR(clk);
|
|
|
+
|
|
|
+ parent_name = __clk_get_name(clk);
|
|
|
+ clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
|
|
|
+ clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
|
|
|
+ clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
|
|
|
+ clk_configs->m250_div.flags = CLK_DIVIDER_ONE_BASED |
|
|
|
CLK_DIVIDER_ALLOW_ZERO |
|
|
|
CLK_DIVIDER_ROUND_CLOSEST;
|
|
|
-
|
|
|
- dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw);
|
|
|
- if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
|
|
|
- return PTR_ERR(dwmac->m250_div_clk);
|
|
|
-
|
|
|
- /* create the fixed_div2 */
|
|
|
- snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
|
|
|
- init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
|
|
- init.ops = &clk_fixed_factor_ops;
|
|
|
- init.flags = CLK_SET_RATE_PARENT;
|
|
|
- clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
|
|
|
- init.parent_names = clk_div_parents;
|
|
|
- init.num_parents = ARRAY_SIZE(clk_div_parents);
|
|
|
-
|
|
|
- dwmac->fixed_div2.mult = 1;
|
|
|
- dwmac->fixed_div2.div = 2;
|
|
|
- dwmac->fixed_div2.hw.init = &init;
|
|
|
-
|
|
|
- dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
|
|
|
- if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
|
|
|
- return PTR_ERR(dwmac->fixed_div2_clk);
|
|
|
-
|
|
|
- /* create the rgmii_tx_en */
|
|
|
- init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#rgmii_tx_en",
|
|
|
- dev_name(dev));
|
|
|
- init.ops = &clk_gate_ops;
|
|
|
- init.flags = CLK_SET_RATE_PARENT;
|
|
|
- clk_div_parents[0] = __clk_get_name(dwmac->fixed_div2_clk);
|
|
|
- init.parent_names = clk_div_parents;
|
|
|
- init.num_parents = ARRAY_SIZE(clk_div_parents);
|
|
|
-
|
|
|
- dwmac->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
|
|
|
- dwmac->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
|
|
|
- dwmac->rgmii_tx_en.hw.init = &init;
|
|
|
-
|
|
|
- dwmac->rgmii_tx_en_clk = devm_clk_register(dev,
|
|
|
- &dwmac->rgmii_tx_en.hw);
|
|
|
- if (WARN_ON(IS_ERR(dwmac->rgmii_tx_en_clk)))
|
|
|
- return PTR_ERR(dwmac->rgmii_tx_en_clk);
|
|
|
+ clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
|
|
|
+ &clk_divider_ops,
|
|
|
+ &clk_configs->m250_div.hw);
|
|
|
+ if (WARN_ON(IS_ERR(clk)))
|
|
|
+ return PTR_ERR(clk);
|
|
|
+
|
|
|
+ parent_name = __clk_get_name(clk);
|
|
|
+ clk_configs->fixed_div2.mult = 1;
|
|
|
+ clk_configs->fixed_div2.div = 2;
|
|
|
+ clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_name, 1,
|
|
|
+ &clk_fixed_factor_ops,
|
|
|
+ &clk_configs->fixed_div2.hw);
|
|
|
+ if (WARN_ON(IS_ERR(clk)))
|
|
|
+ return PTR_ERR(clk);
|
|
|
+
|
|
|
+ parent_name = __clk_get_name(clk);
|
|
|
+ clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
|
|
|
+ clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
|
|
|
+ clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_name, 1,
|
|
|
+ &clk_gate_ops,
|
|
|
+ &clk_configs->rgmii_tx_en.hw);
|
|
|
+ if (WARN_ON(IS_ERR(clk)))
|
|
|
+ return PTR_ERR(clk);
|
|
|
+
|
|
|
+ dwmac->rgmii_tx_clk = clk;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -219,19 +204,23 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
|
|
* a register) based on the line-speed (125MHz for Gbit speeds,
|
|
|
* 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
|
|
|
*/
|
|
|
- ret = clk_set_rate(dwmac->rgmii_tx_en_clk, 125 * 1000 * 1000);
|
|
|
+ ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000);
|
|
|
if (ret) {
|
|
|
- dev_err(&dwmac->pdev->dev,
|
|
|
+ dev_err(dwmac->dev,
|
|
|
"failed to set RGMII TX clock\n");
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- ret = clk_prepare_enable(dwmac->rgmii_tx_en_clk);
|
|
|
+ ret = clk_prepare_enable(dwmac->rgmii_tx_clk);
|
|
|
if (ret) {
|
|
|
- dev_err(&dwmac->pdev->dev,
|
|
|
+ dev_err(dwmac->dev,
|
|
|
"failed to enable the RGMII TX clock\n");
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+ devm_add_action_or_reset(dwmac->dev,
|
|
|
+ (void(*)(void *))clk_disable_unprepare,
|
|
|
+ dwmac->rgmii_tx_clk);
|
|
|
break;
|
|
|
|
|
|
case PHY_INTERFACE_MODE_RMII:
|
|
@@ -251,7 +240,7 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- dev_err(&dwmac->pdev->dev, "unsupported phy-mode %s\n",
|
|
|
+ dev_err(dwmac->dev, "unsupported phy-mode %s\n",
|
|
|
phy_modes(dwmac->phy_mode));
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -292,7 +281,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
|
|
goto err_remove_config_dt;
|
|
|
}
|
|
|
|
|
|
- dwmac->pdev = pdev;
|
|
|
+ dwmac->dev = &pdev->dev;
|
|
|
dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
|
|
|
if (dwmac->phy_mode < 0) {
|
|
|
dev_err(&pdev->dev, "missing phy-mode property\n");
|
|
@@ -317,29 +306,16 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
|
|
|
|
|
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
|
|
if (ret)
|
|
|
- goto err_clk_disable;
|
|
|
+ goto err_remove_config_dt;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
-err_clk_disable:
|
|
|
- if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
|
|
- clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
|
|
|
err_remove_config_dt:
|
|
|
stmmac_remove_config_dt(pdev, plat_dat);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int meson8b_dwmac_remove(struct platform_device *pdev)
|
|
|
-{
|
|
|
- struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
|
|
|
-
|
|
|
- if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
|
|
- clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
|
|
|
-
|
|
|
- return stmmac_pltfr_remove(pdev);
|
|
|
-}
|
|
|
-
|
|
|
static const struct of_device_id meson8b_dwmac_match[] = {
|
|
|
{ .compatible = "amlogic,meson8b-dwmac" },
|
|
|
{ .compatible = "amlogic,meson-gxbb-dwmac" },
|
|
@@ -349,7 +325,7 @@ MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
|
|
|
|
|
|
static struct platform_driver meson8b_dwmac_driver = {
|
|
|
.probe = meson8b_dwmac_probe,
|
|
|
- .remove = meson8b_dwmac_remove,
|
|
|
+ .remove = stmmac_pltfr_remove,
|
|
|
.driver = {
|
|
|
.name = "meson8b-dwmac",
|
|
|
.pm = &stmmac_pltfr_pm_ops,
|