blob: c89c8a188b78000b9afade106d3625ef309f8674 [file] [log] [blame]
Tom Rinidec7ea02024-05-20 13:35:03 -06001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2023, Intel Corporation
4 */
5#include <clk.h>
6#include <cpu_func.h>
7#include <dm.h>
8#include <errno.h>
9#include <eth_phy.h>
10#include <log.h>
11#include <malloc.h>
12#include <memalign.h>
13#include <miiphy.h>
14#include <net.h>
15#include <netdev.h>
16#include <phy.h>
17#include <reset.h>
18#include <wait_bit.h>
19#include <asm/arch/secure_reg_helper.h>
20#include <asm/arch/system_manager.h>
21#include <regmap.h>
22#include <syscon.h>
23#include <asm/cache.h>
24#include <asm/gpio.h>
25#include <asm/io.h>
26#include <linux/delay.h>
27#include <dm/device_compat.h>
28#include "dwc_eth_xgmac.h"
29
30#define SOCFPGA_XGMAC_SYSCON_ARG_COUNT 2
31
Boon Khai Ng946bc622025-01-17 14:14:02 +080032phy_interface_t dwxgmac_of_get_mac_mode(struct udevice *dev)
33{
34 const char *mac_mode;
35 int i;
36
37 debug("%s(dev=%p):\n", __func__, dev);
38 mac_mode = dev_read_string(dev, "mac-mode");
39 if (!mac_mode)
40 return PHY_INTERFACE_MODE_NA;
41
42 if (mac_mode) {
43 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
44 if (!strcmp(mac_mode, phy_interface_strings[i]))
45 return i;
46 }
47 }
48 return PHY_INTERFACE_MODE_NA;
49}
50
Tom Rinidec7ea02024-05-20 13:35:03 -060051static int dwxgmac_socfpga_do_setphy(struct udevice *dev, u32 modereg)
52{
53 struct xgmac_priv *xgmac = dev_get_priv(dev);
54 int ret;
55
56 u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK <<
57 xgmac->syscon_phy_regshift;
58
Simon Glass7ec24132024-09-29 19:49:48 -060059 if (!(IS_ENABLED(CONFIG_XPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) {
Tom Rinidec7ea02024-05-20 13:35:03 -060060 u32 index = ((u64)xgmac->syscon_phy - socfpga_get_sysmgr_addr() -
61 SYSMGR_SOC64_EMAC0) >> 2;
62
63 u32 id = SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 + index;
64
65 ret = socfpga_secure_reg_update32(id,
66 modemask,
67 modereg <<
68 xgmac->syscon_phy_regshift);
69 if (ret) {
70 dev_err(dev, "Failed to set PHY register via SMC call\n");
71 return ret;
72 }
73
74 } else {
75 clrsetbits_le32(xgmac->phy, modemask, modereg);
76 }
77
78 return 0;
79}
80
81static int xgmac_probe_resources_socfpga(struct udevice *dev)
82{
83 struct xgmac_priv *xgmac = dev_get_priv(dev);
84 struct regmap *reg_map;
85 struct ofnode_phandle_args args;
86 void *range;
87 phy_interface_t interface;
Boon Khai Ng946bc622025-01-17 14:14:02 +080088 phy_interface_t mac_mode;
Tom Rinidec7ea02024-05-20 13:35:03 -060089 int ret;
90 u32 modereg;
91
92 interface = xgmac->config->interface(dev);
Boon Khai Ng946bc622025-01-17 14:14:02 +080093 mac_mode = dwxgmac_of_get_mac_mode(dev);
94
95 if (mac_mode == PHY_INTERFACE_MODE_NA)
96 mac_mode = interface;
Tom Rinidec7ea02024-05-20 13:35:03 -060097
Boon Khai Ng946bc622025-01-17 14:14:02 +080098 switch (mac_mode) {
Tom Rinidec7ea02024-05-20 13:35:03 -060099 case PHY_INTERFACE_MODE_MII:
100 case PHY_INTERFACE_MODE_GMII:
101 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
102 break;
103 case PHY_INTERFACE_MODE_RMII:
104 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII;
105 break;
106 case PHY_INTERFACE_MODE_RGMII:
Boon Khai Nge75669d2025-01-17 14:56:25 +0800107 case PHY_INTERFACE_MODE_RGMII_ID:
Tom Rinidec7ea02024-05-20 13:35:03 -0600108 modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
109 break;
110 default:
111 dev_err(dev, "Unsupported PHY mode\n");
112 return -EINVAL;
113 }
114
115 /* Get PHY syscon */
116 ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL,
117 SOCFPGA_XGMAC_SYSCON_ARG_COUNT,
118 0, &args);
119
120 if (ret) {
121 dev_err(dev, "Failed to get syscon: %d\n", ret);
122 return ret;
123 }
124
125 if (args.args_count != SOCFPGA_XGMAC_SYSCON_ARG_COUNT) {
126 dev_err(dev, "Invalid number of syscon args\n");
127 return -EINVAL;
128 }
129
130 reg_map = syscon_node_to_regmap(args.node);
131 if (IS_ERR(reg_map)) {
132 ret = PTR_ERR(reg_map);
133 dev_err(dev, "Failed to get reg_map: %d\n", ret);
134 return ret;
135 }
136
137 range = regmap_get_range(reg_map, 0);
138 if (!range) {
139 dev_err(dev, "Failed to get reg_map: %d\n", ret);
140 return -ENOMEM;
141 }
142
143 xgmac->syscon_phy = range + args.args[0];
144 xgmac->syscon_phy_regshift = args.args[1];
145
146 /* Get Reset Bulk */
147 ret = reset_get_bulk(dev, &xgmac->reset_bulk);
148 if (ret) {
149 dev_err(dev, "Failed to get reset: %d\n", ret);
150 return ret;
151 }
152
153 ret = reset_assert_bulk(&xgmac->reset_bulk);
154 if (ret) {
155 dev_err(dev, "XGMAC failed to assert reset: %d\n", ret);
156 return ret;
157 }
158
159 ret = dwxgmac_socfpga_do_setphy(dev, modereg);
160 if (ret)
161 return ret;
162
163 ret = reset_deassert_bulk(&xgmac->reset_bulk);
164 if (ret) {
165 dev_err(dev, "XGMAC failed to de-assert reset: %d\n", ret);
166 return ret;
167 }
168
169 ret = clk_get_by_name(dev, "stmmaceth", &xgmac->clk_common);
170 if (ret) {
171 pr_err("clk_get_by_name(stmmaceth) failed: %d", ret);
172 goto err_probe;
173 }
174 return 0;
175
176err_probe:
177 debug("%s: returns %d\n", __func__, ret);
178 return ret;
179}
180
181static int xgmac_get_enetaddr_socfpga(struct udevice *dev)
182{
183 struct eth_pdata *pdata = dev_get_plat(dev);
184 struct xgmac_priv *xgmac = dev_get_priv(dev);
185 u32 hi_addr, lo_addr;
186
187 debug("%s(dev=%p):\n", __func__, dev);
188
189 /* Read the MAC Address from the hardawre */
190 hi_addr = readl(&xgmac->mac_regs->address0_high);
191 lo_addr = readl(&xgmac->mac_regs->address0_low);
192
193 pdata->enetaddr[0] = lo_addr & 0xff;
194 pdata->enetaddr[1] = (lo_addr >> 8) & 0xff;
195 pdata->enetaddr[2] = (lo_addr >> 16) & 0xff;
196 pdata->enetaddr[3] = (lo_addr >> 24) & 0xff;
197 pdata->enetaddr[4] = hi_addr & 0xff;
198 pdata->enetaddr[5] = (hi_addr >> 8) & 0xff;
199
200 return !is_valid_ethaddr(pdata->enetaddr);
201}
202
203static int xgmac_start_resets_socfpga(struct udevice *dev)
204{
205 struct xgmac_priv *xgmac = dev_get_priv(dev);
206 int ret;
207
208 debug("%s(dev=%p):\n", __func__, dev);
209
210 ret = reset_assert_bulk(&xgmac->reset_bulk);
211 if (ret < 0) {
212 pr_err("xgmac reset assert failed: %d", ret);
213 return ret;
214 }
215
216 udelay(2);
217
218 ret = reset_deassert_bulk(&xgmac->reset_bulk);
219 if (ret < 0) {
220 pr_err("xgmac reset de-assert failed: %d", ret);
221 return ret;
222 }
223
224 return 0;
225}
226
227static struct xgmac_ops xgmac_socfpga_ops = {
228 .xgmac_inval_desc = xgmac_inval_desc_generic,
229 .xgmac_flush_desc = xgmac_flush_desc_generic,
230 .xgmac_inval_buffer = xgmac_inval_buffer_generic,
231 .xgmac_flush_buffer = xgmac_flush_buffer_generic,
232 .xgmac_probe_resources = xgmac_probe_resources_socfpga,
233 .xgmac_remove_resources = xgmac_null_ops,
234 .xgmac_stop_resets = xgmac_null_ops,
235 .xgmac_start_resets = xgmac_start_resets_socfpga,
236 .xgmac_stop_clks = xgmac_null_ops,
237 .xgmac_start_clks = xgmac_null_ops,
238 .xgmac_calibrate_pads = xgmac_null_ops,
239 .xgmac_disable_calibration = xgmac_null_ops,
240 .xgmac_get_enetaddr = xgmac_get_enetaddr_socfpga,
241};
242
243struct xgmac_config __maybe_unused xgmac_socfpga_config = {
244 .reg_access_always_ok = false,
245 .swr_wait = 50,
246 .config_mac = XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
247 .config_mac_mdio = XGMAC_MAC_MDIO_ADDRESS_CR_350_400,
248 .axi_bus_width = XGMAC_AXI_WIDTH_64,
249 .interface = dev_read_phy_mode,
250 .ops = &xgmac_socfpga_ops
251};