002-net-stmmac-dwmac-sun8i-Handle-integrated-external-MD.patch 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. From 634db83b82658f4641d8026e340c6027cf74a6bb Mon Sep 17 00:00:00 2001
  2. From: Corentin Labbe <clabbe.montjoie@gmail.com>
  3. Date: Tue, 24 Oct 2017 19:57:13 +0200
  4. Subject: [PATCH] net: stmmac: dwmac-sun8i: Handle integrated/external MDIOs
  5. The Allwinner H3 SoC have two distinct MDIO bus, only one could be
  6. active at the same time.
  7. The selection of the active MDIO bus are done via some bits in the EMAC
  8. register of the system controller.
  9. This patch implement this MDIO switch via a custom MDIO-mux.
  10. Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
  11. Reviewed-by: Andrew Lunn <andrew@lunn.ch>
  12. Signed-off-by: David S. Miller <davem@davemloft.net>
  13. ---
  14. drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
  15. drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 353 ++++++++++++++--------
  16. 2 files changed, 224 insertions(+), 130 deletions(-)
  17. --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
  18. +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
  19. @@ -159,6 +159,7 @@ config DWMAC_SUN8I
  20. tristate "Allwinner sun8i GMAC support"
  21. default ARCH_SUNXI
  22. depends on OF && (ARCH_SUNXI || COMPILE_TEST)
  23. + select MDIO_BUS_MUX
  24. ---help---
  25. Support for Allwinner H3 A83T A64 EMAC ethernet controllers.
  26. --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
  27. +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
  28. @@ -17,6 +17,7 @@
  29. #include <linux/clk.h>
  30. #include <linux/io.h>
  31. #include <linux/iopoll.h>
  32. +#include <linux/mdio-mux.h>
  33. #include <linux/mfd/syscon.h>
  34. #include <linux/module.h>
  35. #include <linux/of_device.h>
  36. @@ -41,14 +42,14 @@
  37. * This value is used for disabling properly EMAC
  38. * and used as a good starting value in case of the
  39. * boot process(uboot) leave some stuff.
  40. - * @internal_phy: Does the MAC embed an internal PHY
  41. + * @soc_has_internal_phy: Does the MAC embed an internal PHY
  42. * @support_mii: Does the MAC handle MII
  43. * @support_rmii: Does the MAC handle RMII
  44. * @support_rgmii: Does the MAC handle RGMII
  45. */
  46. struct emac_variant {
  47. u32 default_syscon_value;
  48. - int internal_phy;
  49. + bool soc_has_internal_phy;
  50. bool support_mii;
  51. bool support_rmii;
  52. bool support_rgmii;
  53. @@ -61,7 +62,8 @@ struct emac_variant {
  54. * @rst_ephy: reference to the optional EPHY reset for the internal PHY
  55. * @variant: reference to the current board variant
  56. * @regmap: regmap for using the syscon
  57. - * @use_internal_phy: Does the current PHY choice imply using the internal PHY
  58. + * @internal_phy_powered: Does the internal PHY is enabled
  59. + * @mux_handle: Internal pointer used by mdio-mux lib
  60. */
  61. struct sunxi_priv_data {
  62. struct clk *tx_clk;
  63. @@ -70,12 +72,13 @@ struct sunxi_priv_data {
  64. struct reset_control *rst_ephy;
  65. const struct emac_variant *variant;
  66. struct regmap *regmap;
  67. - bool use_internal_phy;
  68. + bool internal_phy_powered;
  69. + void *mux_handle;
  70. };
  71. static const struct emac_variant emac_variant_h3 = {
  72. .default_syscon_value = 0x58000,
  73. - .internal_phy = PHY_INTERFACE_MODE_MII,
  74. + .soc_has_internal_phy = true,
  75. .support_mii = true,
  76. .support_rmii = true,
  77. .support_rgmii = true
  78. @@ -83,20 +86,20 @@ static const struct emac_variant emac_va
  79. static const struct emac_variant emac_variant_v3s = {
  80. .default_syscon_value = 0x38000,
  81. - .internal_phy = PHY_INTERFACE_MODE_MII,
  82. + .soc_has_internal_phy = true,
  83. .support_mii = true
  84. };
  85. static const struct emac_variant emac_variant_a83t = {
  86. .default_syscon_value = 0,
  87. - .internal_phy = 0,
  88. + .soc_has_internal_phy = false,
  89. .support_mii = true,
  90. .support_rgmii = true
  91. };
  92. static const struct emac_variant emac_variant_a64 = {
  93. .default_syscon_value = 0,
  94. - .internal_phy = 0,
  95. + .soc_has_internal_phy = false,
  96. .support_mii = true,
  97. .support_rmii = true,
  98. .support_rgmii = true
  99. @@ -195,6 +198,9 @@ static const struct emac_variant emac_va
  100. #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
  101. #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
  102. #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
  103. +#define H3_EPHY_MUX_MASK (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT)
  104. +#define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID 1
  105. +#define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID 2
  106. /* H3/A64 specific bits */
  107. #define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */
  108. @@ -634,6 +640,159 @@ static int sun8i_dwmac_reset(struct stmm
  109. return 0;
  110. }
  111. +/* Search in mdio-mux node for internal PHY node and get its clk/reset */
  112. +static int get_ephy_nodes(struct stmmac_priv *priv)
  113. +{
  114. + struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  115. + struct device_node *mdio_mux, *iphynode;
  116. + struct device_node *mdio_internal;
  117. + int ret;
  118. +
  119. + mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
  120. + if (!mdio_mux) {
  121. + dev_err(priv->device, "Cannot get mdio-mux node\n");
  122. + return -ENODEV;
  123. + }
  124. +
  125. + mdio_internal = of_find_compatible_node(mdio_mux, NULL,
  126. + "allwinner,sun8i-h3-mdio-internal");
  127. + if (!mdio_internal) {
  128. + dev_err(priv->device, "Cannot get internal_mdio node\n");
  129. + return -ENODEV;
  130. + }
  131. +
  132. + /* Seek for internal PHY */
  133. + for_each_child_of_node(mdio_internal, iphynode) {
  134. + gmac->ephy_clk = of_clk_get(iphynode, 0);
  135. + if (IS_ERR(gmac->ephy_clk))
  136. + continue;
  137. + gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
  138. + if (IS_ERR(gmac->rst_ephy)) {
  139. + ret = PTR_ERR(gmac->rst_ephy);
  140. + if (ret == -EPROBE_DEFER)
  141. + return ret;
  142. + continue;
  143. + }
  144. + dev_info(priv->device, "Found internal PHY node\n");
  145. + return 0;
  146. + }
  147. + return -ENODEV;
  148. +}
  149. +
  150. +static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
  151. +{
  152. + struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  153. + int ret;
  154. +
  155. + if (gmac->internal_phy_powered) {
  156. + dev_warn(priv->device, "Internal PHY already powered\n");
  157. + return 0;
  158. + }
  159. +
  160. + dev_info(priv->device, "Powering internal PHY\n");
  161. + ret = clk_prepare_enable(gmac->ephy_clk);
  162. + if (ret) {
  163. + dev_err(priv->device, "Cannot enable internal PHY\n");
  164. + return ret;
  165. + }
  166. +
  167. + /* Make sure the EPHY is properly reseted, as U-Boot may leave
  168. + * it at deasserted state, and thus it may fail to reset EMAC.
  169. + */
  170. + reset_control_assert(gmac->rst_ephy);
  171. +
  172. + ret = reset_control_deassert(gmac->rst_ephy);
  173. + if (ret) {
  174. + dev_err(priv->device, "Cannot deassert internal phy\n");
  175. + clk_disable_unprepare(gmac->ephy_clk);
  176. + return ret;
  177. + }
  178. +
  179. + gmac->internal_phy_powered = true;
  180. +
  181. + return 0;
  182. +}
  183. +
  184. +static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
  185. +{
  186. + if (!gmac->internal_phy_powered)
  187. + return 0;
  188. +
  189. + clk_disable_unprepare(gmac->ephy_clk);
  190. + reset_control_assert(gmac->rst_ephy);
  191. + gmac->internal_phy_powered = false;
  192. + return 0;
  193. +}
  194. +
  195. +/* MDIO multiplexing switch function
  196. + * This function is called by the mdio-mux layer when it thinks the mdio bus
  197. + * multiplexer needs to switch.
  198. + * 'current_child' is the current value of the mux register
  199. + * 'desired_child' is the value of the 'reg' property of the target child MDIO
  200. + * node.
  201. + * The first time this function is called, current_child == -1.
  202. + * If current_child == desired_child, then the mux is already set to the
  203. + * correct bus.
  204. + */
  205. +static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
  206. + void *data)
  207. +{
  208. + struct stmmac_priv *priv = data;
  209. + struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  210. + u32 reg, val;
  211. + int ret = 0;
  212. + bool need_power_ephy = false;
  213. +
  214. + if (current_child ^ desired_child) {
  215. + regmap_read(gmac->regmap, SYSCON_EMAC_REG, &reg);
  216. + switch (desired_child) {
  217. + case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
  218. + dev_info(priv->device, "Switch mux to internal PHY");
  219. + val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
  220. +
  221. + need_power_ephy = true;
  222. + break;
  223. + case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
  224. + dev_info(priv->device, "Switch mux to external PHY");
  225. + val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN;
  226. + need_power_ephy = false;
  227. + break;
  228. + default:
  229. + dev_err(priv->device, "Invalid child ID %x\n",
  230. + desired_child);
  231. + return -EINVAL;
  232. + }
  233. + regmap_write(gmac->regmap, SYSCON_EMAC_REG, val);
  234. + if (need_power_ephy) {
  235. + ret = sun8i_dwmac_power_internal_phy(priv);
  236. + if (ret)
  237. + return ret;
  238. + } else {
  239. + sun8i_dwmac_unpower_internal_phy(gmac);
  240. + }
  241. + /* After changing syscon value, the MAC need reset or it will
  242. + * use the last value (and so the last PHY set).
  243. + */
  244. + ret = sun8i_dwmac_reset(priv);
  245. + }
  246. + return ret;
  247. +}
  248. +
  249. +static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
  250. +{
  251. + int ret;
  252. + struct device_node *mdio_mux;
  253. + struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  254. +
  255. + mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
  256. + if (!mdio_mux)
  257. + return -ENODEV;
  258. +
  259. + ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn,
  260. + &gmac->mux_handle, priv, priv->mii);
  261. + return ret;
  262. +}
  263. +
  264. static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
  265. {
  266. struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  267. @@ -648,35 +807,25 @@ static int sun8i_dwmac_set_syscon(struct
  268. "Current syscon value is not the default %x (expect %x)\n",
  269. val, reg);
  270. - if (gmac->variant->internal_phy) {
  271. - if (!gmac->use_internal_phy) {
  272. - /* switch to external PHY interface */
  273. - reg &= ~H3_EPHY_SELECT;
  274. - } else {
  275. - reg |= H3_EPHY_SELECT;
  276. - reg &= ~H3_EPHY_SHUTDOWN;
  277. - dev_dbg(priv->device, "Select internal_phy %x\n", reg);
  278. -
  279. - if (of_property_read_bool(priv->plat->phy_node,
  280. - "allwinner,leds-active-low"))
  281. - reg |= H3_EPHY_LED_POL;
  282. - else
  283. - reg &= ~H3_EPHY_LED_POL;
  284. -
  285. - /* Force EPHY xtal frequency to 24MHz. */
  286. - reg |= H3_EPHY_CLK_SEL;
  287. -
  288. - ret = of_mdio_parse_addr(priv->device,
  289. - priv->plat->phy_node);
  290. - if (ret < 0) {
  291. - dev_err(priv->device, "Could not parse MDIO addr\n");
  292. - return ret;
  293. - }
  294. - /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
  295. - * address. No need to mask it again.
  296. - */
  297. - reg |= ret << H3_EPHY_ADDR_SHIFT;
  298. + if (gmac->variant->soc_has_internal_phy) {
  299. + if (of_property_read_bool(priv->plat->phy_node,
  300. + "allwinner,leds-active-low"))
  301. + reg |= H3_EPHY_LED_POL;
  302. + else
  303. + reg &= ~H3_EPHY_LED_POL;
  304. +
  305. + /* Force EPHY xtal frequency to 24MHz. */
  306. + reg |= H3_EPHY_CLK_SEL;
  307. +
  308. + ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node);
  309. + if (ret < 0) {
  310. + dev_err(priv->device, "Could not parse MDIO addr\n");
  311. + return ret;
  312. }
  313. + /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
  314. + * address. No need to mask it again.
  315. + */
  316. + reg |= 1 << H3_EPHY_ADDR_SHIFT;
  317. }
  318. if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
  319. @@ -746,81 +895,21 @@ static void sun8i_dwmac_unset_syscon(str
  320. regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
  321. }
  322. -static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
  323. +static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
  324. {
  325. - struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
  326. - int ret;
  327. -
  328. - if (!gmac->use_internal_phy)
  329. - return 0;
  330. + struct sunxi_priv_data *gmac = priv;
  331. - ret = clk_prepare_enable(gmac->ephy_clk);
  332. - if (ret) {
  333. - dev_err(priv->device, "Cannot enable ephy\n");
  334. - return ret;
  335. + if (gmac->variant->soc_has_internal_phy) {
  336. + /* sun8i_dwmac_exit could be called with mdiomux uninit */
  337. + if (gmac->mux_handle)
  338. + mdio_mux_uninit(gmac->mux_handle);
  339. + if (gmac->internal_phy_powered)
  340. + sun8i_dwmac_unpower_internal_phy(gmac);
  341. }
  342. - /* Make sure the EPHY is properly reseted, as U-Boot may leave
  343. - * it at deasserted state, and thus it may fail to reset EMAC.
  344. - */
  345. - reset_control_assert(gmac->rst_ephy);
  346. -
  347. - ret = reset_control_deassert(gmac->rst_ephy);
  348. - if (ret) {
  349. - dev_err(priv->device, "Cannot deassert ephy\n");
  350. - clk_disable_unprepare(gmac->ephy_clk);
  351. - return ret;
  352. - }
  353. -
  354. - return 0;
  355. -}
  356. -
  357. -static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
  358. -{
  359. - if (!gmac->use_internal_phy)
  360. - return 0;
  361. -
  362. - clk_disable_unprepare(gmac->ephy_clk);
  363. - reset_control_assert(gmac->rst_ephy);
  364. - return 0;
  365. -}
  366. -
  367. -/* sun8i_power_phy() - Activate the PHY:
  368. - * In case of error, no need to call sun8i_unpower_phy(),
  369. - * it will be called anyway by sun8i_dwmac_exit()
  370. - */
  371. -static int sun8i_power_phy(struct stmmac_priv *priv)
  372. -{
  373. - int ret;
  374. -
  375. - ret = sun8i_dwmac_power_internal_phy(priv);
  376. - if (ret)
  377. - return ret;
  378. -
  379. - ret = sun8i_dwmac_set_syscon(priv);
  380. - if (ret)
  381. - return ret;
  382. -
  383. - /* After changing syscon value, the MAC need reset or it will use
  384. - * the last value (and so the last PHY set.
  385. - */
  386. - ret = sun8i_dwmac_reset(priv);
  387. - if (ret)
  388. - return ret;
  389. - return 0;
  390. -}
  391. -
  392. -static void sun8i_unpower_phy(struct sunxi_priv_data *gmac)
  393. -{
  394. sun8i_dwmac_unset_syscon(gmac);
  395. - sun8i_dwmac_unpower_internal_phy(gmac);
  396. -}
  397. -
  398. -static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
  399. -{
  400. - struct sunxi_priv_data *gmac = priv;
  401. - sun8i_unpower_phy(gmac);
  402. + reset_control_put(gmac->rst_ephy);
  403. clk_disable_unprepare(gmac->tx_clk);
  404. @@ -849,7 +938,7 @@ static struct mac_device_info *sun8i_dwm
  405. if (!mac)
  406. return NULL;
  407. - ret = sun8i_power_phy(priv);
  408. + ret = sun8i_dwmac_set_syscon(priv);
  409. if (ret)
  410. return NULL;
  411. @@ -889,6 +978,8 @@ static int sun8i_dwmac_probe(struct plat
  412. struct sunxi_priv_data *gmac;
  413. struct device *dev = &pdev->dev;
  414. int ret;
  415. + struct stmmac_priv *priv;
  416. + struct net_device *ndev;
  417. ret = stmmac_get_platform_resources(pdev, &stmmac_res);
  418. if (ret)
  419. @@ -932,29 +1023,6 @@ static int sun8i_dwmac_probe(struct plat
  420. }
  421. plat_dat->interface = of_get_phy_mode(dev->of_node);
  422. - if (plat_dat->interface == gmac->variant->internal_phy) {
  423. - dev_info(&pdev->dev, "Will use internal PHY\n");
  424. - gmac->use_internal_phy = true;
  425. - gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0);
  426. - if (IS_ERR(gmac->ephy_clk)) {
  427. - ret = PTR_ERR(gmac->ephy_clk);
  428. - dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret);
  429. - return -EINVAL;
  430. - }
  431. -
  432. - gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL);
  433. - if (IS_ERR(gmac->rst_ephy)) {
  434. - ret = PTR_ERR(gmac->rst_ephy);
  435. - if (ret == -EPROBE_DEFER)
  436. - return ret;
  437. - dev_err(&pdev->dev, "No EPHY reset control found %d\n",
  438. - ret);
  439. - return -EINVAL;
  440. - }
  441. - } else {
  442. - dev_info(&pdev->dev, "Will use external PHY\n");
  443. - gmac->use_internal_phy = false;
  444. - }
  445. /* platform data specifying hardware features and callbacks.
  446. * hardware features were copied from Allwinner drivers.
  447. @@ -973,9 +1041,34 @@ static int sun8i_dwmac_probe(struct plat
  448. ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
  449. if (ret)
  450. - sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
  451. + goto dwmac_exit;
  452. +
  453. + ndev = dev_get_drvdata(&pdev->dev);
  454. + priv = netdev_priv(ndev);
  455. + /* The mux must be registered after parent MDIO
  456. + * so after stmmac_dvr_probe()
  457. + */
  458. + if (gmac->variant->soc_has_internal_phy) {
  459. + ret = get_ephy_nodes(priv);
  460. + if (ret)
  461. + goto dwmac_exit;
  462. + ret = sun8i_dwmac_register_mdio_mux(priv);
  463. + if (ret) {
  464. + dev_err(&pdev->dev, "Failed to register mux\n");
  465. + goto dwmac_mux;
  466. + }
  467. + } else {
  468. + ret = sun8i_dwmac_reset(priv);
  469. + if (ret)
  470. + goto dwmac_exit;
  471. + }
  472. return ret;
  473. +dwmac_mux:
  474. + sun8i_dwmac_unset_syscon(gmac);
  475. +dwmac_exit:
  476. + sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
  477. +return ret;
  478. }
  479. static const struct of_device_id sun8i_dwmac_match[] = {