xref: /openbmc/u-boot/drivers/net/dwmac_socfpga.c (revision c507d306)
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 
dwmac_socfpga_ofdata_to_platdata(struct udevice * dev)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 
dwmac_socfpga_probe(struct udevice * dev)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