// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2021 BayLibre, SAS */ #include #include #include #include #include "designware.h" #include #include #define ETH_REG_0 0x0 #define ETH_REG_1 0x4 #define ETH_REG_2 0x18 #define ETH_REG_3 0x1c #define GX_ETH_REG_0_PHY_INTF BIT(0) #define GX_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) #define GX_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) #define GX_ETH_REG_0_PHY_CLK_EN BIT(10) #define GX_ETH_REG_0_INVERT_RMII_CLK BIT(11) #define GX_ETH_REG_0_CLK_EN BIT(12) #define AXG_ETH_REG_0_PHY_INTF_RGMII BIT(0) #define AXG_ETH_REG_0_PHY_INTF_RMII BIT(2) #define AXG_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) #define AXG_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) #define AXG_ETH_REG_0_PHY_CLK_EN BIT(10) #define AXG_ETH_REG_0_INVERT_RMII_CLK BIT(11) #define AXG_ETH_REG_0_CLK_EN BIT(12) struct dwmac_meson8b_plat { struct dw_eth_pdata dw_eth_pdata; int (*dwmac_setup)(struct udevice *dev, struct eth_pdata *edata); void *regs; }; static int dwmac_meson8b_of_to_plat(struct udevice *dev) { struct dwmac_meson8b_plat *pdata = dev_get_plat(dev); pdata->regs = dev_read_addr_index_ptr(dev, 1); if (!pdata->regs) return -EINVAL; pdata->dwmac_setup = (void *)dev_get_driver_data(dev); if (!pdata->dwmac_setup) return -EINVAL; return designware_eth_of_to_plat(dev); } static int dwmac_setup_axg(struct udevice *dev, struct eth_pdata *edata) { struct dwmac_meson8b_plat *plat = dev_get_plat(dev); switch (edata->phy_interface) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: /* Set RGMII mode */ setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII | AXG_ETH_REG_0_TX_PHASE(1) | AXG_ETH_REG_0_TX_RATIO(4) | AXG_ETH_REG_0_PHY_CLK_EN | AXG_ETH_REG_0_CLK_EN); break; case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: /* TOFIX: handle amlogic,tx-delay-ns & rx-internal-delay-ps from DT */ setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII | AXG_ETH_REG_0_TX_RATIO(4) | AXG_ETH_REG_0_PHY_CLK_EN | AXG_ETH_REG_0_CLK_EN); break; case PHY_INTERFACE_MODE_RMII: /* Set RMII mode */ out_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RMII | AXG_ETH_REG_0_INVERT_RMII_CLK | AXG_ETH_REG_0_CLK_EN); break; default: dev_err(dev, "Unsupported PHY mode\n"); return -EINVAL; } return 0; } static int dwmac_setup_gx(struct udevice *dev, struct eth_pdata *edata) { struct dwmac_meson8b_plat *plat = dev_get_plat(dev); switch (edata->phy_interface) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: /* Set RGMII mode */ setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF | GX_ETH_REG_0_TX_PHASE(1) | GX_ETH_REG_0_TX_RATIO(4) | GX_ETH_REG_0_PHY_CLK_EN | GX_ETH_REG_0_CLK_EN); break; case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: /* TOFIX: handle amlogic,tx-delay-ns & rx-internal-delay-ps from DT */ setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF | GX_ETH_REG_0_TX_RATIO(4) | GX_ETH_REG_0_PHY_CLK_EN | GX_ETH_REG_0_CLK_EN); break; case PHY_INTERFACE_MODE_RMII: /* Set RMII mode */ out_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_INVERT_RMII_CLK | GX_ETH_REG_0_CLK_EN); if (!IS_ENABLED(CONFIG_MESON_GXBB)) writel(0x10110181, plat->regs + ETH_REG_2); break; default: dev_err(dev, "Unsupported PHY mode\n"); return -EINVAL; } return 0; } static int dwmac_meson8b_probe(struct udevice *dev) { struct dwmac_meson8b_plat *pdata = dev_get_plat(dev); struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata; int ret; ret = pdata->dwmac_setup(dev, edata); if (ret) return ret; return designware_eth_probe(dev); } static const struct udevice_id dwmac_meson8b_ids[] = { { .compatible = "amlogic,meson-gxbb-dwmac", .data = (ulong)dwmac_setup_gx }, { .compatible = "amlogic,meson-g12a-dwmac", .data = (ulong)dwmac_setup_axg }, { .compatible = "amlogic,meson-axg-dwmac", .data = (ulong)dwmac_setup_axg }, { } }; U_BOOT_DRIVER(dwmac_meson8b) = { .name = "dwmac_meson8b", .id = UCLASS_ETH, .of_match = dwmac_meson8b_ids, .of_to_plat = dwmac_meson8b_of_to_plat, .probe = dwmac_meson8b_probe, .ops = &designware_eth_ops, .priv_auto = sizeof(struct dw_eth_dev), .plat_auto = sizeof(struct dwmac_meson8b_plat), .flags = DM_FLAG_ALLOC_PRIV_DMA, };