blob: 7545026b158eb8e45fa196f2c4e615701eadd92c [file] [log] [blame]
Marek Vasut426ca622024-03-26 13:07:22 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2024, Marek Vasut <marex@denx.de>
4 *
5 * This is code moved from drivers/net/dwc_eth_qos.c , which is:
6 * Copyright (c) 2016, NVIDIA CORPORATION.
7 */
8
9#include <common.h>
10#include <asm/cache.h>
11#include <asm/gpio.h>
12#include <asm/io.h>
13#include <clk.h>
14#include <cpu_func.h>
15#include <dm.h>
16#include <dm/device_compat.h>
17#include <errno.h>
18#include <eth_phy.h>
19#include <log.h>
20#include <malloc.h>
21#include <memalign.h>
22#include <miiphy.h>
23#include <net.h>
24#include <netdev.h>
25#include <phy.h>
26#include <reset.h>
Marek Vasut7595bfc2024-03-26 13:07:24 +010027#include <syscon.h>
Marek Vasut426ca622024-03-26 13:07:22 +010028#include <wait_bit.h>
Marek Vasut577f46b2024-03-26 13:07:26 +010029#include <linux/bitfield.h>
Marek Vasut426ca622024-03-26 13:07:22 +010030#include <linux/delay.h>
31
32#include "dwc_eth_qos.h"
33
Marek Vasut7595bfc2024-03-26 13:07:24 +010034/* SYSCFG registers */
35#define SYSCFG_PMCSETR 0x04
36#define SYSCFG_PMCCLRR 0x44
37
38#define SYSCFG_PMCSETR_ETH_CLK_SEL BIT(16)
39#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL BIT(17)
40
41#define SYSCFG_PMCSETR_ETH_SELMII BIT(20)
42
43#define SYSCFG_PMCSETR_ETH_SEL_MASK GENMASK(23, 21)
Marek Vasut577f46b2024-03-26 13:07:26 +010044#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII 0x0
45#define SYSCFG_PMCSETR_ETH_SEL_RGMII 0x1
46#define SYSCFG_PMCSETR_ETH_SEL_RMII 0x4
Marek Vasut7595bfc2024-03-26 13:07:24 +010047
Marek Vasut426ca622024-03-26 13:07:22 +010048static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
49{
Marek Vasutb14101c2024-03-26 13:07:25 +010050 struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
51
52 if (!CONFIG_IS_ENABLED(CLK))
53 return 0;
Marek Vasut426ca622024-03-26 13:07:22 +010054
55 return clk_get_rate(&eqos->clk_master_bus);
Marek Vasut426ca622024-03-26 13:07:22 +010056}
57
58static int eqos_start_clks_stm32(struct udevice *dev)
59{
Marek Vasutb14101c2024-03-26 13:07:25 +010060 struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
Marek Vasut426ca622024-03-26 13:07:22 +010061 int ret;
62
Marek Vasutb14101c2024-03-26 13:07:25 +010063 if (!CONFIG_IS_ENABLED(CLK))
64 return 0;
65
Marek Vasut426ca622024-03-26 13:07:22 +010066 debug("%s(dev=%p):\n", __func__, dev);
67
68 ret = clk_enable(&eqos->clk_master_bus);
69 if (ret < 0) {
70 pr_err("clk_enable(clk_master_bus) failed: %d", ret);
71 goto err;
72 }
73
74 ret = clk_enable(&eqos->clk_rx);
75 if (ret < 0) {
76 pr_err("clk_enable(clk_rx) failed: %d", ret);
77 goto err_disable_clk_master_bus;
78 }
79
80 ret = clk_enable(&eqos->clk_tx);
81 if (ret < 0) {
82 pr_err("clk_enable(clk_tx) failed: %d", ret);
83 goto err_disable_clk_rx;
84 }
85
86 if (clk_valid(&eqos->clk_ck) && !eqos->clk_ck_enabled) {
87 ret = clk_enable(&eqos->clk_ck);
88 if (ret < 0) {
89 pr_err("clk_enable(clk_ck) failed: %d", ret);
90 goto err_disable_clk_tx;
91 }
92 eqos->clk_ck_enabled = true;
93 }
Marek Vasut426ca622024-03-26 13:07:22 +010094
95 debug("%s: OK\n", __func__);
96 return 0;
97
Marek Vasut426ca622024-03-26 13:07:22 +010098err_disable_clk_tx:
99 clk_disable(&eqos->clk_tx);
100err_disable_clk_rx:
101 clk_disable(&eqos->clk_rx);
102err_disable_clk_master_bus:
103 clk_disable(&eqos->clk_master_bus);
104err:
105 debug("%s: FAILED: %d\n", __func__, ret);
106 return ret;
Marek Vasut426ca622024-03-26 13:07:22 +0100107}
108
109static int eqos_stop_clks_stm32(struct udevice *dev)
110{
Marek Vasutb14101c2024-03-26 13:07:25 +0100111 struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
112
113 if (!CONFIG_IS_ENABLED(CLK))
114 return 0;
Marek Vasut426ca622024-03-26 13:07:22 +0100115
116 debug("%s(dev=%p):\n", __func__, dev);
117
118 clk_disable(&eqos->clk_tx);
119 clk_disable(&eqos->clk_rx);
120 clk_disable(&eqos->clk_master_bus);
Marek Vasut426ca622024-03-26 13:07:22 +0100121
122 debug("%s: OK\n", __func__);
123 return 0;
124}
125
Marek Vasut7595bfc2024-03-26 13:07:24 +0100126static int eqos_probe_syscfg_stm32(struct udevice *dev,
127 phy_interface_t interface_type)
128{
129 bool eth_ref_clk_sel_reg = false;
130 bool eth_clk_sel_reg = false;
131 u8 *syscfg;
132 u32 value;
133
134 /* Gigabit Ethernet 125MHz clock selection. */
135 eth_clk_sel_reg = dev_read_bool(dev, "st,eth-clk-sel");
136
137 /* Ethernet 50Mhz RMII clock selection */
138 eth_ref_clk_sel_reg = dev_read_bool(dev, "st,eth-ref-clk-sel");
139
140 syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
141 if (!syscfg)
142 return -ENODEV;
143
144 switch (interface_type) {
145 case PHY_INTERFACE_MODE_MII:
Marek Vasut577f46b2024-03-26 13:07:26 +0100146 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
147 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
148 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100149 log_debug("PHY_INTERFACE_MODE_MII\n");
150 break;
151 case PHY_INTERFACE_MODE_GMII:
Marek Vasut577f46b2024-03-26 13:07:26 +0100152 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
153 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100154 if (eth_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100155 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100156 log_debug("PHY_INTERFACE_MODE_GMII\n");
157 break;
158 case PHY_INTERFACE_MODE_RMII:
Marek Vasut577f46b2024-03-26 13:07:26 +0100159 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
160 SYSCFG_PMCSETR_ETH_SEL_RMII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100161 if (eth_ref_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100162 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100163 log_debug("PHY_INTERFACE_MODE_RMII\n");
164 break;
165 case PHY_INTERFACE_MODE_RGMII:
166 case PHY_INTERFACE_MODE_RGMII_ID:
167 case PHY_INTERFACE_MODE_RGMII_RXID:
168 case PHY_INTERFACE_MODE_RGMII_TXID:
Marek Vasut577f46b2024-03-26 13:07:26 +0100169 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
170 SYSCFG_PMCSETR_ETH_SEL_RGMII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100171 if (eth_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100172 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100173 log_debug("PHY_INTERFACE_MODE_RGMII\n");
174 break;
175 default:
176 log_debug("Do not manage %d interface\n",
177 interface_type);
178 /* Do not manage others interfaces */
179 return -EINVAL;
180 }
181
182 /* clear and set ETH configuration bits */
183 writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
184 SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
185 syscfg + SYSCFG_PMCCLRR);
186 writel(value, syscfg + SYSCFG_PMCSETR);
187
188 return 0;
189}
190
Marek Vasut426ca622024-03-26 13:07:22 +0100191static int eqos_probe_resources_stm32(struct udevice *dev)
192{
193 struct eqos_priv *eqos = dev_get_priv(dev);
Marek Vasut426ca622024-03-26 13:07:22 +0100194 phy_interface_t interface;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100195 int ret;
Marek Vasut426ca622024-03-26 13:07:22 +0100196
197 debug("%s(dev=%p):\n", __func__, dev);
198
199 interface = eqos->config->interface(dev);
200
201 if (interface == PHY_INTERFACE_MODE_NA) {
202 pr_err("Invalid PHY interface\n");
203 return -EINVAL;
204 }
205
Marek Vasut7595bfc2024-03-26 13:07:24 +0100206 ret = eqos_probe_syscfg_stm32(dev, interface);
Marek Vasut426ca622024-03-26 13:07:22 +0100207 if (ret)
208 return -EINVAL;
209
210 ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
211 if (ret) {
212 pr_err("clk_get_by_name(master_bus) failed: %d", ret);
213 goto err_probe;
214 }
215
216 ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
217 if (ret) {
218 pr_err("clk_get_by_name(rx) failed: %d", ret);
219 goto err_probe;
220 }
221
222 ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
223 if (ret) {
224 pr_err("clk_get_by_name(tx) failed: %d", ret);
225 goto err_probe;
226 }
227
228 /* Get ETH_CLK clocks (optional) */
229 ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
230 if (ret)
231 pr_warn("No phy clock provided %d", ret);
232
233 debug("%s: OK\n", __func__);
234 return 0;
235
236err_probe:
237
238 debug("%s: returns %d\n", __func__, ret);
239 return ret;
240}
241
242static int eqos_remove_resources_stm32(struct udevice *dev)
243{
244 debug("%s(dev=%p):\n", __func__, dev);
245
246 return 0;
247}
248
249static struct eqos_ops eqos_stm32_ops = {
250 .eqos_inval_desc = eqos_inval_desc_generic,
251 .eqos_flush_desc = eqos_flush_desc_generic,
252 .eqos_inval_buffer = eqos_inval_buffer_generic,
253 .eqos_flush_buffer = eqos_flush_buffer_generic,
254 .eqos_probe_resources = eqos_probe_resources_stm32,
255 .eqos_remove_resources = eqos_remove_resources_stm32,
256 .eqos_stop_resets = eqos_null_ops,
257 .eqos_start_resets = eqos_null_ops,
258 .eqos_stop_clks = eqos_stop_clks_stm32,
259 .eqos_start_clks = eqos_start_clks_stm32,
260 .eqos_calibrate_pads = eqos_null_ops,
261 .eqos_disable_calibration = eqos_null_ops,
262 .eqos_set_tx_clk_speed = eqos_null_ops,
263 .eqos_get_enetaddr = eqos_null_ops,
264 .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32
265};
266
Marek Vasut944ba372024-03-26 13:07:23 +0100267struct eqos_config __maybe_unused eqos_stm32mp15_config = {
Marek Vasut426ca622024-03-26 13:07:22 +0100268 .reg_access_always_ok = false,
269 .mdio_wait = 10000,
270 .swr_wait = 50,
271 .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
272 .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
273 .axi_bus_width = EQOS_AXI_WIDTH_64,
274 .interface = dev_read_phy_mode,
275 .ops = &eqos_stm32_ops
276};