1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2021 BayLibre, SAS 4 */ 5 6#include <common.h> 7#include <asm/io.h> 8#include <dm.h> 9#include <phy.h> 10#include "designware.h" 11#include <dm/device_compat.h> 12#include <linux/err.h> 13 14#define ETH_REG_0 0x0 15#define ETH_REG_1 0x4 16#define ETH_REG_2 0x18 17#define ETH_REG_3 0x1c 18 19#define GX_ETH_REG_0_PHY_INTF BIT(0) 20#define GX_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) 21#define GX_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) 22#define GX_ETH_REG_0_PHY_CLK_EN BIT(10) 23#define GX_ETH_REG_0_INVERT_RMII_CLK BIT(11) 24#define GX_ETH_REG_0_CLK_EN BIT(12) 25 26#define AXG_ETH_REG_0_PHY_INTF_RGMII BIT(0) 27#define AXG_ETH_REG_0_PHY_INTF_RMII BIT(2) 28#define AXG_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) 29#define AXG_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) 30#define AXG_ETH_REG_0_PHY_CLK_EN BIT(10) 31#define AXG_ETH_REG_0_INVERT_RMII_CLK BIT(11) 32#define AXG_ETH_REG_0_CLK_EN BIT(12) 33 34struct dwmac_meson8b_plat { 35 struct dw_eth_pdata dw_eth_pdata; 36 int (*dwmac_setup)(struct udevice *dev, struct eth_pdata *edata); 37 void *regs; 38}; 39 40static int dwmac_meson8b_of_to_plat(struct udevice *dev) 41{ 42 struct dwmac_meson8b_plat *pdata = dev_get_plat(dev); 43 44 pdata->regs = dev_read_addr_index_ptr(dev, 1); 45 if (!pdata->regs) 46 return -EINVAL; 47 48 pdata->dwmac_setup = (void *)dev_get_driver_data(dev); 49 if (!pdata->dwmac_setup) 50 return -EINVAL; 51 52 return designware_eth_of_to_plat(dev); 53} 54 55static int dwmac_setup_axg(struct udevice *dev, struct eth_pdata *edata) 56{ 57 struct dwmac_meson8b_plat *plat = dev_get_plat(dev); 58 59 switch (edata->phy_interface) { 60 case PHY_INTERFACE_MODE_RGMII: 61 case PHY_INTERFACE_MODE_RGMII_ID: 62 /* Set RGMII mode */ 63 setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII | 64 AXG_ETH_REG_0_TX_PHASE(1) | 65 AXG_ETH_REG_0_TX_RATIO(4) | 66 AXG_ETH_REG_0_PHY_CLK_EN | 67 AXG_ETH_REG_0_CLK_EN); 68 break; 69 70 case PHY_INTERFACE_MODE_RGMII_RXID: 71 case PHY_INTERFACE_MODE_RGMII_TXID: 72 /* TOFIX: handle amlogic,tx-delay-ns & rx-internal-delay-ps from DT */ 73 setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII | 74 AXG_ETH_REG_0_TX_RATIO(4) | 75 AXG_ETH_REG_0_PHY_CLK_EN | 76 AXG_ETH_REG_0_CLK_EN); 77 break; 78 79 case PHY_INTERFACE_MODE_RMII: 80 /* Set RMII mode */ 81 out_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RMII | 82 AXG_ETH_REG_0_INVERT_RMII_CLK | 83 AXG_ETH_REG_0_CLK_EN); 84 break; 85 default: 86 dev_err(dev, "Unsupported PHY mode\n"); 87 return -EINVAL; 88 } 89 90 return 0; 91} 92 93static int dwmac_setup_gx(struct udevice *dev, struct eth_pdata *edata) 94{ 95 struct dwmac_meson8b_plat *plat = dev_get_plat(dev); 96 97 switch (edata->phy_interface) { 98 case PHY_INTERFACE_MODE_RGMII: 99 case PHY_INTERFACE_MODE_RGMII_ID: 100 /* Set RGMII mode */ 101 setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF | 102 GX_ETH_REG_0_TX_PHASE(1) | 103 GX_ETH_REG_0_TX_RATIO(4) | 104 GX_ETH_REG_0_PHY_CLK_EN | 105 GX_ETH_REG_0_CLK_EN); 106 107 break; 108 109 case PHY_INTERFACE_MODE_RGMII_RXID: 110 case PHY_INTERFACE_MODE_RGMII_TXID: 111 /* TOFIX: handle amlogic,tx-delay-ns & rx-internal-delay-ps from DT */ 112 setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF | 113 GX_ETH_REG_0_TX_RATIO(4) | 114 GX_ETH_REG_0_PHY_CLK_EN | 115 GX_ETH_REG_0_CLK_EN); 116 117 break; 118 119 case PHY_INTERFACE_MODE_RMII: 120 /* Set RMII mode */ 121 out_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_INVERT_RMII_CLK | 122 GX_ETH_REG_0_CLK_EN); 123 124 if (!IS_ENABLED(CONFIG_MESON_GXBB)) 125 writel(0x10110181, plat->regs + ETH_REG_2); 126 127 break; 128 default: 129 dev_err(dev, "Unsupported PHY mode\n"); 130 return -EINVAL; 131 } 132 133 return 0; 134} 135 136static int dwmac_meson8b_probe(struct udevice *dev) 137{ 138 struct dwmac_meson8b_plat *pdata = dev_get_plat(dev); 139 struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata; 140 int ret; 141 142 ret = pdata->dwmac_setup(dev, edata); 143 if (ret) 144 return ret; 145 146 return designware_eth_probe(dev); 147} 148 149static const struct udevice_id dwmac_meson8b_ids[] = { 150 { .compatible = "amlogic,meson-gxbb-dwmac", .data = (ulong)dwmac_setup_gx }, 151 { .compatible = "amlogic,meson-g12a-dwmac", .data = (ulong)dwmac_setup_axg }, 152 { .compatible = "amlogic,meson-axg-dwmac", .data = (ulong)dwmac_setup_axg }, 153 { } 154}; 155 156U_BOOT_DRIVER(dwmac_meson8b) = { 157 .name = "dwmac_meson8b", 158 .id = UCLASS_ETH, 159 .of_match = dwmac_meson8b_ids, 160 .of_to_plat = dwmac_meson8b_of_to_plat, 161 .probe = dwmac_meson8b_probe, 162 .ops = &designware_eth_ops, 163 .priv_auto = sizeof(struct dw_eth_dev), 164 .plat_auto = sizeof(struct dwmac_meson8b_plat), 165 .flags = DM_FLAG_ALLOC_PRIV_DMA, 166}; 167