blob: d9ace435ee2b65871c97dec52755f569622aa689 [file] [log] [blame]
Yanhong Wang736733b2023-06-15 17:36:43 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2023 StarFive Technology Co., Ltd.
4 * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
5 */
6
Yanhong Wang736733b2023-06-15 17:36:43 +08007#include <asm/cache.h>
8#include <asm/gpio.h>
9#include <clk.h>
10#include <dm.h>
11#include <eth_phy.h>
12#include <net.h>
13#include <regmap.h>
14#include <reset.h>
15#include <syscon.h>
16
17#include "dwc_eth_qos.h"
18
19#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1
20#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4
21#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U
22
23struct starfive_platform_data {
24 struct regmap *regmap;
25 struct reset_ctl_bulk resets;
26 struct clk_bulk clks;
27 phy_interface_t interface;
28 u32 offset;
29 u32 shift;
30 bool tx_use_rgmii_clk;
31};
32
33static int eqos_interface_init_jh7110(struct udevice *dev)
34{
35 struct eth_pdata *pdata = dev_get_plat(dev);
36 struct starfive_platform_data *data = pdata->priv_pdata;
37 struct ofnode_phandle_args args;
38 unsigned int mode;
39 int ret;
40
41 switch (data->interface) {
42 case PHY_INTERFACE_MODE_RMII:
43 mode = STARFIVE_DWMAC_PHY_INFT_RMII;
44 break;
45
46 case PHY_INTERFACE_MODE_RGMII:
47 case PHY_INTERFACE_MODE_RGMII_ID:
48 mode = STARFIVE_DWMAC_PHY_INFT_RGMII;
49 break;
50
51 default:
52 return -EINVAL;
53 }
54
55 ret = dev_read_phandle_with_args(dev, "starfive,syscon", NULL,
56 2, 0, &args);
57 if (ret)
58 return ret;
59
60 if (args.args_count != 2)
61 return -EINVAL;
62
63 data->offset = args.args[0];
64 data->shift = args.args[1];
65 data->regmap = syscon_regmap_lookup_by_phandle(dev, "starfive,syscon");
66 if (IS_ERR(data->regmap)) {
67 ret = PTR_ERR(data->regmap);
68 pr_err("Failed to get regmap: %d\n", ret);
69 return ret;
70 }
71
72 return regmap_update_bits(data->regmap, data->offset,
73 STARFIVE_DWMAC_PHY_INFT_FIELD << data->shift,
74 mode << data->shift);
75}
76
77static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev)
78{
79 struct eqos_priv *eqos = dev_get_priv(dev);
80 struct eth_pdata *pdata = dev_get_plat(dev);
81 struct starfive_platform_data *data = pdata->priv_pdata;
82 struct clk *pclk, *c;
83 ulong rate;
84 int ret;
85
86 /* Generally, the rgmii_tx clock is provided by the internal clock,
87 * which needs to match the corresponding clock frequency according
88 * to different speeds. If the rgmii_tx clock is provided by the
89 * external rgmii_rxin, there is no need to configure the clock
90 * internally, because rgmii_rxin will be adaptively adjusted.
91 */
92 if (data->tx_use_rgmii_clk)
93 return 0;
94
95 switch (eqos->phy->speed) {
96 case SPEED_1000:
97 rate = 125 * 1000 * 1000;
98 break;
99 case SPEED_100:
100 rate = 25 * 1000 * 1000;
101 break;
102 case SPEED_10:
103 rate = 2.5 * 1000 * 1000;
104 break;
105 default:
106 pr_err("invalid speed %d", eqos->phy->speed);
107 return -EINVAL;
108 }
109
110 /* eqos->clk_tx clock has no set rate operation, so just set the parent
111 * clock rate directly
112 */
113 ret = clk_get_by_id(eqos->clk_tx.id, &c);
114 if (ret)
115 return ret;
116
117 pclk = clk_get_parent(c);
118 if (pclk) {
119 ret = clk_set_rate(pclk, rate);
120 if (ret < 0) {
121 pr_err("jh7110 (clk_tx, %lu) failed: %d", rate, ret);
122 return ret;
123 }
124 }
125
126 return 0;
127}
128
129static ulong eqos_get_tick_clk_rate_jh7110(struct udevice *dev)
130{
131 struct eqos_priv *eqos = dev_get_priv(dev);
132
133 return clk_get_rate(&eqos->clk_tx);
134}
135
136static int eqos_start_clks_jh7110(struct udevice *dev)
137{
138 struct eth_pdata *pdata = dev_get_plat(dev);
139 struct starfive_platform_data *data = pdata->priv_pdata;
140
141 return clk_enable_bulk(&data->clks);
142}
143
144static int eqos_stop_clks_jh7110(struct udevice *dev)
145{
146 struct eth_pdata *pdata = dev_get_plat(dev);
147 struct starfive_platform_data *data = pdata->priv_pdata;
148
149 return clk_disable_bulk(&data->clks);
150}
151
152static int eqos_start_resets_jh7110(struct udevice *dev)
153{
154 struct eth_pdata *pdata = dev_get_plat(dev);
155 struct starfive_platform_data *data = pdata->priv_pdata;
156
157 return reset_deassert_bulk(&data->resets);
158}
159
160static int eqos_stop_resets_jh7110(struct udevice *dev)
161{
162 struct eth_pdata *pdata = dev_get_plat(dev);
163 struct starfive_platform_data *data = pdata->priv_pdata;
164
165 return reset_assert_bulk(&data->resets);
166}
167
168static int eqos_remove_resources_jh7110(struct udevice *dev)
169{
170 struct eth_pdata *pdata = dev_get_plat(dev);
171 struct starfive_platform_data *data = pdata->priv_pdata;
172
173 reset_assert_bulk(&data->resets);
174 clk_disable_bulk(&data->clks);
175
176 return 0;
177}
178
179static int eqos_probe_resources_jh7110(struct udevice *dev)
180{
181 struct eqos_priv *eqos = dev_get_priv(dev);
182 struct eth_pdata *pdata = dev_get_plat(dev);
183 struct starfive_platform_data *data;
184 int ret;
185
Philip Oberfichtnerbeabef62024-08-02 11:25:37 +0200186 ret = eqos_get_base_addr_dt(dev);
187 if (ret) {
188 pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
189 return ret;
190 }
191
Yanhong Wang736733b2023-06-15 17:36:43 +0800192 data = calloc(1, sizeof(struct starfive_platform_data));
193 if (!data)
194 return -ENOMEM;
195
196 pdata->priv_pdata = data;
197 data->interface = eqos->config->interface(dev);
198 if (data->interface == PHY_INTERFACE_MODE_NA) {
199 pr_err("Invalid PHY interface\n");
200 return -EINVAL;
201 }
202
203 ret = reset_get_bulk(dev, &data->resets);
204 if (ret < 0)
205 return ret;
206
207 ret = clk_get_bulk(dev, &data->clks);
208 if (ret < 0)
209 return ret;
210
211 ret = clk_get_by_name(dev, "gtx", &eqos->clk_tx);
212 if (ret)
213 return ret;
214
215 data->tx_use_rgmii_clk = dev_read_bool(dev, "starfive,tx-use-rgmii-clk");
216
217 return eqos_interface_init_jh7110(dev);
218}
219
220static struct eqos_ops eqos_jh7110_ops = {
221 .eqos_inval_desc = eqos_inval_desc_generic,
222 .eqos_flush_desc = eqos_flush_desc_generic,
223 .eqos_inval_buffer = eqos_inval_buffer_generic,
224 .eqos_flush_buffer = eqos_flush_buffer_generic,
225 .eqos_probe_resources = eqos_probe_resources_jh7110,
226 .eqos_remove_resources = eqos_remove_resources_jh7110,
227 .eqos_stop_resets = eqos_stop_resets_jh7110,
228 .eqos_start_resets = eqos_start_resets_jh7110,
229 .eqos_stop_clks = eqos_stop_clks_jh7110,
230 .eqos_start_clks = eqos_start_clks_jh7110,
231 .eqos_calibrate_pads = eqos_null_ops,
232 .eqos_disable_calibration = eqos_null_ops,
233 .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_jh7110,
234 .eqos_get_enetaddr = eqos_null_ops,
235 .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_jh7110
236};
237
238/* mdio_wait: There is no need to wait after setting the MAC_MDIO_Address register
239 * swr_wait: Software reset bit must be read at least 4 CSR clock cycles
240 * after it is written to 1.
241 * config_mac: Enable rx queue to DCB mode.
242 * config_mac_mdio: CSR clock range is 250-300 Mhz.
243 * axi_bus_width: The width of the data bus is 64 bit.
244 */
245struct eqos_config __maybe_unused eqos_jh7110_config = {
246 .reg_access_always_ok = false,
247 .mdio_wait = 0,
248 .swr_wait = 4,
249 .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
250 .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
251 .axi_bus_width = EQOS_AXI_WIDTH_64,
252 .interface = dev_read_phy_mode,
253 .ops = &eqos_jh7110_ops
254};