blob: 544bc621146c3da32d8df6a9fd2cb46aa8614c20 [file] [log] [blame]
Thomas Gleixner3c910ec2019-06-01 10:09:00 +02001// SPDX-License-Identifier: GPL-2.0-only
Martin Blumenstingl566e8252016-09-06 23:38:46 +02002/*
Martin Blumenstingl76766932018-03-30 01:00:35 +02003 * Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer
Martin Blumenstingl566e8252016-09-06 23:38:46 +02004 *
5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Martin Blumenstingl566e8252016-09-06 23:38:46 +02006 */
7
Martin Blumenstingl3649abe2020-05-12 23:10:58 +02008#include <linux/bitfield.h>
Martin Blumenstingl566e8252016-09-06 23:38:46 +02009#include <linux/clk.h>
10#include <linux/clk-provider.h>
11#include <linux/device.h>
12#include <linux/ethtool.h>
13#include <linux/io.h>
14#include <linux/ioport.h>
15#include <linux/module.h>
Yixun Lanefacb562018-04-28 10:21:11 +000016#include <linux/of_device.h>
Martin Blumenstingl566e8252016-09-06 23:38:46 +020017#include <linux/of_net.h>
18#include <linux/mfd/syscon.h>
19#include <linux/platform_device.h>
20#include <linux/stmmac.h>
21
22#include "stmmac_platform.h"
23
24#define PRG_ETH0 0x0
25
26#define PRG_ETH0_RGMII_MODE BIT(0)
27
Yixun Lanefacb562018-04-28 10:21:11 +000028#define PRG_ETH0_EXT_PHY_MODE_MASK GENMASK(2, 0)
29#define PRG_ETH0_EXT_RGMII_MODE 1
30#define PRG_ETH0_EXT_RMII_MODE 4
31
Martin Blumenstingl566e8252016-09-06 23:38:46 +020032/* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */
33#define PRG_ETH0_CLK_M250_SEL_SHIFT 4
34#define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4)
35
Martin Blumenstingl889df202020-05-12 23:10:59 +020036/* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where 8ns are exactly one
37 * cycle of the 125MHz RGMII TX clock):
38 * 0ns = 0x0, 2ns = 0x1, 4ns = 0x2, 6ns = 0x3
39 */
Martin Blumenstingl566e8252016-09-06 23:38:46 +020040#define PRG_ETH0_TXDLY_MASK GENMASK(6, 5)
Martin Blumenstingl566e8252016-09-06 23:38:46 +020041
42/* divider for the result of m250_sel */
43#define PRG_ETH0_CLK_M250_DIV_SHIFT 7
44#define PRG_ETH0_CLK_M250_DIV_WIDTH 3
45
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +010046#define PRG_ETH0_RGMII_TX_CLK_EN 10
Martin Blumenstingl566e8252016-09-06 23:38:46 +020047
48#define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
49#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
50
Martin Blumenstinglc92d1d22020-05-12 23:11:00 +020051/* Bypass (= 0, the signal from the GPIO input directly connects to the
52 * internal sampling) or enable (= 1) the internal logic for RXEN and RXD[3:0]
53 * timing tuning.
54 */
55#define PRG_ETH0_ADJ_ENABLE BIT(13)
56/* Controls whether the RXEN and RXD[3:0] signals should be aligned with the
57 * input RX rising/falling edge and sent to the Ethernet internals. This sets
58 * the automatically delay and skew automatically (internally).
59 */
60#define PRG_ETH0_ADJ_SETUP BIT(14)
61/* An internal counter based on the "timing-adjustment" clock. The counter is
62 * cleared on both, the falling and rising edge of the RX_CLK. This selects the
63 * delay (= the counter value) when to start sampling RXEN and RXD[3:0].
64 */
65#define PRG_ETH0_ADJ_DELAY GENMASK(19, 15)
66/* Adjusts the skew between each bit of RXEN and RXD[3:0]. If a signal has a
67 * large input delay, the bit for that signal (RXEN = bit 0, RXD[3] = bit 1,
68 * ...) can be configured to be 1 to compensate for a delay of about 1ns.
69 */
70#define PRG_ETH0_ADJ_SKEW GENMASK(24, 20)
71
Martin Blumenstingl566e8252016-09-06 23:38:46 +020072#define MUX_CLK_NUM_PARENTS 2
73
Yixun Lanefacb562018-04-28 10:21:11 +000074struct meson8b_dwmac;
75
76struct meson8b_dwmac_data {
77 int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
78};
79
Martin Blumenstingl566e8252016-09-06 23:38:46 +020080struct meson8b_dwmac {
Yixun Lanefacb562018-04-28 10:21:11 +000081 struct device *dev;
82 void __iomem *regs;
83
84 const struct meson8b_dwmac_data *data;
85 phy_interface_t phy_mode;
86 struct clk *rgmii_tx_clk;
87 u32 tx_delay_ns;
Martin Blumenstingl9308c4762020-05-12 23:11:03 +020088 u32 rx_delay_ns;
Martin Blumenstingle4227bf2020-05-12 23:11:01 +020089 struct clk *timing_adj_clk;
Martin Blumenstingl80767592018-02-17 15:08:20 +010090};
Martin Blumenstingl566e8252016-09-06 23:38:46 +020091
Martin Blumenstingl80767592018-02-17 15:08:20 +010092struct meson8b_dwmac_clk_configs {
Martin Blumenstingl566e8252016-09-06 23:38:46 +020093 struct clk_mux m250_mux;
Martin Blumenstingl566e8252016-09-06 23:38:46 +020094 struct clk_divider m250_div;
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +010095 struct clk_fixed_factor fixed_div2;
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +010096 struct clk_gate rgmii_tx_en;
Martin Blumenstingl566e8252016-09-06 23:38:46 +020097};
98
99static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
100 u32 mask, u32 value)
101{
102 u32 data;
103
104 data = readl(dwmac->regs + reg);
105 data &= ~mask;
106 data |= (value & mask);
107
108 writel(data, dwmac->regs + reg);
109}
110
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100111static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac,
112 const char *name_suffix,
113 const char **parent_names,
114 int num_parents,
115 const struct clk_ops *ops,
116 struct clk_hw *hw)
117{
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100118 struct clk_init_data init;
119 char clk_name[32];
120
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100121 snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev),
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100122 name_suffix);
123
124 init.name = clk_name;
125 init.ops = ops;
126 init.flags = CLK_SET_RATE_PARENT;
127 init.parent_names = parent_names;
128 init.num_parents = num_parents;
129
130 hw->init = &init;
131
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100132 return devm_clk_register(dwmac->dev, hw);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100133}
134
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100135static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200136{
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200137 int i, ret;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100138 struct clk *clk;
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100139 struct device *dev = dwmac->dev;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100140 const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
Martin Blumenstingl80767592018-02-17 15:08:20 +0100141 struct meson8b_dwmac_clk_configs *clk_configs;
Martin Blumenstinglbd6f4852019-12-26 20:01:01 +0100142 static const struct clk_div_table div_table[] = {
143 { .div = 2, .val = 2, },
144 { .div = 3, .val = 3, },
145 { .div = 4, .val = 4, },
146 { .div = 5, .val = 5, },
147 { .div = 6, .val = 6, },
148 { .div = 7, .val = 7, },
Marc Zyngierf0212a52020-04-18 19:14:57 +0100149 { /* end of array */ }
Martin Blumenstinglbd6f4852019-12-26 20:01:01 +0100150 };
Martin Blumenstingl80767592018-02-17 15:08:20 +0100151
152 clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
153 if (!clk_configs)
154 return -ENOMEM;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200155
156 /* get the mux parents from DT */
157 for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
158 char name[16];
159
160 snprintf(name, sizeof(name), "clkin%d", i);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100161 clk = devm_clk_get(dev, name);
162 if (IS_ERR(clk)) {
163 ret = PTR_ERR(clk);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200164 if (ret != -EPROBE_DEFER)
165 dev_err(dev, "Missing clock %s\n", name);
166 return ret;
167 }
168
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100169 mux_parent_names[i] = __clk_get_name(clk);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200170 }
171
Martin Blumenstingl80767592018-02-17 15:08:20 +0100172 clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
173 clk_configs->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
174 clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100175 clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names,
176 MUX_CLK_NUM_PARENTS, &clk_mux_ops,
Martin Blumenstingl80767592018-02-17 15:08:20 +0100177 &clk_configs->m250_mux.hw);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100178 if (WARN_ON(IS_ERR(clk)))
179 return PTR_ERR(clk);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200180
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100181 parent_name = __clk_get_name(clk);
Martin Blumenstingl80767592018-02-17 15:08:20 +0100182 clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
183 clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
184 clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
Martin Blumenstinglbd6f4852019-12-26 20:01:01 +0100185 clk_configs->m250_div.table = div_table;
186 clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO |
187 CLK_DIVIDER_ROUND_CLOSEST;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100188 clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
189 &clk_divider_ops,
Martin Blumenstingl80767592018-02-17 15:08:20 +0100190 &clk_configs->m250_div.hw);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100191 if (WARN_ON(IS_ERR(clk)))
192 return PTR_ERR(clk);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200193
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100194 parent_name = __clk_get_name(clk);
Martin Blumenstingl80767592018-02-17 15:08:20 +0100195 clk_configs->fixed_div2.mult = 1;
196 clk_configs->fixed_div2.div = 2;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100197 clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_name, 1,
198 &clk_fixed_factor_ops,
Martin Blumenstingl80767592018-02-17 15:08:20 +0100199 &clk_configs->fixed_div2.hw);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100200 if (WARN_ON(IS_ERR(clk)))
201 return PTR_ERR(clk);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200202
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100203 parent_name = __clk_get_name(clk);
Martin Blumenstingl80767592018-02-17 15:08:20 +0100204 clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
205 clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100206 clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_name, 1,
207 &clk_gate_ops,
Martin Blumenstingl80767592018-02-17 15:08:20 +0100208 &clk_configs->rgmii_tx_en.hw);
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100209 if (WARN_ON(IS_ERR(clk)))
210 return PTR_ERR(clk);
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +0100211
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100212 dwmac->rgmii_tx_clk = clk;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200213
214 return 0;
215}
216
Yixun Lanefacb562018-04-28 10:21:11 +0000217static int meson8b_set_phy_mode(struct meson8b_dwmac *dwmac)
218{
219 switch (dwmac->phy_mode) {
220 case PHY_INTERFACE_MODE_RGMII:
221 case PHY_INTERFACE_MODE_RGMII_RXID:
222 case PHY_INTERFACE_MODE_RGMII_ID:
223 case PHY_INTERFACE_MODE_RGMII_TXID:
224 /* enable RGMII mode */
225 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
226 PRG_ETH0_RGMII_MODE,
227 PRG_ETH0_RGMII_MODE);
228 break;
229 case PHY_INTERFACE_MODE_RMII:
230 /* disable RGMII mode -> enables RMII mode */
231 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
232 PRG_ETH0_RGMII_MODE, 0);
233 break;
234 default:
235 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
236 phy_modes(dwmac->phy_mode));
237 return -EINVAL;
238 }
239
240 return 0;
241}
242
243static int meson_axg_set_phy_mode(struct meson8b_dwmac *dwmac)
244{
245 switch (dwmac->phy_mode) {
246 case PHY_INTERFACE_MODE_RGMII:
247 case PHY_INTERFACE_MODE_RGMII_RXID:
248 case PHY_INTERFACE_MODE_RGMII_ID:
249 case PHY_INTERFACE_MODE_RGMII_TXID:
250 /* enable RGMII mode */
251 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
252 PRG_ETH0_EXT_PHY_MODE_MASK,
253 PRG_ETH0_EXT_RGMII_MODE);
254 break;
255 case PHY_INTERFACE_MODE_RMII:
256 /* disable RGMII mode -> enables RMII mode */
257 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
258 PRG_ETH0_EXT_PHY_MODE_MASK,
259 PRG_ETH0_EXT_RMII_MODE);
260 break;
261 default:
262 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
263 phy_modes(dwmac->phy_mode));
264 return -EINVAL;
265 }
266
267 return 0;
268}
269
Martin Blumenstingla54dc4a2020-05-12 23:11:02 +0200270static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac,
271 struct clk *clk)
272{
273 int ret;
274
275 ret = clk_prepare_enable(clk);
276 if (ret)
277 return ret;
278
279 devm_add_action_or_reset(dwmac->dev,
280 (void(*)(void *))clk_disable_unprepare,
281 dwmac->rgmii_tx_clk);
282
283 return 0;
284}
285
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200286static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
287{
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200288 u32 tx_dly_config, rx_dly_config, delay_config;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200289 int ret;
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200290
291 tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
292 dwmac->tx_delay_ns >> 1);
293
294 if (dwmac->rx_delay_ns == 2)
295 rx_dly_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
296 else
297 rx_dly_config = 0;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200298
299 switch (dwmac->phy_mode) {
300 case PHY_INTERFACE_MODE_RGMII:
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200301 delay_config = tx_dly_config | rx_dly_config;
302 break;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200303 case PHY_INTERFACE_MODE_RGMII_RXID:
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200304 delay_config = tx_dly_config;
305 break;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200306 case PHY_INTERFACE_MODE_RGMII_TXID:
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200307 delay_config = rx_dly_config;
308 break;
309 case PHY_INTERFACE_MODE_RGMII_ID:
310 case PHY_INTERFACE_MODE_RMII:
311 delay_config = 0;
312 break;
313 default:
314 dev_err(dwmac->dev, "unsupported phy-mode %s\n",
315 phy_modes(dwmac->phy_mode));
316 return -EINVAL;
317 };
318
319 if (rx_dly_config & PRG_ETH0_ADJ_ENABLE) {
320 if (!dwmac->timing_adj_clk) {
321 dev_err(dwmac->dev,
322 "The timing-adjustment clock is mandatory for the RX delay re-timing\n");
323 return -EINVAL;
324 }
325
326 /* The timing adjustment logic is driven by a separate clock */
327 ret = meson8b_devm_clk_prepare_enable(dwmac,
328 dwmac->timing_adj_clk);
329 if (ret) {
330 dev_err(dwmac->dev,
331 "Failed to enable the timing-adjustment clock\n");
332 return ret;
333 }
334 }
335
336 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK |
337 PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP |
338 PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW,
339 delay_config);
340
341 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) {
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200342 /* only relevant for RMII mode -> disable in RGMII mode */
343 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
344 PRG_ETH0_INVERTED_RMII_CLK, 0);
345
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +0100346 /* Configure the 125MHz RGMII TX clock, the IP block changes
347 * the output automatically (= without us having to configure
348 * a register) based on the line-speed (125MHz for Gbit speeds,
349 * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
350 */
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100351 ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000);
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100352 if (ret) {
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100353 dev_err(dwmac->dev,
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +0100354 "failed to set RGMII TX clock\n");
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100355 return ret;
356 }
357
Martin Blumenstingla54dc4a2020-05-12 23:11:02 +0200358 ret = meson8b_devm_clk_prepare_enable(dwmac,
359 dwmac->rgmii_tx_clk);
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100360 if (ret) {
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100361 dev_err(dwmac->dev,
Martin Blumenstingl4f6a71b2018-01-15 18:10:13 +0100362 "failed to enable the RGMII TX clock\n");
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100363 return ret;
364 }
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200365 } else {
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200366 /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */
367 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
368 PRG_ETH0_INVERTED_RMII_CLK,
369 PRG_ETH0_INVERTED_RMII_CLK);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200370 }
371
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200372 /* enable TX_CLK and PHY_REF_CLK generator */
373 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
374 PRG_ETH0_TX_AND_PHY_REF_CLK);
375
376 return 0;
377}
378
379static int meson8b_dwmac_probe(struct platform_device *pdev)
380{
381 struct plat_stmmacenet_data *plat_dat;
382 struct stmmac_resources stmmac_res;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200383 struct meson8b_dwmac *dwmac;
384 int ret;
385
386 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
387 if (ret)
388 return ret;
389
390 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
391 if (IS_ERR(plat_dat))
392 return PTR_ERR(plat_dat);
393
394 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100395 if (!dwmac) {
396 ret = -ENOMEM;
397 goto err_remove_config_dt;
398 }
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200399
Yixun Lanefacb562018-04-28 10:21:11 +0000400 dwmac->data = (const struct meson8b_dwmac_data *)
401 of_device_get_match_data(&pdev->dev);
Christophe JAILLET760a6ed2018-06-11 19:52:27 +0200402 if (!dwmac->data) {
403 ret = -EINVAL;
404 goto err_remove_config_dt;
405 }
YueHaibing999232a2019-08-21 21:51:30 +0800406 dwmac->regs = devm_platform_ioremap_resource(pdev, 1);
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100407 if (IS_ERR(dwmac->regs)) {
408 ret = PTR_ERR(dwmac->regs);
409 goto err_remove_config_dt;
410 }
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200411
Martin Blumenstinglb7563712018-02-17 15:08:19 +0100412 dwmac->dev = &pdev->dev;
Andrew Lunn0c65b2b2019-11-04 02:40:33 +0100413 ret = of_get_phy_mode(pdev->dev.of_node, &dwmac->phy_mode);
414 if (ret) {
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200415 dev_err(&pdev->dev, "missing phy-mode property\n");
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100416 goto err_remove_config_dt;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200417 }
418
Martin Blumenstinglb7652342017-01-22 23:02:46 +0100419 /* use 2ns as fallback since this value was previously hardcoded */
420 if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns",
421 &dwmac->tx_delay_ns))
422 dwmac->tx_delay_ns = 2;
423
Martin Blumenstingl9308c4762020-05-12 23:11:03 +0200424 /* use 0ns as fallback since this is what most boards actually use */
425 if (of_property_read_u32(pdev->dev.of_node, "amlogic,rx-delay-ns",
426 &dwmac->rx_delay_ns))
427 dwmac->rx_delay_ns = 0;
428
429 if (dwmac->rx_delay_ns != 0 && dwmac->rx_delay_ns != 2) {
430 dev_err(&pdev->dev,
431 "The only allowed RX delays values are: 0ns, 2ns");
432 ret = -EINVAL;
433 goto err_remove_config_dt;
434 }
435
Martin Blumenstingle4227bf2020-05-12 23:11:01 +0200436 dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev,
437 "timing-adjustment");
438 if (IS_ERR(dwmac->timing_adj_clk)) {
439 ret = PTR_ERR(dwmac->timing_adj_clk);
440 goto err_remove_config_dt;
441 }
442
Martin Blumenstingl37512b42018-01-15 18:10:12 +0100443 ret = meson8b_init_rgmii_tx_clk(dwmac);
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200444 if (ret)
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100445 goto err_remove_config_dt;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200446
Yixun Lanefacb562018-04-28 10:21:11 +0000447 ret = dwmac->data->set_phy_mode(dwmac);
448 if (ret)
449 goto err_remove_config_dt;
450
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200451 ret = meson8b_init_prg_eth(dwmac);
452 if (ret)
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100453 goto err_remove_config_dt;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200454
455 plat_dat->bsp_priv = dwmac;
456
Johan Hovold5cc70bb2016-11-30 15:29:53 +0100457 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
458 if (ret)
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100459 goto err_remove_config_dt;
Johan Hovold5cc70bb2016-11-30 15:29:53 +0100460
461 return 0;
462
Johan Hovoldd2ed0a72016-11-30 15:29:55 +0100463err_remove_config_dt:
464 stmmac_remove_config_dt(pdev, plat_dat);
Johan Hovold5cc70bb2016-11-30 15:29:53 +0100465
466 return ret;
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200467}
468
Yixun Lanefacb562018-04-28 10:21:11 +0000469static const struct meson8b_dwmac_data meson8b_dwmac_data = {
470 .set_phy_mode = meson8b_set_phy_mode,
471};
472
473static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
474 .set_phy_mode = meson_axg_set_phy_mode,
475};
476
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200477static const struct of_device_id meson8b_dwmac_match[] = {
Yixun Lanefacb562018-04-28 10:21:11 +0000478 {
479 .compatible = "amlogic,meson8b-dwmac",
480 .data = &meson8b_dwmac_data,
481 },
482 {
483 .compatible = "amlogic,meson8m2-dwmac",
484 .data = &meson8b_dwmac_data,
485 },
486 {
487 .compatible = "amlogic,meson-gxbb-dwmac",
488 .data = &meson8b_dwmac_data,
489 },
490 {
491 .compatible = "amlogic,meson-axg-dwmac",
492 .data = &meson_axg_dwmac_data,
493 },
Martin Blumenstingla4f63342020-06-20 21:26:41 +0200494 {
495 .compatible = "amlogic,meson-g12a-dwmac",
496 .data = &meson_axg_dwmac_data,
497 },
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200498 { }
499};
500MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
501
502static struct platform_driver meson8b_dwmac_driver = {
503 .probe = meson8b_dwmac_probe,
Martin Blumenstingl11184a52018-02-17 15:08:18 +0100504 .remove = stmmac_pltfr_remove,
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200505 .driver = {
506 .name = "meson8b-dwmac",
507 .pm = &stmmac_pltfr_pm_ops,
508 .of_match_table = meson8b_dwmac_match,
509 },
510};
511module_platform_driver(meson8b_dwmac_driver);
512
513MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
Martin Blumenstingl76766932018-03-30 01:00:35 +0200514MODULE_DESCRIPTION("Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer");
Martin Blumenstingl566e8252016-09-06 23:38:46 +0200515MODULE_LICENSE("GPL v2");