Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer
0004  *
0005  * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
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 /* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */
0033 #define PRG_ETH0_CLK_M250_SEL_MASK  GENMASK(4, 4)
0034 
0035 /* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where 8ns are exactly one
0036  * cycle of the 125MHz RGMII TX clock):
0037  * 0ns = 0x0, 2ns = 0x1, 4ns = 0x2, 6ns = 0x3
0038  */
0039 #define PRG_ETH0_TXDLY_MASK     GENMASK(6, 5)
0040 
0041 /* divider for the result of m250_sel */
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 /* Bypass (= 0, the signal from the GPIO input directly connects to the
0051  * internal sampling) or enable (= 1) the internal logic for RXEN and RXD[3:0]
0052  * timing tuning.
0053  */
0054 #define PRG_ETH0_ADJ_ENABLE     BIT(13)
0055 /* Controls whether the RXEN and RXD[3:0] signals should be aligned with the
0056  * input RX rising/falling edge and sent to the Ethernet internals. This sets
0057  * the automatically delay and skew automatically (internally).
0058  */
0059 #define PRG_ETH0_ADJ_SETUP      BIT(14)
0060 /* An internal counter based on the "timing-adjustment" clock. The counter is
0061  * cleared on both, the falling and rising edge of the RX_CLK. This selects the
0062  * delay (= the counter value) when to start sampling RXEN and RXD[3:0].
0063  */
0064 #define PRG_ETH0_ADJ_DELAY      GENMASK(19, 15)
0065 /* Adjusts the skew between each bit of RXEN and RXD[3:0]. If a signal has a
0066  * large input delay, the bit for that signal (RXEN = bit 0, RXD[3] = bit 1,
0067  * ...) can be configured to be 1 to compensate for a delay of about 1ns.
0068  */
0069 #define PRG_ETH0_ADJ_SKEW       GENMASK(24, 20)
0070 
0071 #define PRG_ETH1            0x4
0072 
0073 /* Defined for adding a delay to the input RX_CLK for better timing.
0074  * Each step is 200ps. These bits are used with external RGMII PHYs
0075  * because RGMII RX only has the small window. cfg_rxclk_dly can
0076  * adjust the window between RX_CLK and RX_DATA and improve the stability
0077  * of "rx data valid".
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         { /* end of array */ }
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         /* enable RGMII mode */
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         /* disable RGMII mode -> enables RMII mode */
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         /* enable RGMII mode */
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         /* disable RGMII mode -> enables RMII mode */
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         /* The timing adjustment logic is driven by a separate clock */
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         /* only relevant for RMII mode -> disable in RGMII mode */
0354         meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0355                     PRG_ETH0_INVERTED_RMII_CLK, 0);
0356 
0357         /* Configure the 125MHz RGMII TX clock, the IP block changes
0358          * the output automatically (= without us having to configure
0359          * a register) based on the line-speed (125MHz for Gbit speeds,
0360          * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
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         /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */
0378         meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
0379                     PRG_ETH0_INVERTED_RMII_CLK,
0380                     PRG_ETH0_INVERTED_RMII_CLK);
0381     }
0382 
0383     /* enable TX_CLK and PHY_REF_CLK generator */
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     /* use 2ns as fallback since this value was previously hardcoded */
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     /* RX delay defaults to 0ps since this is what many boards use */
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             /* convert ns to ps */
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");