blob: 0b13d01346b9c67647c6504a3cd1655f9532383d [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{
Marek Vasute77fa872024-03-26 13:07:29 +0100131 /* Ethernet 50MHz RMII clock selection. */
132 const bool eth_ref_clk_sel = dev_read_bool(dev, "st,eth-ref-clk-sel");
133 /* Gigabit Ethernet 125MHz clock selection. */
134 const bool eth_clk_sel = dev_read_bool(dev, "st,eth-clk-sel");
Marek Vasut7595bfc2024-03-26 13:07:24 +0100135 u8 *syscfg;
136 u32 value;
137
Marek Vasut7595bfc2024-03-26 13:07:24 +0100138 syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
139 if (!syscfg)
140 return -ENODEV;
141
142 switch (interface_type) {
143 case PHY_INTERFACE_MODE_MII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100144 dev_dbg(dev, "PHY_INTERFACE_MODE_MII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100145 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
146 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
147 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100148 break;
149 case PHY_INTERFACE_MODE_GMII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100150 dev_dbg(dev, "PHY_INTERFACE_MODE_GMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100151 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
152 SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
Marek Vasute77fa872024-03-26 13:07:29 +0100153 if (eth_clk_sel)
Marek Vasut577f46b2024-03-26 13:07:26 +0100154 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100155 break;
156 case PHY_INTERFACE_MODE_RMII:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100157 dev_dbg(dev, "PHY_INTERFACE_MODE_RMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100158 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
159 SYSCFG_PMCSETR_ETH_SEL_RMII);
Marek Vasute77fa872024-03-26 13:07:29 +0100160 if (eth_ref_clk_sel)
Marek Vasut577f46b2024-03-26 13:07:26 +0100161 value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100162 break;
163 case PHY_INTERFACE_MODE_RGMII:
164 case PHY_INTERFACE_MODE_RGMII_ID:
165 case PHY_INTERFACE_MODE_RGMII_RXID:
166 case PHY_INTERFACE_MODE_RGMII_TXID:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100167 dev_dbg(dev, "PHY_INTERFACE_MODE_RGMII\n");
Marek Vasut577f46b2024-03-26 13:07:26 +0100168 value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
169 SYSCFG_PMCSETR_ETH_SEL_RGMII);
Marek Vasute77fa872024-03-26 13:07:29 +0100170 if (eth_clk_sel)
Marek Vasut577f46b2024-03-26 13:07:26 +0100171 value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100172 break;
173 default:
Marek Vasut5a1640e2024-03-26 13:07:28 +0100174 dev_dbg(dev, "Do not manage %d interface\n",
175 interface_type);
Marek Vasut7595bfc2024-03-26 13:07:24 +0100176 /* Do not manage others interfaces */
177 return -EINVAL;
178 }
179
180 /* clear and set ETH configuration bits */
181 writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
182 SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
183 syscfg + SYSCFG_PMCCLRR);
184 writel(value, syscfg + SYSCFG_PMCSETR);
185
186 return 0;
187}
188
Marek Vasut426ca622024-03-26 13:07:22 +0100189static int eqos_probe_resources_stm32(struct udevice *dev)
190{
191 struct eqos_priv *eqos = dev_get_priv(dev);
Marek Vasut426ca622024-03-26 13:07:22 +0100192 phy_interface_t interface;
Marek Vasut7595bfc2024-03-26 13:07:24 +0100193 int ret;
Marek Vasut426ca622024-03-26 13:07:22 +0100194
Marek Vasut5a1640e2024-03-26 13:07:28 +0100195 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +0100196
197 interface = eqos->config->interface(dev);
198
199 if (interface == PHY_INTERFACE_MODE_NA) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100200 dev_err(dev, "Invalid PHY interface\n");
Marek Vasut426ca622024-03-26 13:07:22 +0100201 return -EINVAL;
202 }
203
Marek Vasut7595bfc2024-03-26 13:07:24 +0100204 ret = eqos_probe_syscfg_stm32(dev, interface);
Marek Vasut426ca622024-03-26 13:07:22 +0100205 if (ret)
206 return -EINVAL;
207
208 ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
209 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100210 dev_err(dev, "clk_get_by_name(master_bus) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100211 goto err_probe;
212 }
213
214 ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
215 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100216 dev_err(dev, "clk_get_by_name(rx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100217 goto err_probe;
218 }
219
220 ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
221 if (ret) {
Marek Vasut5a1640e2024-03-26 13:07:28 +0100222 dev_err(dev, "clk_get_by_name(tx) failed: %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100223 goto err_probe;
224 }
225
226 /* Get ETH_CLK clocks (optional) */
227 ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
228 if (ret)
Marek Vasut5a1640e2024-03-26 13:07:28 +0100229 dev_warn(dev, "No phy clock provided %d\n", ret);
Marek Vasut426ca622024-03-26 13:07:22 +0100230
Marek Vasut5a1640e2024-03-26 13:07:28 +0100231 dev_dbg(dev, "%s: OK\n", __func__);
232
Marek Vasut426ca622024-03-26 13:07:22 +0100233 return 0;
234
235err_probe:
236
Marek Vasut5a1640e2024-03-26 13:07:28 +0100237 dev_dbg(dev, "%s: returns %d\n", __func__, ret);
238
Marek Vasut426ca622024-03-26 13:07:22 +0100239 return ret;
240}
241
242static int eqos_remove_resources_stm32(struct udevice *dev)
243{
Marek Vasut5a1640e2024-03-26 13:07:28 +0100244 dev_dbg(dev, "%s:\n", __func__);
Marek Vasut426ca622024-03-26 13:07:22 +0100245
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};