0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/bitfield.h>
0009 #include <linux/clk.h>
0010 #include <linux/clk-provider.h>
0011 #include <linux/device.h>
0012 #include <linux/ethtool.h>
0013 #include <linux/io.h>
0014 #include <linux/ioport.h>
0015 #include <linux/module.h>
0016 #include <linux/of_device.h>
0017 #include <linux/of_net.h>
0018 #include <linux/mfd/syscon.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/stmmac.h>
0021
0022 #include "stmmac_platform.h"
0023
0024 #define PRG_ETH0 0x0
0025
0026 #define PRG_ETH0_RGMII_MODE BIT(0)
0027
0028 #define PRG_ETH0_EXT_PHY_MODE_MASK GENMASK(2, 0)
0029 #define PRG_ETH0_EXT_RGMII_MODE 1
0030 #define PRG_ETH0_EXT_RMII_MODE 4
0031
0032
0033 #define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4)
0034
0035
0036
0037
0038
0039 #define PRG_ETH0_TXDLY_MASK GENMASK(6, 5)
0040
0041
0042 #define PRG_ETH0_CLK_M250_DIV_SHIFT 7
0043 #define PRG_ETH0_CLK_M250_DIV_WIDTH 3
0044
0045 #define PRG_ETH0_RGMII_TX_CLK_EN 10
0046
0047 #define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
0048 #define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
0049
0050
0051
0052
0053
0054 #define PRG_ETH0_ADJ_ENABLE BIT(13)
0055
0056
0057
0058
0059 #define PRG_ETH0_ADJ_SETUP BIT(14)
0060
0061
0062
0063
0064 #define PRG_ETH0_ADJ_DELAY GENMASK(19, 15)
0065
0066
0067
0068
0069 #define PRG_ETH0_ADJ_SKEW GENMASK(24, 20)
0070
0071 #define PRG_ETH1 0x4
0072
0073
0074
0075
0076
0077
0078
0079 #define PRG_ETH1_CFG_RXCLK_DLY GENMASK(19, 16)
0080
0081 struct meson8b_dwmac;
0082
0083 struct meson8b_dwmac_data {
0084 int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
0085 bool has_prg_eth1_rgmii_rx_delay;
0086 };
0087
0088 struct meson8b_dwmac {
0089 struct device *dev;
0090 void __iomem *regs;
0091
0092 const struct meson8b_dwmac_data *data;
0093 phy_interface_t phy_mode;
0094 struct clk *rgmii_tx_clk;
0095 u32 tx_delay_ns;
0096 u32 rx_delay_ps;
0097 struct clk *timing_adj_clk;
0098 };
0099
0100 struct meson8b_dwmac_clk_configs {
0101 struct clk_mux m250_mux;
0102 struct clk_divider m250_div;
0103 struct clk_fixed_factor fixed_div2;
0104 struct clk_gate rgmii_tx_en;
0105 };
0106
0107 static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
0108 u32 mask, u32 value)
0109 {
0110 u32 data;
0111
0112 data = readl(dwmac->regs + reg);
0113 data &= ~mask;
0114 data |= (value & mask);
0115
0116 writel(data, dwmac->regs + reg);
0117 }
0118
0119 static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac,
0120 const char *name_suffix,
0121 const struct clk_parent_data *parents,
0122 int num_parents,
0123 const struct clk_ops *ops,
0124 struct clk_hw *hw)
0125 {
0126 struct clk_init_data init = { };
0127 char clk_name[32];
0128
0129 snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev),
0130 name_suffix);
0131
0132 init.name = clk_name;
0133 init.ops = ops;
0134 init.flags = CLK_SET_RATE_PARENT;
0135 init.parent_data = parents;
0136 init.num_parents = num_parents;
0137
0138 hw->init = &init;
0139
0140 return devm_clk_register(dwmac->dev, hw);
0141 }
0142
0143 static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
0144 {
0145 struct clk *clk;
0146 struct device *dev = dwmac->dev;
0147 static const struct clk_parent_data mux_parents[] = {
0148 { .fw_name = "clkin0", },
0149 { .index = -1, },
0150 };
0151 static const struct clk_div_table div_table[] = {
0152 { .div = 2, .val = 2, },
0153 { .div = 3, .val = 3, },
0154 { .div = 4, .val = 4, },
0155 { .div = 5, .val = 5, },
0156 { .div = 6, .val = 6, },
0157 { .div = 7, .val = 7, },
0158 { }
0159 };
0160 struct meson8b_dwmac_clk_configs *clk_configs;
0161 struct clk_parent_data parent_data = { };
0162
0163 clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
0164 if (!clk_configs)
0165 return -ENOMEM;
0166
0167 clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
0168 clk_configs->m250_mux.shift = __ffs(PRG_ETH0_CLK_M250_SEL_MASK);
0169 clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK >>
0170 clk_configs->m250_mux.shift;
0171 clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parents,
0172 ARRAY_SIZE(mux_parents), &clk_mux_ops,
0173 &clk_configs->m250_mux.hw);
0174 if (WARN_ON(IS_ERR(clk)))
0175 return PTR_ERR(clk);
0176
0177 parent_data.hw = &clk_configs->m250_mux.hw;
0178 clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
0179 clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
0180 clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
0181 clk_configs->m250_div.table = div_table;
0182 clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO |
0183 CLK_DIVIDER_ROUND_CLOSEST;
0184 clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_data, 1,
0185 &clk_divider_ops,
0186 &clk_configs->m250_div.hw);
0187 if (WARN_ON(IS_ERR(clk)))
0188 return PTR_ERR(clk);
0189
0190 parent_data.hw = &clk_configs->m250_div.hw;
0191 clk_configs->fixed_div2.mult = 1;
0192 clk_configs->fixed_div2.div = 2;
0193 clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_data, 1,
0194 &clk_fixed_factor_ops,
0195 &clk_configs->fixed_div2.hw);
0196 if (WARN_ON(IS_ERR(clk)))
0197 return PTR_ERR(clk);
0198
0199 parent_data.hw = &clk_configs->fixed_div2.hw;
0200 clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
0201 clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
0202 clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_data, 1,
0203 &clk_gate_ops,
0204 &clk_configs->rgmii_tx_en.hw);
0205 if (WARN_ON(IS_ERR(clk)))
0206 return PTR_ERR(clk);
0207
0208 dwmac->rgmii_tx_clk = clk;
0209
0210 return 0;
0211 }
0212
0213 static int meson8b_set_phy_mode(struct meson8b_dwmac *dwmac)
0214 {
0215 switch (dwmac->phy_mode) {
0216 case PHY_INTERFACE_MODE_RGMII:
0217 case PHY_INTERFACE_MODE_RGMII_RXID:
0218 case PHY_INTERFACE_MODE_RGMII_ID:
0219 case PHY_INTERFACE_MODE_RGMII_TXID:
0220
0221 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0222 PRG_ETH0_RGMII_MODE,
0223 PRG_ETH0_RGMII_MODE);
0224 break;
0225 case PHY_INTERFACE_MODE_RMII:
0226
0227 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0228 PRG_ETH0_RGMII_MODE, 0);
0229 break;
0230 default:
0231 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
0232 phy_modes(dwmac->phy_mode));
0233 return -EINVAL;
0234 }
0235
0236 return 0;
0237 }
0238
0239 static int meson_axg_set_phy_mode(struct meson8b_dwmac *dwmac)
0240 {
0241 switch (dwmac->phy_mode) {
0242 case PHY_INTERFACE_MODE_RGMII:
0243 case PHY_INTERFACE_MODE_RGMII_RXID:
0244 case PHY_INTERFACE_MODE_RGMII_ID:
0245 case PHY_INTERFACE_MODE_RGMII_TXID:
0246
0247 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0248 PRG_ETH0_EXT_PHY_MODE_MASK,
0249 PRG_ETH0_EXT_RGMII_MODE);
0250 break;
0251 case PHY_INTERFACE_MODE_RMII:
0252
0253 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0254 PRG_ETH0_EXT_PHY_MODE_MASK,
0255 PRG_ETH0_EXT_RMII_MODE);
0256 break;
0257 default:
0258 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
0259 phy_modes(dwmac->phy_mode));
0260 return -EINVAL;
0261 }
0262
0263 return 0;
0264 }
0265
0266 static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac,
0267 struct clk *clk)
0268 {
0269 int ret;
0270
0271 ret = clk_prepare_enable(clk);
0272 if (ret)
0273 return ret;
0274
0275 devm_add_action_or_reset(dwmac->dev,
0276 (void(*)(void *))clk_disable_unprepare,
0277 dwmac->rgmii_tx_clk);
0278
0279 return 0;
0280 }
0281
0282 static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
0283 {
0284 u32 tx_dly_config, rx_adj_config, cfg_rxclk_dly, delay_config;
0285 int ret;
0286
0287 rx_adj_config = 0;
0288 cfg_rxclk_dly = 0;
0289 tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
0290 dwmac->tx_delay_ns >> 1);
0291
0292 if (dwmac->data->has_prg_eth1_rgmii_rx_delay)
0293 cfg_rxclk_dly = FIELD_PREP(PRG_ETH1_CFG_RXCLK_DLY,
0294 dwmac->rx_delay_ps / 200);
0295 else if (dwmac->rx_delay_ps == 2000)
0296 rx_adj_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
0297
0298 switch (dwmac->phy_mode) {
0299 case PHY_INTERFACE_MODE_RGMII:
0300 delay_config = tx_dly_config | rx_adj_config;
0301 break;
0302 case PHY_INTERFACE_MODE_RGMII_RXID:
0303 delay_config = tx_dly_config;
0304 cfg_rxclk_dly = 0;
0305 break;
0306 case PHY_INTERFACE_MODE_RGMII_TXID:
0307 delay_config = rx_adj_config;
0308 break;
0309 case PHY_INTERFACE_MODE_RGMII_ID:
0310 case PHY_INTERFACE_MODE_RMII:
0311 delay_config = 0;
0312 cfg_rxclk_dly = 0;
0313 break;
0314 default:
0315 dev_err(dwmac->dev, "unsupported phy-mode %s\n",
0316 phy_modes(dwmac->phy_mode));
0317 return -EINVAL;
0318 }
0319
0320 if (delay_config & PRG_ETH0_ADJ_ENABLE) {
0321 if (!dwmac->timing_adj_clk) {
0322 dev_err(dwmac->dev,
0323 "The timing-adjustment clock is mandatory for the RX delay re-timing\n");
0324 return -EINVAL;
0325 }
0326
0327
0328 ret = meson8b_devm_clk_prepare_enable(dwmac,
0329 dwmac->timing_adj_clk);
0330 if (ret) {
0331 dev_err(dwmac->dev,
0332 "Failed to enable the timing-adjustment clock\n");
0333 return ret;
0334 }
0335 }
0336
0337 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK |
0338 PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP |
0339 PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW,
0340 delay_config);
0341
0342 meson8b_dwmac_mask_bits(dwmac, PRG_ETH1, PRG_ETH1_CFG_RXCLK_DLY,
0343 cfg_rxclk_dly);
0344
0345 return 0;
0346 }
0347
0348 static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
0349 {
0350 int ret;
0351
0352 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) {
0353
0354 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0355 PRG_ETH0_INVERTED_RMII_CLK, 0);
0356
0357
0358
0359
0360
0361
0362 ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000);
0363 if (ret) {
0364 dev_err(dwmac->dev,
0365 "failed to set RGMII TX clock\n");
0366 return ret;
0367 }
0368
0369 ret = meson8b_devm_clk_prepare_enable(dwmac,
0370 dwmac->rgmii_tx_clk);
0371 if (ret) {
0372 dev_err(dwmac->dev,
0373 "failed to enable the RGMII TX clock\n");
0374 return ret;
0375 }
0376 } else {
0377
0378 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0379 PRG_ETH0_INVERTED_RMII_CLK,
0380 PRG_ETH0_INVERTED_RMII_CLK);
0381 }
0382
0383
0384 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
0385 PRG_ETH0_TX_AND_PHY_REF_CLK);
0386
0387 return 0;
0388 }
0389
0390 static int meson8b_dwmac_probe(struct platform_device *pdev)
0391 {
0392 struct plat_stmmacenet_data *plat_dat;
0393 struct stmmac_resources stmmac_res;
0394 struct meson8b_dwmac *dwmac;
0395 int ret;
0396
0397 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
0398 if (ret)
0399 return ret;
0400
0401 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
0402 if (IS_ERR(plat_dat))
0403 return PTR_ERR(plat_dat);
0404
0405 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
0406 if (!dwmac) {
0407 ret = -ENOMEM;
0408 goto err_remove_config_dt;
0409 }
0410
0411 dwmac->data = (const struct meson8b_dwmac_data *)
0412 of_device_get_match_data(&pdev->dev);
0413 if (!dwmac->data) {
0414 ret = -EINVAL;
0415 goto err_remove_config_dt;
0416 }
0417 dwmac->regs = devm_platform_ioremap_resource(pdev, 1);
0418 if (IS_ERR(dwmac->regs)) {
0419 ret = PTR_ERR(dwmac->regs);
0420 goto err_remove_config_dt;
0421 }
0422
0423 dwmac->dev = &pdev->dev;
0424 ret = of_get_phy_mode(pdev->dev.of_node, &dwmac->phy_mode);
0425 if (ret) {
0426 dev_err(&pdev->dev, "missing phy-mode property\n");
0427 goto err_remove_config_dt;
0428 }
0429
0430
0431 if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns",
0432 &dwmac->tx_delay_ns))
0433 dwmac->tx_delay_ns = 2;
0434
0435
0436 if (of_property_read_u32(pdev->dev.of_node, "rx-internal-delay-ps",
0437 &dwmac->rx_delay_ps)) {
0438 if (!of_property_read_u32(pdev->dev.of_node,
0439 "amlogic,rx-delay-ns",
0440 &dwmac->rx_delay_ps))
0441
0442 dwmac->rx_delay_ps *= 1000;
0443 }
0444
0445 if (dwmac->data->has_prg_eth1_rgmii_rx_delay) {
0446 if (dwmac->rx_delay_ps > 3000 || dwmac->rx_delay_ps % 200) {
0447 dev_err(dwmac->dev,
0448 "The RGMII RX delay range is 0..3000ps in 200ps steps");
0449 ret = -EINVAL;
0450 goto err_remove_config_dt;
0451 }
0452 } else {
0453 if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
0454 dev_err(dwmac->dev,
0455 "The only allowed RGMII RX delays values are: 0ps, 2000ps");
0456 ret = -EINVAL;
0457 goto err_remove_config_dt;
0458 }
0459 }
0460
0461 dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev,
0462 "timing-adjustment");
0463 if (IS_ERR(dwmac->timing_adj_clk)) {
0464 ret = PTR_ERR(dwmac->timing_adj_clk);
0465 goto err_remove_config_dt;
0466 }
0467
0468 ret = meson8b_init_rgmii_delays(dwmac);
0469 if (ret)
0470 goto err_remove_config_dt;
0471
0472 ret = meson8b_init_rgmii_tx_clk(dwmac);
0473 if (ret)
0474 goto err_remove_config_dt;
0475
0476 ret = dwmac->data->set_phy_mode(dwmac);
0477 if (ret)
0478 goto err_remove_config_dt;
0479
0480 ret = meson8b_init_prg_eth(dwmac);
0481 if (ret)
0482 goto err_remove_config_dt;
0483
0484 plat_dat->bsp_priv = dwmac;
0485
0486 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
0487 if (ret)
0488 goto err_remove_config_dt;
0489
0490 return 0;
0491
0492 err_remove_config_dt:
0493 stmmac_remove_config_dt(pdev, plat_dat);
0494
0495 return ret;
0496 }
0497
0498 static const struct meson8b_dwmac_data meson8b_dwmac_data = {
0499 .set_phy_mode = meson8b_set_phy_mode,
0500 .has_prg_eth1_rgmii_rx_delay = false,
0501 };
0502
0503 static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
0504 .set_phy_mode = meson_axg_set_phy_mode,
0505 .has_prg_eth1_rgmii_rx_delay = false,
0506 };
0507
0508 static const struct meson8b_dwmac_data meson_g12a_dwmac_data = {
0509 .set_phy_mode = meson_axg_set_phy_mode,
0510 .has_prg_eth1_rgmii_rx_delay = true,
0511 };
0512
0513 static const struct of_device_id meson8b_dwmac_match[] = {
0514 {
0515 .compatible = "amlogic,meson8b-dwmac",
0516 .data = &meson8b_dwmac_data,
0517 },
0518 {
0519 .compatible = "amlogic,meson8m2-dwmac",
0520 .data = &meson8b_dwmac_data,
0521 },
0522 {
0523 .compatible = "amlogic,meson-gxbb-dwmac",
0524 .data = &meson8b_dwmac_data,
0525 },
0526 {
0527 .compatible = "amlogic,meson-axg-dwmac",
0528 .data = &meson_axg_dwmac_data,
0529 },
0530 {
0531 .compatible = "amlogic,meson-g12a-dwmac",
0532 .data = &meson_g12a_dwmac_data,
0533 },
0534 { }
0535 };
0536 MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
0537
0538 static struct platform_driver meson8b_dwmac_driver = {
0539 .probe = meson8b_dwmac_probe,
0540 .remove = stmmac_pltfr_remove,
0541 .driver = {
0542 .name = "meson8b-dwmac",
0543 .pm = &stmmac_pltfr_pm_ops,
0544 .of_match_table = meson8b_dwmac_match,
0545 },
0546 };
0547 module_platform_driver(meson8b_dwmac_driver);
0548
0549 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
0550 MODULE_DESCRIPTION("Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer");
0551 MODULE_LICENSE("GPL v2");