1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 Marek Vasut <marex@denx.de> 4 * 5 * Altera SoCFPGA EMAC extras 6 */ 7 8 #include <common.h> 9 #include <asm/io.h> 10 #include <dm.h> 11 #include <clk.h> 12 #include <phy.h> 13 #include <regmap.h> 14 #include <reset.h> 15 #include <syscon.h> 16 #include "designware.h" 17 18 #include <asm/arch/system_manager.h> 19 20 enum dwmac_type { 21 DWMAC_SOCFPGA_GEN5 = 0, 22 DWMAC_SOCFPGA_ARRIA10, 23 DWMAC_SOCFPGA_STRATIX10, 24 }; 25 26 struct dwmac_socfpga_platdata { 27 struct dw_eth_pdata dw_eth_pdata; 28 enum dwmac_type type; 29 void *phy_intf; 30 }; 31 32 static int dwmac_socfpga_ofdata_to_platdata(struct udevice *dev) 33 { 34 struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev); 35 struct regmap *regmap; 36 struct ofnode_phandle_args args; 37 void *range; 38 int ret; 39 40 ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL, 41 2, 0, &args); 42 if (ret) { 43 dev_err(dev, "Failed to get syscon: %d\n", ret); 44 return ret; 45 } 46 47 if (args.args_count != 2) { 48 dev_err(dev, "Invalid number of syscon args\n"); 49 return -EINVAL; 50 } 51 52 regmap = syscon_node_to_regmap(args.node); 53 if (IS_ERR(regmap)) { 54 ret = PTR_ERR(regmap); 55 dev_err(dev, "Failed to get regmap: %d\n", ret); 56 return ret; 57 } 58 59 range = regmap_get_range(regmap, 0); 60 if (!range) { 61 dev_err(dev, "Failed to get regmap range\n"); 62 return -ENOMEM; 63 } 64 65 pdata->phy_intf = range + args.args[0]; 66 67 /* 68 * Sadly, the Altera DT bindings don't have SoC-specific compatibles, 69 * so we have to guesstimate which SoC we are running on from the 70 * DWMAC version. Luckily, Altera at least updated the DWMAC with 71 * each SoC. 72 */ 73 if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.70a")) 74 pdata->type = DWMAC_SOCFPGA_GEN5; 75 76 if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.72a")) 77 pdata->type = DWMAC_SOCFPGA_ARRIA10; 78 79 if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.74a")) 80 pdata->type = DWMAC_SOCFPGA_STRATIX10; 81 82 return designware_eth_ofdata_to_platdata(dev); 83 } 84 85 static int dwmac_socfpga_probe(struct udevice *dev) 86 { 87 struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev); 88 struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata; 89 struct reset_ctl_bulk reset_bulk; 90 int ret; 91 u8 modereg; 92 93 if (pdata->type == DWMAC_SOCFPGA_ARRIA10) { 94 switch (edata->phy_interface) { 95 case PHY_INTERFACE_MODE_MII: 96 case PHY_INTERFACE_MODE_GMII: 97 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 98 break; 99 case PHY_INTERFACE_MODE_RMII: 100 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII; 101 break; 102 case PHY_INTERFACE_MODE_RGMII: 103 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; 104 break; 105 default: 106 dev_err(dev, "Unsupported PHY mode\n"); 107 return -EINVAL; 108 } 109 110 ret = reset_get_bulk(dev, &reset_bulk); 111 if (ret) { 112 dev_err(dev, "Failed to get reset: %d\n", ret); 113 return ret; 114 } 115 116 reset_assert_bulk(&reset_bulk); 117 118 clrsetbits_le32(pdata->phy_intf, 119 SYSMGR_EMACGRP_CTRL_PHYSEL_MASK, 120 modereg); 121 122 reset_release_bulk(&reset_bulk); 123 } 124 125 return designware_eth_probe(dev); 126 } 127 128 static const struct udevice_id dwmac_socfpga_ids[] = { 129 { .compatible = "altr,socfpga-stmmac" }, 130 { } 131 }; 132 133 U_BOOT_DRIVER(dwmac_socfpga) = { 134 .name = "dwmac_socfpga", 135 .id = UCLASS_ETH, 136 .of_match = dwmac_socfpga_ids, 137 .ofdata_to_platdata = dwmac_socfpga_ofdata_to_platdata, 138 .probe = dwmac_socfpga_probe, 139 .ops = &designware_eth_ops, 140 .priv_auto_alloc_size = sizeof(struct dw_eth_dev), 141 .platdata_auto_alloc_size = sizeof(struct dwmac_socfpga_platdata), 142 .flags = DM_FLAG_ALLOC_PRIV_DMA, 143 }; 144