]>
Commit | Line | Data |
---|---|---|
03de305e TR |
1 | // 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 | ||
32 | static int dwxgmac_socfpga_do_setphy(struct udevice *dev, u32 modereg) | |
33 | { | |
34 | struct xgmac_priv *xgmac = dev_get_priv(dev); | |
35 | int ret; | |
36 | ||
37 | u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << | |
38 | xgmac->syscon_phy_regshift; | |
39 | ||
40 | if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) { | |
41 | u32 index = ((u64)xgmac->syscon_phy - socfpga_get_sysmgr_addr() - | |
42 | SYSMGR_SOC64_EMAC0) >> 2; | |
43 | ||
44 | u32 id = SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 + index; | |
45 | ||
46 | ret = socfpga_secure_reg_update32(id, | |
47 | modemask, | |
48 | modereg << | |
49 | xgmac->syscon_phy_regshift); | |
50 | if (ret) { | |
51 | dev_err(dev, "Failed to set PHY register via SMC call\n"); | |
52 | return ret; | |
53 | } | |
54 | ||
55 | } else { | |
56 | clrsetbits_le32(xgmac->phy, modemask, modereg); | |
57 | } | |
58 | ||
59 | return 0; | |
60 | } | |
61 | ||
62 | static int xgmac_probe_resources_socfpga(struct udevice *dev) | |
63 | { | |
64 | struct xgmac_priv *xgmac = dev_get_priv(dev); | |
65 | struct regmap *reg_map; | |
66 | struct ofnode_phandle_args args; | |
67 | void *range; | |
68 | phy_interface_t interface; | |
69 | int ret; | |
70 | u32 modereg; | |
71 | ||
72 | interface = xgmac->config->interface(dev); | |
73 | ||
74 | switch (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 | /* Get PHY syscon */ | |
91 | ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL, | |
92 | SOCFPGA_XGMAC_SYSCON_ARG_COUNT, | |
93 | 0, &args); | |
94 | ||
95 | if (ret) { | |
96 | dev_err(dev, "Failed to get syscon: %d\n", ret); | |
97 | return ret; | |
98 | } | |
99 | ||
100 | if (args.args_count != SOCFPGA_XGMAC_SYSCON_ARG_COUNT) { | |
101 | dev_err(dev, "Invalid number of syscon args\n"); | |
102 | return -EINVAL; | |
103 | } | |
104 | ||
105 | reg_map = syscon_node_to_regmap(args.node); | |
106 | if (IS_ERR(reg_map)) { | |
107 | ret = PTR_ERR(reg_map); | |
108 | dev_err(dev, "Failed to get reg_map: %d\n", ret); | |
109 | return ret; | |
110 | } | |
111 | ||
112 | range = regmap_get_range(reg_map, 0); | |
113 | if (!range) { | |
114 | dev_err(dev, "Failed to get reg_map: %d\n", ret); | |
115 | return -ENOMEM; | |
116 | } | |
117 | ||
118 | xgmac->syscon_phy = range + args.args[0]; | |
119 | xgmac->syscon_phy_regshift = args.args[1]; | |
120 | ||
121 | /* Get Reset Bulk */ | |
122 | ret = reset_get_bulk(dev, &xgmac->reset_bulk); | |
123 | if (ret) { | |
124 | dev_err(dev, "Failed to get reset: %d\n", ret); | |
125 | return ret; | |
126 | } | |
127 | ||
128 | ret = reset_assert_bulk(&xgmac->reset_bulk); | |
129 | if (ret) { | |
130 | dev_err(dev, "XGMAC failed to assert reset: %d\n", ret); | |
131 | return ret; | |
132 | } | |
133 | ||
134 | ret = dwxgmac_socfpga_do_setphy(dev, modereg); | |
135 | if (ret) | |
136 | return ret; | |
137 | ||
138 | ret = reset_deassert_bulk(&xgmac->reset_bulk); | |
139 | if (ret) { | |
140 | dev_err(dev, "XGMAC failed to de-assert reset: %d\n", ret); | |
141 | return ret; | |
142 | } | |
143 | ||
144 | ret = clk_get_by_name(dev, "stmmaceth", &xgmac->clk_common); | |
145 | if (ret) { | |
146 | pr_err("clk_get_by_name(stmmaceth) failed: %d", ret); | |
147 | goto err_probe; | |
148 | } | |
149 | return 0; | |
150 | ||
151 | err_probe: | |
152 | debug("%s: returns %d\n", __func__, ret); | |
153 | return ret; | |
154 | } | |
155 | ||
156 | static int xgmac_get_enetaddr_socfpga(struct udevice *dev) | |
157 | { | |
158 | struct eth_pdata *pdata = dev_get_plat(dev); | |
159 | struct xgmac_priv *xgmac = dev_get_priv(dev); | |
160 | u32 hi_addr, lo_addr; | |
161 | ||
162 | debug("%s(dev=%p):\n", __func__, dev); | |
163 | ||
164 | /* Read the MAC Address from the hardawre */ | |
165 | hi_addr = readl(&xgmac->mac_regs->address0_high); | |
166 | lo_addr = readl(&xgmac->mac_regs->address0_low); | |
167 | ||
168 | pdata->enetaddr[0] = lo_addr & 0xff; | |
169 | pdata->enetaddr[1] = (lo_addr >> 8) & 0xff; | |
170 | pdata->enetaddr[2] = (lo_addr >> 16) & 0xff; | |
171 | pdata->enetaddr[3] = (lo_addr >> 24) & 0xff; | |
172 | pdata->enetaddr[4] = hi_addr & 0xff; | |
173 | pdata->enetaddr[5] = (hi_addr >> 8) & 0xff; | |
174 | ||
175 | return !is_valid_ethaddr(pdata->enetaddr); | |
176 | } | |
177 | ||
178 | static int xgmac_start_resets_socfpga(struct udevice *dev) | |
179 | { | |
180 | struct xgmac_priv *xgmac = dev_get_priv(dev); | |
181 | int ret; | |
182 | ||
183 | debug("%s(dev=%p):\n", __func__, dev); | |
184 | ||
185 | ret = reset_assert_bulk(&xgmac->reset_bulk); | |
186 | if (ret < 0) { | |
187 | pr_err("xgmac reset assert failed: %d", ret); | |
188 | return ret; | |
189 | } | |
190 | ||
191 | udelay(2); | |
192 | ||
193 | ret = reset_deassert_bulk(&xgmac->reset_bulk); | |
194 | if (ret < 0) { | |
195 | pr_err("xgmac reset de-assert failed: %d", ret); | |
196 | return ret; | |
197 | } | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | static struct xgmac_ops xgmac_socfpga_ops = { | |
203 | .xgmac_inval_desc = xgmac_inval_desc_generic, | |
204 | .xgmac_flush_desc = xgmac_flush_desc_generic, | |
205 | .xgmac_inval_buffer = xgmac_inval_buffer_generic, | |
206 | .xgmac_flush_buffer = xgmac_flush_buffer_generic, | |
207 | .xgmac_probe_resources = xgmac_probe_resources_socfpga, | |
208 | .xgmac_remove_resources = xgmac_null_ops, | |
209 | .xgmac_stop_resets = xgmac_null_ops, | |
210 | .xgmac_start_resets = xgmac_start_resets_socfpga, | |
211 | .xgmac_stop_clks = xgmac_null_ops, | |
212 | .xgmac_start_clks = xgmac_null_ops, | |
213 | .xgmac_calibrate_pads = xgmac_null_ops, | |
214 | .xgmac_disable_calibration = xgmac_null_ops, | |
215 | .xgmac_get_enetaddr = xgmac_get_enetaddr_socfpga, | |
216 | }; | |
217 | ||
218 | struct xgmac_config __maybe_unused xgmac_socfpga_config = { | |
219 | .reg_access_always_ok = false, | |
220 | .swr_wait = 50, | |
221 | .config_mac = XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, | |
222 | .config_mac_mdio = XGMAC_MAC_MDIO_ADDRESS_CR_350_400, | |
223 | .axi_bus_width = XGMAC_AXI_WIDTH_64, | |
224 | .interface = dev_read_phy_mode, | |
225 | .ops = &xgmac_socfpga_ops | |
226 | }; |