blob: 72f65f80540188d15245b7daa11e3095f592d527 [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 Vasut5a1640e2024-03-26 13:07:28 +010066 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +010067
68 ret = clk_enable(&eqos->clk_master_bus);
69 if (ret < 0) {
Marek Vasut5a1640e2024-03-26 13:07:28 +010070 dev_err(dev, "clk_enable(clk_master_bus) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +010071 goto err;
72 }
73
74 ret = clk_enable(&eqos->clk_rx);
75 if (ret < 0) {
Marek Vasut5a1640e2024-03-26 13:07:28 +010076 dev_err(dev, "clk_enable(clk_rx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +010077 goto err_disable_clk_master_bus;
78 }
79
80 ret = clk_enable(&eqos->clk_tx);
81 if (ret < 0) {
Marek Vasut5a1640e2024-03-26 13:07:28 +010082 dev_err(dev, "clk_enable(clk_tx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +010083 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) {
Marek Vasut5a1640e2024-03-26 13:07:28 +010089 dev_err(dev, "clk_enable(clk_ck) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +010090 goto err_disable_clk_tx;
91 }
92 eqos->clk_ck_enabled = true;
93 }
Marek Vasut426ca622024-03-26 13:07:22 +010094
Marek Vasut5a1640e2024-03-26 13:07:28 +010095 dev_dbg(dev, "%s: OK\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +010096 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:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100105 dev_dbg(dev, "%s: FAILED: %d\n", __func__, ret);
106
Marek Vasut426ca622024-03-26 13:07:22 +0100107 return ret;
Marek Vasut426ca622024-03-26 13:07:22 +0100108}
109
110static int eqos_stop_clks_stm32(struct udevice *dev)
111{
Marek Vasutb14101c2024-03-26 13:07:25 +0100112 struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
113
114 if (!CONFIG_IS_ENABLED(CLK))
115 return 0;
Marek Vasut426ca622024-03-26 13:07:22 +0100116
Marek Vasut5a1640e2024-03-26 13:07:28 +0100117 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +0100118
119 clk_disable(&eqos->clk_tx);
120 clk_disable(&eqos->clk_rx);
121 clk_disable(&eqos->clk_master_bus);
Marek Vasut426ca622024-03-26 13:07:22 +0100122
Marek Vasut5a1640e2024-03-26 13:07:28 +0100123 dev_dbg(dev, "%s: OK\n", __func__);
124
Marek Vasut426ca622024-03-26 13:07:22 +0100125 return 0;
126}
127
Marek Vasut7595bfc2024-03-26 13:07:24 +0100128static int eqos_probe_syscfg_stm32(struct udevice *dev,
129 phy_interface_t interface_type)
130{
131 bool eth_ref_clk_sel_reg = false;
132 bool eth_clk_sel_reg = false;
133 u8 *syscfg;
134 u32 value;
135
136 /* Gigabit Ethernet 125MHz clock selection. */
137 eth_clk_sel_reg = dev_read_bool(dev, "st,eth-clk-sel");
138
139 /* Ethernet 50Mhz RMII clock selection */
140 eth_ref_clk_sel_reg = dev_read_bool(dev, "st,eth-ref-clk-sel");
141
142 syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
143 if (!syscfg)
144 return -ENODEV;
145
146 switch (interface_type) {
147 case PHY_INTERFACE_MODE_MII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100148 dev_dbg(dev, "PHY_INTERFACE_MODE_MII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100149 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
150 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
151 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100152 break;
153 case PHY_INTERFACE_MODE_GMII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100154 dev_dbg(dev, "PHY_INTERFACE_MODE_GMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100155 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
156 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100157 if (eth_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100158 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100159 break;
160 case PHY_INTERFACE_MODE_RMII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100161 dev_dbg(dev, "PHY_INTERFACE_MODE_RMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100162 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
163 SYSCFG_PMCSETR_ETH_SEL_RMII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100164 if (eth_ref_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100165 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100166 break;
167 case PHY_INTERFACE_MODE_RGMII:
168 case PHY_INTERFACE_MODE_RGMII_ID:
169 case PHY_INTERFACE_MODE_RGMII_RXID:
170 case PHY_INTERFACE_MODE_RGMII_TXID:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100171 dev_dbg(dev, "PHY_INTERFACE_MODE_RGMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100172 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
173 SYSCFG_PMCSETR_ETH_SEL_RGMII);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100174 if (eth_clk_sel_reg)
Marek Vasut577f46b2024-03-26 13:07:26 +0100175 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100176 break;
177 default:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100178 dev_dbg(dev, "Do not manage %d interface\n",
179 interface_type);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100180 /* Do not manage others interfaces */
181 return -EINVAL;
182 }
183
184 /* clear and set ETH configuration bits */
185 writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
186 SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
187 syscfg + SYSCFG_PMCCLRR);
188 writel(value, syscfg + SYSCFG_PMCSETR);
189
190 return 0;
191}
192
Marek Vasut426ca622024-03-26 13:07:22 +0100193static int eqos_probe_resources_stm32(struct udevice *dev)
194{
195 struct eqos_priv *eqos = dev_get_priv(dev);
Marek Vasut426ca622024-03-26 13:07:22 +0100196 phy_interface_t interface;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100197 int ret;
Marek Vasut426ca622024-03-26 13:07:22 +0100198
Marek Vasut5a1640e2024-03-26 13:07:28 +0100199 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +0100200
201 interface = eqos->config->interface(dev);
202
203 if (interface == PHY_INTERFACE_MODE_NA) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100204 dev_err(dev, "Invalid PHY interface\n");
Marek Vasut426ca622024-03-26 13:07:22 +0100205 return -EINVAL;
206 }
207
Marek Vasut7595bfc2024-03-26 13:07:24 +0100208 ret = eqos_probe_syscfg_stm32(dev, interface);
Marek Vasut426ca622024-03-26 13:07:22 +0100209 if (ret)
210 return -EINVAL;
211
212 ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
213 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100214 dev_err(dev, "clk_get_by_name(master_bus) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100215 goto err_probe;
216 }
217
218 ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
219 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100220 dev_err(dev, "clk_get_by_name(rx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100221 goto err_probe;
222 }
223
224 ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
225 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100226 dev_err(dev, "clk_get_by_name(tx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100227 goto err_probe;
228 }
229
230 /* Get ETH_CLK clocks (optional) */
231 ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
232 if (ret)
Marek Vasut5a1640e2024-03-26 13:07:28 +0100233 dev_warn(dev, "No phy clock provided %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100234
Marek Vasut5a1640e2024-03-26 13:07:28 +0100235 dev_dbg(dev, "%s: OK\n", __func__);
236
Marek Vasut426ca622024-03-26 13:07:22 +0100237 return 0;
238
239err_probe:
240
Marek Vasut5a1640e2024-03-26 13:07:28 +0100241 dev_dbg(dev, "%s: returns %d\n", __func__, ret);
242
Marek Vasut426ca622024-03-26 13:07:22 +0100243 return ret;
244}
245
246static int eqos_remove_resources_stm32(struct udevice *dev)
247{
Marek Vasut5a1640e2024-03-26 13:07:28 +0100248 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +0100249
250 return 0;
251}
252
253static struct eqos_ops eqos_stm32_ops = {
254 .eqos_inval_desc = eqos_inval_desc_generic,
255 .eqos_flush_desc = eqos_flush_desc_generic,
256 .eqos_inval_buffer = eqos_inval_buffer_generic,
257 .eqos_flush_buffer = eqos_flush_buffer_generic,
258 .eqos_probe_resources = eqos_probe_resources_stm32,
259 .eqos_remove_resources = eqos_remove_resources_stm32,
260 .eqos_stop_resets = eqos_null_ops,
261 .eqos_start_resets = eqos_null_ops,
262 .eqos_stop_clks = eqos_stop_clks_stm32,
263 .eqos_start_clks = eqos_start_clks_stm32,
264 .eqos_calibrate_pads = eqos_null_ops,
265 .eqos_disable_calibration = eqos_null_ops,
266 .eqos_set_tx_clk_speed = eqos_null_ops,
267 .eqos_get_enetaddr = eqos_null_ops,
268 .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32
269};
270
Marek Vasut944ba372024-03-26 13:07:23 +0100271struct eqos_config __maybe_unused eqos_stm32mp15_config = {
Marek Vasut426ca622024-03-26 13:07:22 +0100272 .reg_access_always_ok = false,
273 .mdio_wait = 10000,
274 .swr_wait = 50,
275 .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
276 .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
277 .axi_bus_width = EQOS_AXI_WIDTH_64,
278 .interface = dev_read_phy_mode,
279 .ops = &eqos_stm32_ops
280};