Lines Matching +full:tx +full:- +full:clk +full:- +full:delay +full:- +full:ps
1 // SPDX-License-Identifier: GPL-2.0-only
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
35 /* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where 8ns are exactly one
36 * cycle of the 125MHz RGMII TX clock):
57 * the automatically delay and skew automatically (internally).
60 /* An internal counter based on the "timing-adjustment" clock. The counter is
62 * delay (= the counter value) when to start sampling RXEN and RXD[3:0].
66 * large input delay, the bit for that signal (RXEN = bit 0, RXD[3] = bit 1,
67 * ...) can be configured to be 1 to compensate for a delay of about 1ns.
73 /* Defined for adding a delay to the input RX_CLK for better timing.
74 * Each step is 200ps. These bits are used with external RGMII PHYs
94 struct clk *rgmii_tx_clk;
97 struct clk *timing_adj_clk;
112 data = readl(dwmac->regs + reg); in meson8b_dwmac_mask_bits()
116 writel(data, dwmac->regs + reg); in meson8b_dwmac_mask_bits()
119 static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac, in meson8b_dwmac_register_clk()
129 snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev), in meson8b_dwmac_register_clk()
138 hw->init = &init; in meson8b_dwmac_register_clk()
140 return devm_clk_register(dwmac->dev, hw); in meson8b_dwmac_register_clk()
145 struct clk *clk; in meson8b_init_rgmii_tx_clk() local
146 struct device *dev = dwmac->dev; in meson8b_init_rgmii_tx_clk()
149 { .index = -1, }, in meson8b_init_rgmii_tx_clk()
165 return -ENOMEM; in meson8b_init_rgmii_tx_clk()
167 clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0; in meson8b_init_rgmii_tx_clk()
168 clk_configs->m250_mux.shift = __ffs(PRG_ETH0_CLK_M250_SEL_MASK); in meson8b_init_rgmii_tx_clk()
169 clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK >> in meson8b_init_rgmii_tx_clk()
170 clk_configs->m250_mux.shift; in meson8b_init_rgmii_tx_clk()
171 clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parents, in meson8b_init_rgmii_tx_clk()
173 &clk_configs->m250_mux.hw); in meson8b_init_rgmii_tx_clk()
174 if (WARN_ON(IS_ERR(clk))) in meson8b_init_rgmii_tx_clk()
175 return PTR_ERR(clk); in meson8b_init_rgmii_tx_clk()
177 parent_data.hw = &clk_configs->m250_mux.hw; in meson8b_init_rgmii_tx_clk()
178 clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0; in meson8b_init_rgmii_tx_clk()
179 clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; in meson8b_init_rgmii_tx_clk()
180 clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; in meson8b_init_rgmii_tx_clk()
181 clk_configs->m250_div.table = div_table; in meson8b_init_rgmii_tx_clk()
182 clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO | in meson8b_init_rgmii_tx_clk()
184 clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_data, 1, in meson8b_init_rgmii_tx_clk()
186 &clk_configs->m250_div.hw); in meson8b_init_rgmii_tx_clk()
187 if (WARN_ON(IS_ERR(clk))) in meson8b_init_rgmii_tx_clk()
188 return PTR_ERR(clk); in meson8b_init_rgmii_tx_clk()
190 parent_data.hw = &clk_configs->m250_div.hw; in meson8b_init_rgmii_tx_clk()
191 clk_configs->fixed_div2.mult = 1; in meson8b_init_rgmii_tx_clk()
192 clk_configs->fixed_div2.div = 2; in meson8b_init_rgmii_tx_clk()
193 clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_data, 1, in meson8b_init_rgmii_tx_clk()
195 &clk_configs->fixed_div2.hw); in meson8b_init_rgmii_tx_clk()
196 if (WARN_ON(IS_ERR(clk))) in meson8b_init_rgmii_tx_clk()
197 return PTR_ERR(clk); in meson8b_init_rgmii_tx_clk()
199 parent_data.hw = &clk_configs->fixed_div2.hw; in meson8b_init_rgmii_tx_clk()
200 clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0; in meson8b_init_rgmii_tx_clk()
201 clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN; in meson8b_init_rgmii_tx_clk()
202 clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_data, 1, in meson8b_init_rgmii_tx_clk()
204 &clk_configs->rgmii_tx_en.hw); in meson8b_init_rgmii_tx_clk()
205 if (WARN_ON(IS_ERR(clk))) in meson8b_init_rgmii_tx_clk()
206 return PTR_ERR(clk); in meson8b_init_rgmii_tx_clk()
208 dwmac->rgmii_tx_clk = clk; in meson8b_init_rgmii_tx_clk()
215 switch (dwmac->phy_mode) { in meson8b_set_phy_mode()
226 /* disable RGMII mode -> enables RMII mode */ in meson8b_set_phy_mode()
231 dev_err(dwmac->dev, "fail to set phy-mode %s\n", in meson8b_set_phy_mode()
232 phy_modes(dwmac->phy_mode)); in meson8b_set_phy_mode()
233 return -EINVAL; in meson8b_set_phy_mode()
241 switch (dwmac->phy_mode) { in meson_axg_set_phy_mode()
252 /* disable RGMII mode -> enables RMII mode */ in meson_axg_set_phy_mode()
258 dev_err(dwmac->dev, "fail to set phy-mode %s\n", in meson_axg_set_phy_mode()
259 phy_modes(dwmac->phy_mode)); in meson_axg_set_phy_mode()
260 return -EINVAL; in meson_axg_set_phy_mode()
272 struct clk *clk) in meson8b_devm_clk_prepare_enable() argument
276 ret = clk_prepare_enable(clk); in meson8b_devm_clk_prepare_enable()
280 return devm_add_action_or_reset(dwmac->dev, in meson8b_devm_clk_prepare_enable()
281 meson8b_clk_disable_unprepare, clk); in meson8b_devm_clk_prepare_enable()
292 dwmac->tx_delay_ns >> 1); in meson8b_init_rgmii_delays()
294 if (dwmac->data->has_prg_eth1_rgmii_rx_delay) in meson8b_init_rgmii_delays()
296 dwmac->rx_delay_ps / 200); in meson8b_init_rgmii_delays()
297 else if (dwmac->rx_delay_ps == 2000) in meson8b_init_rgmii_delays()
300 switch (dwmac->phy_mode) { in meson8b_init_rgmii_delays()
317 dev_err(dwmac->dev, "unsupported phy-mode %s\n", in meson8b_init_rgmii_delays()
318 phy_modes(dwmac->phy_mode)); in meson8b_init_rgmii_delays()
319 return -EINVAL; in meson8b_init_rgmii_delays()
323 if (!dwmac->timing_adj_clk) { in meson8b_init_rgmii_delays()
324 dev_err(dwmac->dev, in meson8b_init_rgmii_delays()
325 "The timing-adjustment clock is mandatory for the RX delay re-timing\n"); in meson8b_init_rgmii_delays()
326 return -EINVAL; in meson8b_init_rgmii_delays()
331 dwmac->timing_adj_clk); in meson8b_init_rgmii_delays()
333 dev_err(dwmac->dev, in meson8b_init_rgmii_delays()
334 "Failed to enable the timing-adjustment clock\n"); in meson8b_init_rgmii_delays()
354 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) { in meson8b_init_prg_eth()
355 /* only relevant for RMII mode -> disable in RGMII mode */ in meson8b_init_prg_eth()
359 /* Configure the 125MHz RGMII TX clock, the IP block changes in meson8b_init_prg_eth()
361 * a register) based on the line-speed (125MHz for Gbit speeds, in meson8b_init_prg_eth()
364 ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000); in meson8b_init_prg_eth()
366 dev_err(dwmac->dev, in meson8b_init_prg_eth()
367 "failed to set RGMII TX clock\n"); in meson8b_init_prg_eth()
372 dwmac->rgmii_tx_clk); in meson8b_init_prg_eth()
374 dev_err(dwmac->dev, in meson8b_init_prg_eth()
375 "failed to enable the RGMII TX clock\n"); in meson8b_init_prg_eth()
407 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); in meson8b_dwmac_probe()
409 return -ENOMEM; in meson8b_dwmac_probe()
411 dwmac->data = (const struct meson8b_dwmac_data *) in meson8b_dwmac_probe()
412 of_device_get_match_data(&pdev->dev); in meson8b_dwmac_probe()
413 if (!dwmac->data) in meson8b_dwmac_probe()
414 return -EINVAL; in meson8b_dwmac_probe()
415 dwmac->regs = devm_platform_ioremap_resource(pdev, 1); in meson8b_dwmac_probe()
416 if (IS_ERR(dwmac->regs)) in meson8b_dwmac_probe()
417 return PTR_ERR(dwmac->regs); in meson8b_dwmac_probe()
419 dwmac->dev = &pdev->dev; in meson8b_dwmac_probe()
420 ret = of_get_phy_mode(pdev->dev.of_node, &dwmac->phy_mode); in meson8b_dwmac_probe()
422 dev_err(&pdev->dev, "missing phy-mode property\n"); in meson8b_dwmac_probe()
427 if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns", in meson8b_dwmac_probe()
428 &dwmac->tx_delay_ns)) in meson8b_dwmac_probe()
429 dwmac->tx_delay_ns = 2; in meson8b_dwmac_probe()
431 /* RX delay defaults to 0ps since this is what many boards use */ in meson8b_dwmac_probe()
432 if (of_property_read_u32(pdev->dev.of_node, "rx-internal-delay-ps", in meson8b_dwmac_probe()
433 &dwmac->rx_delay_ps)) { in meson8b_dwmac_probe()
434 if (!of_property_read_u32(pdev->dev.of_node, in meson8b_dwmac_probe()
435 "amlogic,rx-delay-ns", in meson8b_dwmac_probe()
436 &dwmac->rx_delay_ps)) in meson8b_dwmac_probe()
437 /* convert ns to ps */ in meson8b_dwmac_probe()
438 dwmac->rx_delay_ps *= 1000; in meson8b_dwmac_probe()
441 if (dwmac->data->has_prg_eth1_rgmii_rx_delay) { in meson8b_dwmac_probe()
442 if (dwmac->rx_delay_ps > 3000 || dwmac->rx_delay_ps % 200) { in meson8b_dwmac_probe()
443 dev_err(dwmac->dev, in meson8b_dwmac_probe()
444 "The RGMII RX delay range is 0..3000ps in 200ps steps"); in meson8b_dwmac_probe()
445 return -EINVAL; in meson8b_dwmac_probe()
448 if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) { in meson8b_dwmac_probe()
449 dev_err(dwmac->dev, in meson8b_dwmac_probe()
450 "The only allowed RGMII RX delays values are: 0ps, 2000ps"); in meson8b_dwmac_probe()
451 return -EINVAL; in meson8b_dwmac_probe()
455 dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev, in meson8b_dwmac_probe()
456 "timing-adjustment"); in meson8b_dwmac_probe()
457 if (IS_ERR(dwmac->timing_adj_clk)) in meson8b_dwmac_probe()
458 return PTR_ERR(dwmac->timing_adj_clk); in meson8b_dwmac_probe()
468 ret = dwmac->data->set_phy_mode(dwmac); in meson8b_dwmac_probe()
476 plat_dat->bsp_priv = dwmac; in meson8b_dwmac_probe()
478 return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); in meson8b_dwmac_probe()
498 .compatible = "amlogic,meson8b-dwmac",
502 .compatible = "amlogic,meson8m2-dwmac",
506 .compatible = "amlogic,meson-gxbb-dwmac",
510 .compatible = "amlogic,meson-axg-dwmac",
514 .compatible = "amlogic,meson-g12a-dwmac",
525 .name = "meson8b-dwmac",