Skip to content

Commit ee81098

Browse files
committed
Merge branch 'dwmac-meson8b-clock-fixes-for-Meson8b'
Martin Blumenstingl says: ==================== dwmac-meson8b: clock fixes for Meson8b this series is now successfully tested, thus we think it's ready to be applied to your net-next tree. Emiliano reported [0] that he couldn't get dwmac-meson8b to work on his Odroid-C1. This is the (hopefully) final version of this series, which was successfully tested. Due to the fact that the public S805/S905/S912 datasheets all seem to be outdated regarding the description of the PRG_ETH0 (also called PRG_ETHERNET_ADDR0) register Linus Lüssing offered to help testing with an oscilloscope and an Odroid-C1. I would like to say HUGE thanks to him at this point as he spent hours figuring out the effects of the bits that are (though to be) relevant to get Ethernet working on the Odroid-C1. We tested three scenarios, all based on version 3 of this series: 1) MPLL2 at ~500MHz, m250_div set to 1, bit 10 enabled this resulted in a clock rate twice as high as expected at the RGMII TX clock pin (250MHz instead of 125MHz for Gbit connections and 50MHz instead of 25MHz for 100Mbit/s connections). it did not change the rate at the XTAL_IN pin of PHY (which stayed consistenly at 25MHz) 2) MPLL2 at ~250MHz, m250_div set to 1, bit 10 disabled the oscilloscope shows "no clock" for the RGMII TX clock pin at it's highest resolution (and random rates at lower resolutions). XTAL_IN is still at 25MHz 3) MPLL2 at ~250MHz, m250_div set to 1, bit 10 enabled this resulted in a 125MHz signal at the RGMII TX clock pin for Gbit speeds and 25MHz for 100Mbit/s - both values are as expected. The rate on the XTAL_IN pin was at 25MHz -> boot-logs (with the PRG_ETH0 register value) and screenshots from the readings of the oscilloscope can be found at: https://metameute.de/~tux/linux/amlogic/odroidc1/ethernet/ Version 4 of this series is based on the results from Linus Lüssing's help with the oscilloscope and Odroid-C1. Unfortunately I don't have any Meson8b boards with RGMII PHY so I could only partially test this. @Emiliano: Could you please give this version a try and let me know about the results (preferably with a "Tested-by" if it works)? You obviously still need your two "ARM: dts: meson8b" patches which - add the amlogic,meson8b-dwmac" compatible to meson8b.dtsi - enable Ethernet on the Odroid-C1 (according to your last thest a TX delay of 4ns is required to make it work properly) When testing on Meson8b this also needs a fix for the MPLL clock driver: "clk: meson: mpll: use 64-bit maths in params_from_rate", see: https://patchwork.kernel.org/patch/10131677/ I have tested this myself on a Khadas VIM (GXL SoC, internal RMII PHY) and a Khadas VIM2 (GXM SoC, external RGMII PHY). Both are still working fine (so let's hope that this also fixes your Meson8b issue :)). changes since v4 at [4]: - dropped "RFT" status since Jerome tested this series successfully! - dropped PATCH #2 ("simplify generating the clock names"). I will improve the whole clock registration in a separate series. since that patch didn't really improve anything I dropped it for now - added Jerome's Acked-/Reviewed-/Tested-by's - many thanks! changes since v3 at [3]: - renamed the function PATCH #1 from meson8b_init_rgmii_clk to meson8b_init_rgmii_tx_clk since we now know what the register bits mean - rewrote PATCH #3 because bit 10 is a gate clock and it seems that there is an internal fixed divide-by-2 clock. see the patch description for a detailed explanation - updated the description of PATCH #4 and #5 as the clock we're trying to fix is the "RGMII TX" clock (old version stated that this is the "RGMII clock" or "PHY reference clock"). also updated the numbers in the description now that we have the clock hierarchy right (at least we hope so) changes since v2 at [2]: - added PATCH #2 to make the following patch easier - Emiliano reported that there's currently another bug in the dwmac-meson8b driver which prevents it from working with RGMII PHYs on Meson8b: bit 10 of the PRG_ETH0 register is configures a clock gate (instead of a divide by 5 or divide by 10 clock divider). This has not been visible on GXBB and later due to the input clock which always led to a selection of "divide by 10" (which is done internally in the IP block, but the bit actually means "enable RGMII clock output"). PATCH #3 was added to address this issue. - the commit message of PATCH #4 and #5 (formerly PATCH #2 and #3) were updated and the patch itself rebased because the m25_div clock was removed with the new PATCH #3 (so some of the statements were not valid anymore) changes since v1 at [1]: - changed the subject of the cover-letter to indicate that this is all about the RGMII clock - added PATCH #1 which ensures that we don't unnecessarily change the parent clocks in RMII mode (and also makes the code easier to understand) - changed subject of PATCH #2 (formerly PATCH #1) to state that this is about the RGMII clock - added Jerome's Reviewed-by to PATCH #2 (formerly PATCH #1) - replaced PATCH #3 (formerly PATCH #2) with one that sets CLK_SET_RATE_PARENT on the mux and thus re-configures the MPLL2 clock on Meson8b correctly [0] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005596.html [1] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005848.html [2] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005861.html [3] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005899.html [4] http://lists.infradead.org/pipermail/linux-amlogic/2018-January/006125.html ==================== Tested-by: Emiliano Ingrassia <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents 416ef9b + fb7d38a commit ee81098

File tree

1 file changed

+63
-50
lines changed

1 file changed

+63
-50
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@
4040
#define PRG_ETH0_CLK_M250_DIV_SHIFT 7
4141
#define PRG_ETH0_CLK_M250_DIV_WIDTH 3
4242

43-
/* divides the result of m25_sel by either 5 (bit unset) or 10 (bit set) */
44-
#define PRG_ETH0_CLK_M25_DIV_SHIFT 10
45-
#define PRG_ETH0_CLK_M25_DIV_WIDTH 1
43+
#define PRG_ETH0_RGMII_TX_CLK_EN 10
4644

4745
#define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
4846
#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
@@ -63,8 +61,11 @@ struct meson8b_dwmac {
6361
struct clk_divider m250_div;
6462
struct clk *m250_div_clk;
6563

66-
struct clk_divider m25_div;
67-
struct clk *m25_div_clk;
64+
struct clk_fixed_factor fixed_div2;
65+
struct clk *fixed_div2_clk;
66+
67+
struct clk_gate rgmii_tx_en;
68+
struct clk *rgmii_tx_en_clk;
6869

6970
u32 tx_delay_ns;
7071
};
@@ -81,19 +82,14 @@ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
8182
writel(data, dwmac->regs + reg);
8283
}
8384

84-
static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
85+
static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
8586
{
8687
struct clk_init_data init;
8788
int i, ret;
8889
struct device *dev = &dwmac->pdev->dev;
8990
char clk_name[32];
9091
const char *clk_div_parents[1];
9192
const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
92-
static const struct clk_div_table clk_25m_div_table[] = {
93-
{ .val = 0, .div = 5 },
94-
{ .val = 1, .div = 10 },
95-
{ /* sentinel */ },
96-
};
9793

9894
/* get the mux parents from DT */
9995
for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
@@ -116,7 +112,7 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
116112
snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev));
117113
init.name = clk_name;
118114
init.ops = &clk_mux_ops;
119-
init.flags = 0;
115+
init.flags = CLK_SET_RATE_PARENT;
120116
init.parent_names = mux_parent_names;
121117
init.num_parents = MUX_CLK_NUM_PARENTS;
122118

@@ -144,39 +140,55 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
144140
dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
145141
dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
146142
dwmac->m250_div.hw.init = &init;
147-
dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
143+
dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED |
144+
CLK_DIVIDER_ALLOW_ZERO |
145+
CLK_DIVIDER_ROUND_CLOSEST;
148146

149147
dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw);
150148
if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
151149
return PTR_ERR(dwmac->m250_div_clk);
152150

153-
/* create the m25_div */
154-
snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev));
151+
/* create the fixed_div2 */
152+
snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
155153
init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
156-
init.ops = &clk_divider_ops;
157-
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
154+
init.ops = &clk_fixed_factor_ops;
155+
init.flags = CLK_SET_RATE_PARENT;
158156
clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
159157
init.parent_names = clk_div_parents;
160158
init.num_parents = ARRAY_SIZE(clk_div_parents);
161159

162-
dwmac->m25_div.reg = dwmac->regs + PRG_ETH0;
163-
dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT;
164-
dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH;
165-
dwmac->m25_div.table = clk_25m_div_table;
166-
dwmac->m25_div.hw.init = &init;
167-
dwmac->m25_div.flags = CLK_DIVIDER_ALLOW_ZERO;
160+
dwmac->fixed_div2.mult = 1;
161+
dwmac->fixed_div2.div = 2;
162+
dwmac->fixed_div2.hw.init = &init;
168163

169-
dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw);
170-
if (WARN_ON(IS_ERR(dwmac->m25_div_clk)))
171-
return PTR_ERR(dwmac->m25_div_clk);
164+
dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
165+
if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
166+
return PTR_ERR(dwmac->fixed_div2_clk);
167+
168+
/* create the rgmii_tx_en */
169+
init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#rgmii_tx_en",
170+
dev_name(dev));
171+
init.ops = &clk_gate_ops;
172+
init.flags = CLK_SET_RATE_PARENT;
173+
clk_div_parents[0] = __clk_get_name(dwmac->fixed_div2_clk);
174+
init.parent_names = clk_div_parents;
175+
init.num_parents = ARRAY_SIZE(clk_div_parents);
176+
177+
dwmac->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
178+
dwmac->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
179+
dwmac->rgmii_tx_en.hw.init = &init;
180+
181+
dwmac->rgmii_tx_en_clk = devm_clk_register(dev,
182+
&dwmac->rgmii_tx_en.hw);
183+
if (WARN_ON(IS_ERR(dwmac->rgmii_tx_en_clk)))
184+
return PTR_ERR(dwmac->rgmii_tx_en_clk);
172185

173186
return 0;
174187
}
175188

176189
static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
177190
{
178191
int ret;
179-
unsigned long clk_rate;
180192
u8 tx_dly_val = 0;
181193

182194
switch (dwmac->phy_mode) {
@@ -191,9 +203,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
191203

192204
case PHY_INTERFACE_MODE_RGMII_ID:
193205
case PHY_INTERFACE_MODE_RGMII_TXID:
194-
/* Generate a 25MHz clock for the PHY */
195-
clk_rate = 25 * 1000 * 1000;
196-
197206
/* enable RGMII mode */
198207
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
199208
PRG_ETH0_RGMII_MODE);
@@ -204,12 +213,28 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
204213

205214
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
206215
tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
216+
217+
/* Configure the 125MHz RGMII TX clock, the IP block changes
218+
* the output automatically (= without us having to configure
219+
* a register) based on the line-speed (125MHz for Gbit speeds,
220+
* 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
221+
*/
222+
ret = clk_set_rate(dwmac->rgmii_tx_en_clk, 125 * 1000 * 1000);
223+
if (ret) {
224+
dev_err(&dwmac->pdev->dev,
225+
"failed to set RGMII TX clock\n");
226+
return ret;
227+
}
228+
229+
ret = clk_prepare_enable(dwmac->rgmii_tx_en_clk);
230+
if (ret) {
231+
dev_err(&dwmac->pdev->dev,
232+
"failed to enable the RGMII TX clock\n");
233+
return ret;
234+
}
207235
break;
208236

209237
case PHY_INTERFACE_MODE_RMII:
210-
/* Use the rate of the mux clock for the internal RMII PHY */
211-
clk_rate = clk_get_rate(dwmac->m250_mux_clk);
212-
213238
/* disable RGMII mode -> enables RMII mode */
214239
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
215240
0);
@@ -231,20 +256,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
231256
return -EINVAL;
232257
}
233258

234-
ret = clk_prepare_enable(dwmac->m25_div_clk);
235-
if (ret) {
236-
dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n");
237-
return ret;
238-
}
239-
240-
ret = clk_set_rate(dwmac->m25_div_clk, clk_rate);
241-
if (ret) {
242-
clk_disable_unprepare(dwmac->m25_div_clk);
243-
244-
dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
245-
return ret;
246-
}
247-
248259
/* enable TX_CLK and PHY_REF_CLK generator */
249260
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
250261
PRG_ETH0_TX_AND_PHY_REF_CLK);
@@ -294,7 +305,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
294305
&dwmac->tx_delay_ns))
295306
dwmac->tx_delay_ns = 2;
296307

297-
ret = meson8b_init_clk(dwmac);
308+
ret = meson8b_init_rgmii_tx_clk(dwmac);
298309
if (ret)
299310
goto err_remove_config_dt;
300311

@@ -311,7 +322,8 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
311322
return 0;
312323

313324
err_clk_disable:
314-
clk_disable_unprepare(dwmac->m25_div_clk);
325+
if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
326+
clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
315327
err_remove_config_dt:
316328
stmmac_remove_config_dt(pdev, plat_dat);
317329

@@ -322,7 +334,8 @@ static int meson8b_dwmac_remove(struct platform_device *pdev)
322334
{
323335
struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
324336

325-
clk_disable_unprepare(dwmac->m25_div_clk);
337+
if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
338+
clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
326339

327340
return stmmac_pltfr_remove(pdev);
328341
}

0 commit comments

Comments
 (0)