xref: /openbmc/u-boot/drivers/net/dwmac_socfpga.c (revision da4cfa6b)
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