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 struct dwmac_socfpga_platdata { 21 struct dw_eth_pdata dw_eth_pdata; 22 void *phy_intf; 23 u32 reg_shift; 24 }; 25 26 static int dwmac_socfpga_ofdata_to_platdata(struct udevice *dev) 27 { 28 struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev); 29 struct regmap *regmap; 30 struct ofnode_phandle_args args; 31 void *range; 32 int ret; 33 34 ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL, 35 2, 0, &args); 36 if (ret) { 37 dev_err(dev, "Failed to get syscon: %d\n", ret); 38 return ret; 39 } 40 41 if (args.args_count != 2) { 42 dev_err(dev, "Invalid number of syscon args\n"); 43 return -EINVAL; 44 } 45 46 regmap = syscon_node_to_regmap(args.node); 47 if (IS_ERR(regmap)) { 48 ret = PTR_ERR(regmap); 49 dev_err(dev, "Failed to get regmap: %d\n", ret); 50 return ret; 51 } 52 53 range = regmap_get_range(regmap, 0); 54 if (!range) { 55 dev_err(dev, "Failed to get regmap range\n"); 56 return -ENOMEM; 57 } 58 59 pdata->phy_intf = range + args.args[0]; 60 pdata->reg_shift = args.args[1]; 61 62 return designware_eth_ofdata_to_platdata(dev); 63 } 64 65 static int dwmac_socfpga_probe(struct udevice *dev) 66 { 67 struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev); 68 struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata; 69 struct reset_ctl_bulk reset_bulk; 70 int ret; 71 u32 modereg; 72 u32 modemask; 73 74 switch (edata->phy_interface) { 75 case PHY_INTERFACE_MODE_MII: 76 case PHY_INTERFACE_MODE_GMII: 77 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 78 break; 79 case PHY_INTERFACE_MODE_RMII: 80 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII; 81 break; 82 case PHY_INTERFACE_MODE_RGMII: 83 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; 84 break; 85 default: 86 dev_err(dev, "Unsupported PHY mode\n"); 87 return -EINVAL; 88 } 89 90 ret = reset_get_bulk(dev, &reset_bulk); 91 if (ret) { 92 dev_err(dev, "Failed to get reset: %d\n", ret); 93 return ret; 94 } 95 96 reset_assert_bulk(&reset_bulk); 97 98 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift; 99 clrsetbits_le32(pdata->phy_intf, modemask, 100 modereg << pdata->reg_shift); 101 102 reset_release_bulk(&reset_bulk); 103 104 return designware_eth_probe(dev); 105 } 106 107 static const struct udevice_id dwmac_socfpga_ids[] = { 108 { .compatible = "altr,socfpga-stmmac" }, 109 { } 110 }; 111 112 U_BOOT_DRIVER(dwmac_socfpga) = { 113 .name = "dwmac_socfpga", 114 .id = UCLASS_ETH, 115 .of_match = dwmac_socfpga_ids, 116 .ofdata_to_platdata = dwmac_socfpga_ofdata_to_platdata, 117 .probe = dwmac_socfpga_probe, 118 .ops = &designware_eth_ops, 119 .priv_auto_alloc_size = sizeof(struct dw_eth_dev), 120 .platdata_auto_alloc_size = sizeof(struct dwmac_socfpga_platdata), 121 .flags = DM_FLAG_ALLOC_PRIV_DMA, 122 }; 123