aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Blumenstingl <martin.blumenstingl@googlemail.com>2018-01-15 12:10:13 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-17 14:41:05 -0500
commit4f6a71b84e1afdf13827741e7421a844203cf8d0 (patch)
treea99d729c15955eccd06479cb546745330f76be3e
parent37512b42f082d784a012c3734ef109f25d199786 (diff)
net: stmmac: dwmac-meson8b: fix internal RGMII clock configuration
Tests (using an oscilloscope and an Odroid-C1 board with a RTL8211F RGMII PHY) have shown that the PRG_ETH0 register behaves as follows: - bit 4 is a mux to choose between two parent clocks. according to the public S805 datasheet the only supported parent clock is MPLL2 (this was not verified using the oscilloscope). The public S805/S905 datasheet claims that this bit is reserved. - bits 9:7 control a one-based divider (register value 1 means "divide by 1", etc.) for the input clock. we call this clock the "m250_div" clock because it's value is always supposed to be (close to) 250MHz (see below for an explanation). The description in the public S805/S905 datasheet is a bit cryptic, but it comes down to "input clock = 250MHz * value" (which could also be expressed as "250MHz = input clock / value") - there seems to be an internal fixed divide-by-2 clock which takes the output from the m250_div and divides it by 2. This is not unusual on Amlogic SoCs, since the SDIO (MMC) driver also uses an internal fixed divide-by-2 clock. This is not documented in the public S805/S905 datasheet - bit 10 controls a gate clock which enables or disables the RGMII TX clock (which is an output on the MAC/SoC and an input in the PHY). we call this the "rgmii_tx_en" clock. if this bit is set to "0" the RGMII TX clock output is close to 0 The description for this bit in the public S805/S905 datasheet is "Generate 25MHz clock for PHY". Based on these tests it's believed that this is wrong, and should probably read "Generate the 125MHz RGMII TX clock for the PHY" - the RGMII TX clock has to be set to 125MHz - the IP block adjusts the output (automatically) depending on the line speed (RGMII specifies that Gbit connections use a 125MHz clock, 100Mbit/s connections use a 25MHz clock and 10Mbit/s connections use a 2.5MHz clock. only Gbit and 100Mbit/s were tested with an oscilloscope). Due to the requirement that this clock always has to be set to 125MHz and due to the fixed divide-by-2 parent clock this means that m250_div will always end up with a rate of (close to) 250MHz. - bits 6:5 are the TX delay, which is also named "clock phase" in some of Amlogic's older GPL kernel sources. The PHY also has an XTAL_IN pin where a 25MHz clock has to be provided. Tests with the oscilloscope have shown that this is routed to a crystal right next to the RTL8211F PHY. The same seems to be true on the Khadas VIM2 (which uses a GXM SoC) board - however the 25MHz crystal is on the other side of the PCB there. This updates the clocks in the dwmac-meson8b driver by replacing the "m25_div" with the "rgmii_tx_en" clock and additionally introducing a fixed divide-by-2 clock between "m250_div" and "rgmii_tx_en". Now we also need to set a frequency of 125MHz on the RGMII clock (opposed to the 25MHz we set before, with that non-existing divide-by-5-or-10 divider). Special thanks go to Linus Lüssing for testing the various bits and checking the results with an oscilloscope on his Odroid-C1! Fixes: 566e8251625304 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC") Reported-by: Emiliano Ingrassia <ingrassia@epigenesys.com> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> Acked-by: Jerome Brunet <jbrunet@baylibre.com> Tested-by: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c79
1 files changed, 47 insertions, 32 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index c6f87e9c4ccb..7930a152dd63 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};
@@ -89,11 +90,6 @@ static int meson8b_init_rgmii_tx_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++) {
@@ -150,25 +146,40 @@ static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
150 if (WARN_ON(IS_ERR(dwmac->m250_div_clk))) 146 if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
151 return PTR_ERR(dwmac->m250_div_clk); 147 return PTR_ERR(dwmac->m250_div_clk);
152 148
153 /* create the m25_div */ 149 /* create the fixed_div2 */
154 snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev)); 150 snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
155 init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL); 151 init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
156 init.ops = &clk_divider_ops; 152 init.ops = &clk_fixed_factor_ops;
157 init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; 153 init.flags = CLK_SET_RATE_PARENT;
158 clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk); 154 clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
159 init.parent_names = clk_div_parents; 155 init.parent_names = clk_div_parents;
160 init.num_parents = ARRAY_SIZE(clk_div_parents); 156 init.num_parents = ARRAY_SIZE(clk_div_parents);
161 157
162 dwmac->m25_div.reg = dwmac->regs + PRG_ETH0; 158 dwmac->fixed_div2.mult = 1;
163 dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT; 159 dwmac->fixed_div2.div = 2;
164 dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH; 160 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 161
169 dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw); 162 dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
170 if (WARN_ON(IS_ERR(dwmac->m25_div_clk))) 163 if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
171 return PTR_ERR(dwmac->m25_div_clk); 164 return PTR_ERR(dwmac->fixed_div2_clk);
165
166 /* create the rgmii_tx_en */
167 init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#rgmii_tx_en",
168 dev_name(dev));
169 init.ops = &clk_gate_ops;
170 init.flags = CLK_SET_RATE_PARENT;
171 clk_div_parents[0] = __clk_get_name(dwmac->fixed_div2_clk);
172 init.parent_names = clk_div_parents;
173 init.num_parents = ARRAY_SIZE(clk_div_parents);
174
175 dwmac->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
176 dwmac->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
177 dwmac->rgmii_tx_en.hw.init = &init;
178
179 dwmac->rgmii_tx_en_clk = devm_clk_register(dev,
180 &dwmac->rgmii_tx_en.hw);
181 if (WARN_ON(IS_ERR(dwmac->rgmii_tx_en_clk)))
182 return PTR_ERR(dwmac->rgmii_tx_en_clk);
172 183
173 return 0; 184 return 0;
174} 185}
@@ -201,18 +212,22 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
201 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK, 212 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
202 tx_dly_val << PRG_ETH0_TXDLY_SHIFT); 213 tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
203 214
204 ret = clk_prepare_enable(dwmac->m25_div_clk); 215 /* Configure the 125MHz RGMII TX clock, the IP block changes
216 * the output automatically (= without us having to configure
217 * a register) based on the line-speed (125MHz for Gbit speeds,
218 * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
219 */
220 ret = clk_set_rate(dwmac->rgmii_tx_en_clk, 125 * 1000 * 1000);
205 if (ret) { 221 if (ret) {
206 dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n"); 222 dev_err(&dwmac->pdev->dev,
223 "failed to set RGMII TX clock\n");
207 return ret; 224 return ret;
208 } 225 }
209 226
210 /* Generate the 25MHz RGMII clock for the PHY */ 227 ret = clk_prepare_enable(dwmac->rgmii_tx_en_clk);
211 ret = clk_set_rate(dwmac->m25_div_clk, 25 * 1000 * 1000);
212 if (ret) { 228 if (ret) {
213 clk_disable_unprepare(dwmac->m25_div_clk); 229 dev_err(&dwmac->pdev->dev,
214 230 "failed to enable the RGMII TX clock\n");
215 dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
216 return ret; 231 return ret;
217 } 232 }
218 break; 233 break;
@@ -306,7 +321,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
306 321
307err_clk_disable: 322err_clk_disable:
308 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) 323 if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
309 clk_disable_unprepare(dwmac->m25_div_clk); 324 clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
310err_remove_config_dt: 325err_remove_config_dt:
311 stmmac_remove_config_dt(pdev, plat_dat); 326 stmmac_remove_config_dt(pdev, plat_dat);
312 327
@@ -318,7 +333,7 @@ static int meson8b_dwmac_remove(struct platform_device *pdev)
318 struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); 333 struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
319 334
320 if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) 335 if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
321 clk_disable_unprepare(dwmac->m25_div_clk); 336 clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
322 337
323 return stmmac_pltfr_remove(pdev); 338 return stmmac_pltfr_remove(pdev);
324} 339}