1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer 4 * 5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 6 */ 7 8 #include <linux/bitfield.h> 9 #include <linux/clk.h> 10 #include <linux/clk-provider.h> 11 #include <linux/device.h> 12 #include <linux/ethtool.h> 13 #include <linux/io.h> 14 #include <linux/ioport.h> 15 #include <linux/module.h> 16 #include <linux/of_device.h> 17 #include <linux/of_net.h> 18 #include <linux/mfd/syscon.h> 19 #include <linux/platform_device.h> 20 #include <linux/stmmac.h> 21 22 #include "stmmac_platform.h" 23 24 #define PRG_ETH0 0x0 25 26 #define PRG_ETH0_RGMII_MODE BIT(0) 27 28 #define PRG_ETH0_EXT_PHY_MODE_MASK GENMASK(2, 0) 29 #define PRG_ETH0_EXT_RGMII_MODE 1 30 #define PRG_ETH0_EXT_RMII_MODE 4 31 32 /* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */ 33 #define PRG_ETH0_CLK_M250_SEL_SHIFT 4 34 #define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4) 35 36 /* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where 8ns are exactly one 37 * cycle of the 125MHz RGMII TX clock): 38 * 0ns = 0x0, 2ns = 0x1, 4ns = 0x2, 6ns = 0x3 39 */ 40 #define PRG_ETH0_TXDLY_MASK GENMASK(6, 5) 41 42 /* divider for the result of m250_sel */ 43 #define PRG_ETH0_CLK_M250_DIV_SHIFT 7 44 #define PRG_ETH0_CLK_M250_DIV_WIDTH 3 45 46 #define PRG_ETH0_RGMII_TX_CLK_EN 10 47 48 #define PRG_ETH0_INVERTED_RMII_CLK BIT(11) 49 #define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12) 50 51 /* Bypass (= 0, the signal from the GPIO input directly connects to the 52 * internal sampling) or enable (= 1) the internal logic for RXEN and RXD[3:0] 53 * timing tuning. 54 */ 55 #define PRG_ETH0_ADJ_ENABLE BIT(13) 56 /* Controls whether the RXEN and RXD[3:0] signals should be aligned with the 57 * input RX rising/falling edge and sent to the Ethernet internals. This sets 58 * the automatically delay and skew automatically (internally). 59 */ 60 #define PRG_ETH0_ADJ_SETUP BIT(14) 61 /* An internal counter based on the "timing-adjustment" clock. The counter is 62 * cleared on both, the falling and rising edge of the RX_CLK. This selects the 63 * delay (= the counter value) when to start sampling RXEN and RXD[3:0]. 64 */ 65 #define PRG_ETH0_ADJ_DELAY GENMASK(19, 15) 66 /* Adjusts the skew between each bit of RXEN and RXD[3:0]. If a signal has a 67 * large input delay, the bit for that signal (RXEN = bit 0, RXD[3] = bit 1, 68 * ...) can be configured to be 1 to compensate for a delay of about 1ns. 69 */ 70 #define PRG_ETH0_ADJ_SKEW GENMASK(24, 20) 71 72 #define MUX_CLK_NUM_PARENTS 2 73 74 struct meson8b_dwmac; 75 76 struct meson8b_dwmac_data { 77 int (*set_phy_mode)(struct meson8b_dwmac *dwmac); 78 }; 79 80 struct meson8b_dwmac { 81 struct device *dev; 82 void __iomem *regs; 83 84 const struct meson8b_dwmac_data *data; 85 phy_interface_t phy_mode; 86 struct clk *rgmii_tx_clk; 87 u32 tx_delay_ns; 88 u32 rx_delay_ns; 89 struct clk *timing_adj_clk; 90 }; 91 92 struct meson8b_dwmac_clk_configs { 93 struct clk_mux m250_mux; 94 struct clk_divider m250_div; 95 struct clk_fixed_factor fixed_div2; 96 struct clk_gate rgmii_tx_en; 97 }; 98 99 static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg, 100 u32 mask, u32 value) 101 { 102 u32 data; 103 104 data = readl(dwmac->regs + reg); 105 data &= ~mask; 106 data |= (value & mask); 107 108 writel(data, dwmac->regs + reg); 109 } 110 111 static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac, 112 const char *name_suffix, 113 const char **parent_names, 114 int num_parents, 115 const struct clk_ops *ops, 116 struct clk_hw *hw) 117 { 118 struct clk_init_data init; 119 char clk_name[32]; 120 121 snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev), 122 name_suffix); 123 124 init.name = clk_name; 125 init.ops = ops; 126 init.flags = CLK_SET_RATE_PARENT; 127 init.parent_names = parent_names; 128 init.num_parents = num_parents; 129 130 hw->init = &init; 131 132 return devm_clk_register(dwmac->dev, hw); 133 } 134 135 static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac) 136 { 137 int i, ret; 138 struct clk *clk; 139 struct device *dev = dwmac->dev; 140 const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS]; 141 struct meson8b_dwmac_clk_configs *clk_configs; 142 static const struct clk_div_table div_table[] = { 143 { .div = 2, .val = 2, }, 144 { .div = 3, .val = 3, }, 145 { .div = 4, .val = 4, }, 146 { .div = 5, .val = 5, }, 147 { .div = 6, .val = 6, }, 148 { .div = 7, .val = 7, }, 149 { /* end of array */ } 150 }; 151 152 clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL); 153 if (!clk_configs) 154 return -ENOMEM; 155 156 /* get the mux parents from DT */ 157 for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) { 158 char name[16]; 159 160 snprintf(name, sizeof(name), "clkin%d", i); 161 clk = devm_clk_get(dev, name); 162 if (IS_ERR(clk)) { 163 ret = PTR_ERR(clk); 164 if (ret != -EPROBE_DEFER) 165 dev_err(dev, "Missing clock %s\n", name); 166 return ret; 167 } 168 169 mux_parent_names[i] = __clk_get_name(clk); 170 } 171 172 clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0; 173 clk_configs->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT; 174 clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK; 175 clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names, 176 MUX_CLK_NUM_PARENTS, &clk_mux_ops, 177 &clk_configs->m250_mux.hw); 178 if (WARN_ON(IS_ERR(clk))) 179 return PTR_ERR(clk); 180 181 parent_name = __clk_get_name(clk); 182 clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0; 183 clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; 184 clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; 185 clk_configs->m250_div.table = div_table; 186 clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO | 187 CLK_DIVIDER_ROUND_CLOSEST; 188 clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1, 189 &clk_divider_ops, 190 &clk_configs->m250_div.hw); 191 if (WARN_ON(IS_ERR(clk))) 192 return PTR_ERR(clk); 193 194 parent_name = __clk_get_name(clk); 195 clk_configs->fixed_div2.mult = 1; 196 clk_configs->fixed_div2.div = 2; 197 clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_name, 1, 198 &clk_fixed_factor_ops, 199 &clk_configs->fixed_div2.hw); 200 if (WARN_ON(IS_ERR(clk))) 201 return PTR_ERR(clk); 202 203 parent_name = __clk_get_name(clk); 204 clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0; 205 clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN; 206 clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_name, 1, 207 &clk_gate_ops, 208 &clk_configs->rgmii_tx_en.hw); 209 if (WARN_ON(IS_ERR(clk))) 210 return PTR_ERR(clk); 211 212 dwmac->rgmii_tx_clk = clk; 213 214 return 0; 215 } 216 217 static int meson8b_set_phy_mode(struct meson8b_dwmac *dwmac) 218 { 219 switch (dwmac->phy_mode) { 220 case PHY_INTERFACE_MODE_RGMII: 221 case PHY_INTERFACE_MODE_RGMII_RXID: 222 case PHY_INTERFACE_MODE_RGMII_ID: 223 case PHY_INTERFACE_MODE_RGMII_TXID: 224 /* enable RGMII mode */ 225 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 226 PRG_ETH0_RGMII_MODE, 227 PRG_ETH0_RGMII_MODE); 228 break; 229 case PHY_INTERFACE_MODE_RMII: 230 /* disable RGMII mode -> enables RMII mode */ 231 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 232 PRG_ETH0_RGMII_MODE, 0); 233 break; 234 default: 235 dev_err(dwmac->dev, "fail to set phy-mode %s\n", 236 phy_modes(dwmac->phy_mode)); 237 return -EINVAL; 238 } 239 240 return 0; 241 } 242 243 static int meson_axg_set_phy_mode(struct meson8b_dwmac *dwmac) 244 { 245 switch (dwmac->phy_mode) { 246 case PHY_INTERFACE_MODE_RGMII: 247 case PHY_INTERFACE_MODE_RGMII_RXID: 248 case PHY_INTERFACE_MODE_RGMII_ID: 249 case PHY_INTERFACE_MODE_RGMII_TXID: 250 /* enable RGMII mode */ 251 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 252 PRG_ETH0_EXT_PHY_MODE_MASK, 253 PRG_ETH0_EXT_RGMII_MODE); 254 break; 255 case PHY_INTERFACE_MODE_RMII: 256 /* disable RGMII mode -> enables RMII mode */ 257 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 258 PRG_ETH0_EXT_PHY_MODE_MASK, 259 PRG_ETH0_EXT_RMII_MODE); 260 break; 261 default: 262 dev_err(dwmac->dev, "fail to set phy-mode %s\n", 263 phy_modes(dwmac->phy_mode)); 264 return -EINVAL; 265 } 266 267 return 0; 268 } 269 270 static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac, 271 struct clk *clk) 272 { 273 int ret; 274 275 ret = clk_prepare_enable(clk); 276 if (ret) 277 return ret; 278 279 devm_add_action_or_reset(dwmac->dev, 280 (void(*)(void *))clk_disable_unprepare, 281 dwmac->rgmii_tx_clk); 282 283 return 0; 284 } 285 286 static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac) 287 { 288 u32 tx_dly_config, rx_dly_config, delay_config; 289 int ret; 290 291 tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK, 292 dwmac->tx_delay_ns >> 1); 293 294 if (dwmac->rx_delay_ns == 2) 295 rx_dly_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP; 296 else 297 rx_dly_config = 0; 298 299 switch (dwmac->phy_mode) { 300 case PHY_INTERFACE_MODE_RGMII: 301 delay_config = tx_dly_config | rx_dly_config; 302 break; 303 case PHY_INTERFACE_MODE_RGMII_RXID: 304 delay_config = tx_dly_config; 305 break; 306 case PHY_INTERFACE_MODE_RGMII_TXID: 307 delay_config = rx_dly_config; 308 break; 309 case PHY_INTERFACE_MODE_RGMII_ID: 310 case PHY_INTERFACE_MODE_RMII: 311 delay_config = 0; 312 break; 313 default: 314 dev_err(dwmac->dev, "unsupported phy-mode %s\n", 315 phy_modes(dwmac->phy_mode)); 316 return -EINVAL; 317 }; 318 319 if (rx_dly_config & PRG_ETH0_ADJ_ENABLE) { 320 if (!dwmac->timing_adj_clk) { 321 dev_err(dwmac->dev, 322 "The timing-adjustment clock is mandatory for the RX delay re-timing\n"); 323 return -EINVAL; 324 } 325 326 /* The timing adjustment logic is driven by a separate clock */ 327 ret = meson8b_devm_clk_prepare_enable(dwmac, 328 dwmac->timing_adj_clk); 329 if (ret) { 330 dev_err(dwmac->dev, 331 "Failed to enable the timing-adjustment clock\n"); 332 return ret; 333 } 334 } 335 336 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK | 337 PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP | 338 PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW, 339 delay_config); 340 341 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) { 342 /* only relevant for RMII mode -> disable in RGMII mode */ 343 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 344 PRG_ETH0_INVERTED_RMII_CLK, 0); 345 346 /* Configure the 125MHz RGMII TX clock, the IP block changes 347 * the output automatically (= without us having to configure 348 * a register) based on the line-speed (125MHz for Gbit speeds, 349 * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s). 350 */ 351 ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000); 352 if (ret) { 353 dev_err(dwmac->dev, 354 "failed to set RGMII TX clock\n"); 355 return ret; 356 } 357 358 ret = meson8b_devm_clk_prepare_enable(dwmac, 359 dwmac->rgmii_tx_clk); 360 if (ret) { 361 dev_err(dwmac->dev, 362 "failed to enable the RGMII TX clock\n"); 363 return ret; 364 } 365 } else { 366 /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */ 367 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, 368 PRG_ETH0_INVERTED_RMII_CLK, 369 PRG_ETH0_INVERTED_RMII_CLK); 370 } 371 372 /* enable TX_CLK and PHY_REF_CLK generator */ 373 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK, 374 PRG_ETH0_TX_AND_PHY_REF_CLK); 375 376 return 0; 377 } 378 379 static int meson8b_dwmac_probe(struct platform_device *pdev) 380 { 381 struct plat_stmmacenet_data *plat_dat; 382 struct stmmac_resources stmmac_res; 383 struct meson8b_dwmac *dwmac; 384 int ret; 385 386 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 387 if (ret) 388 return ret; 389 390 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 391 if (IS_ERR(plat_dat)) 392 return PTR_ERR(plat_dat); 393 394 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 395 if (!dwmac) { 396 ret = -ENOMEM; 397 goto err_remove_config_dt; 398 } 399 400 dwmac->data = (const struct meson8b_dwmac_data *) 401 of_device_get_match_data(&pdev->dev); 402 if (!dwmac->data) { 403 ret = -EINVAL; 404 goto err_remove_config_dt; 405 } 406 dwmac->regs = devm_platform_ioremap_resource(pdev, 1); 407 if (IS_ERR(dwmac->regs)) { 408 ret = PTR_ERR(dwmac->regs); 409 goto err_remove_config_dt; 410 } 411 412 dwmac->dev = &pdev->dev; 413 ret = of_get_phy_mode(pdev->dev.of_node, &dwmac->phy_mode); 414 if (ret) { 415 dev_err(&pdev->dev, "missing phy-mode property\n"); 416 goto err_remove_config_dt; 417 } 418 419 /* use 2ns as fallback since this value was previously hardcoded */ 420 if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns", 421 &dwmac->tx_delay_ns)) 422 dwmac->tx_delay_ns = 2; 423 424 /* use 0ns as fallback since this is what most boards actually use */ 425 if (of_property_read_u32(pdev->dev.of_node, "amlogic,rx-delay-ns", 426 &dwmac->rx_delay_ns)) 427 dwmac->rx_delay_ns = 0; 428 429 if (dwmac->rx_delay_ns != 0 && dwmac->rx_delay_ns != 2) { 430 dev_err(&pdev->dev, 431 "The only allowed RX delays values are: 0ns, 2ns"); 432 ret = -EINVAL; 433 goto err_remove_config_dt; 434 } 435 436 dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev, 437 "timing-adjustment"); 438 if (IS_ERR(dwmac->timing_adj_clk)) { 439 ret = PTR_ERR(dwmac->timing_adj_clk); 440 goto err_remove_config_dt; 441 } 442 443 ret = meson8b_init_rgmii_tx_clk(dwmac); 444 if (ret) 445 goto err_remove_config_dt; 446 447 ret = dwmac->data->set_phy_mode(dwmac); 448 if (ret) 449 goto err_remove_config_dt; 450 451 ret = meson8b_init_prg_eth(dwmac); 452 if (ret) 453 goto err_remove_config_dt; 454 455 plat_dat->bsp_priv = dwmac; 456 457 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 458 if (ret) 459 goto err_remove_config_dt; 460 461 return 0; 462 463 err_remove_config_dt: 464 stmmac_remove_config_dt(pdev, plat_dat); 465 466 return ret; 467 } 468 469 static const struct meson8b_dwmac_data meson8b_dwmac_data = { 470 .set_phy_mode = meson8b_set_phy_mode, 471 }; 472 473 static const struct meson8b_dwmac_data meson_axg_dwmac_data = { 474 .set_phy_mode = meson_axg_set_phy_mode, 475 }; 476 477 static const struct of_device_id meson8b_dwmac_match[] = { 478 { 479 .compatible = "amlogic,meson8b-dwmac", 480 .data = &meson8b_dwmac_data, 481 }, 482 { 483 .compatible = "amlogic,meson8m2-dwmac", 484 .data = &meson8b_dwmac_data, 485 }, 486 { 487 .compatible = "amlogic,meson-gxbb-dwmac", 488 .data = &meson8b_dwmac_data, 489 }, 490 { 491 .compatible = "amlogic,meson-axg-dwmac", 492 .data = &meson_axg_dwmac_data, 493 }, 494 { } 495 }; 496 MODULE_DEVICE_TABLE(of, meson8b_dwmac_match); 497 498 static struct platform_driver meson8b_dwmac_driver = { 499 .probe = meson8b_dwmac_probe, 500 .remove = stmmac_pltfr_remove, 501 .driver = { 502 .name = "meson8b-dwmac", 503 .pm = &stmmac_pltfr_pm_ops, 504 .of_match_table = meson8b_dwmac_match, 505 }, 506 }; 507 module_platform_driver(meson8b_dwmac_driver); 508 509 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); 510 MODULE_DESCRIPTION("Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer"); 511 MODULE_LICENSE("GPL v2"); 512