aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-01-17 14:41:06 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-17 14:41:06 -0500
commitee81098efe0de33d1dbddcb293c6a3a6a126f9e0 (patch)
treeb1d87045d53885bfb1f4dbafe8a4231a24cc3f7e
parent416ef9b15c688b91edbf654ebe7bc349c9151147 (diff)
parentfb7d38a70e1d8ffd54f7a7464dcc4889d7e490ad (diff)
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 <ingrassia@epigenesys.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c113
1 files changed, 63 insertions, 50 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 4404650b32c5..5270d26f0bc6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -40,9 +40,7 @@
40#define PRG_ETH0_CLK_M250_DIV_SHIFT 7 40#define PRG_ETH0_CLK_M250_DIV_SHIFT 7
41#define PRG_ETH0_CLK_M250_DIV_WIDTH 3 41#define PRG_ETH0_CLK_M250_DIV_WIDTH 3
42 42
43/* divides the result of m25_sel by either 5 (bit unset) or 10 (bit set) */ 43#define PRG_ETH0_RGMII_TX_CLK_EN 10
44#define PRG_ETH0_CLK_M25_DIV_SHIFT 10
45#define PRG_ETH0_CLK_M25_DIV_WIDTH 1
46 44
47#define PRG_ETH0_INVERTED_RMII_CLK BIT(11) 45#define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
48#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12) 46#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
@@ -63,8 +61,11 @@ struct meson8b_dwmac {
63 struct clk_divider m250_div; 61 struct clk_divider m250_div;
64 struct clk *m250_div_clk; 62 struct clk *m250_div_clk;
65 63
66 struct clk_divider m25_div; 64 struct clk_fixed_factor fixed_div2;
67 struct clk *m25_div_clk; 65 struct clk *fixed_div2_clk;
66
67 struct clk_gate rgmii_tx_en;
68 struct clk *rgmii_tx_en_clk;
68 69
69 u32 tx_delay_ns; 70 u32 tx_delay_ns;
70}; 71};
@@ -81,7 +82,7 @@ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
81 writel(data, dwmac->regs + reg); 82 writel(data, dwmac->regs + reg);
82} 83}
83 84
84static int meson8b_init_clk(struct meson8b_dwmac *dwmac) 85static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
85{ 86{
86 struct clk_init_data init; 87 struct clk_init_data init;
87 int i, ret; 88 int i, ret;
@@ -89,11 +90,6 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
89 char clk_name[32]; 90 char clk_name[32];
90 const char *clk_div_parents[1]; 91 const char *clk_div_parents[1];
91 const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; 92 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 };
97 93
98 /* get the mux parents from DT */ 94 /* get the mux parents from DT */
99 for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) { 95 for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
@@ -116,7 +112,7 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
116 snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev)); 112 snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev));
117 init.name = clk_name; 113 init.name = clk_name;
118 init.ops = &clk_mux_ops; 114 init.ops = &clk_mux_ops;
119 init.flags = 0; 115 init.flags = CLK_SET_RATE_PARENT;
120 init.parent_names = mux_parent_names; 116 init.parent_names = mux_parent_names;
121 init.num_parents = MUX_CLK_NUM_PARENTS; 117 init.num_parents = MUX_CLK_NUM_PARENTS;
122 118
@@ -144,31 +140,48 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
144 dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; 140 dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
145 dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; 141 dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
146 dwmac->m250_div.hw.init = &init; 142 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;
148 146
149 dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw); 147 dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw);
150 if (WARN_ON(IS_ERR(dwmac->m250_div_clk))) 148 if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
151 return PTR_ERR(dwmac->m250_div_clk); 149 return PTR_ERR(dwmac->m250_div_clk);
152 150
153 /* create the m25_div */ 151 /* create the fixed_div2 */
154 snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev)); 152 snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
155 init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL); 153 init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
156 init.ops = &clk_divider_ops; 154 init.ops = &clk_fixed_factor_ops;
157 init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; 155 init.flags = CLK_SET_RATE_PARENT;
158 clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk); 156 clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
159 init.parent_names = clk_div_parents; 157 init.parent_names = clk_div_parents;
160 init.num_parents = ARRAY_SIZE(clk_div_parents); 158 init.num_parents = ARRAY_SIZE(clk_div_parents);
161 159
162 dwmac->m25_div.reg = dwmac->regs + PRG_ETH0; 160 dwmac->fixed_div2.mult = 1;
163 dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT; 161 dwmac->fixed_div2.div = 2;
164 dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH; 162 dwmac->fixed_div2.hw.init = &init;
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;
168 163
169 dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw); 164 dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
170 if (WARN_ON(IS_ERR(dwmac->m25_div_clk))) 165 if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
171 return PTR_ERR(dwmac->m25_div_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);
172 185
173 return 0; 186 return 0;
174} 187}
@@ -176,7 +189,6 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
176static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac) 189static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
177{ 190{
178 int ret; 191 int ret;
179 unsigned long clk_rate;
180 u8 tx_dly_val = 0; 192 u8 tx_dly_val = 0;
181 193
182 switch (dwmac->phy_mode) { 194 switch (dwmac->phy_mode) {
@@ -191,9 +203,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
191 203
192 case PHY_INTERFACE_MODE_RGMII_ID: 204 case PHY_INTERFACE_MODE_RGMII_ID:
193 case PHY_INTERFACE_MODE_RGMII_TXID: 205 case PHY_INTERFACE_MODE_RGMII_TXID:
194 /* Generate a 25MHz clock for the PHY */
195 clk_rate = 25 * 1000 * 1000;
196
197 /* enable RGMII mode */ 206 /* enable RGMII mode */
198 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE, 207 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
199 PRG_ETH0_RGMII_MODE); 208 PRG_ETH0_RGMII_MODE);
@@ -204,12 +213,28 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
204 213
205 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK, 214 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
206 tx_dly_val << PRG_ETH0_TXDLY_SHIFT); 215 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 }
207 break; 235 break;
208 236
209 case PHY_INTERFACE_MODE_RMII: 237 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
213 /* disable RGMII mode -> enables RMII mode */ 238 /* disable RGMII mode -> enables RMII mode */
214 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE, 239 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
215 0); 240 0);
@@ -231,20 +256,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
231 return -EINVAL; 256 return -EINVAL;
232 } 257 }
233 258
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
248 /* enable TX_CLK and PHY_REF_CLK generator */ 259 /* enable TX_CLK and PHY_REF_CLK generator */
249 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK, 260 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
250 PRG_ETH0_TX_AND_PHY_REF_CLK); 261 PRG_ETH0_TX_AND_PHY_REF_CLK);
@@ -294,7 +305,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
294 &dwmac->tx_delay_ns)) 305 &dwmac->tx_delay_ns))
295 dwmac->tx_delay_ns = 2; 306 dwmac->tx_delay_ns = 2;
296 307
297 ret = meson8b_init_clk(dwmac); 308 ret = meson8b_init_rgmii_tx_clk(dwmac);
298 if (ret) 309 if (ret)
299 goto err_remove_config_dt; 310 goto err_remove_config_dt;
300 311
@@ -311,7 +322,8 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
311 return 0; 322 return 0;
312 323
313err_clk_disable: 324err_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);
315err_remove_config_dt: 327err_remove_config_dt:
316 stmmac_remove_config_dt(pdev, plat_dat); 328 stmmac_remove_config_dt(pdev, plat_dat);
317 329
@@ -322,7 +334,8 @@ static int meson8b_dwmac_remove(struct platform_device *pdev)
322{ 334{
323 struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); 335 struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
324 336
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);
326 339
327 return stmmac_pltfr_remove(pdev); 340 return stmmac_pltfr_remove(pdev);
328} 341}