cpsw-phy-sel.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Texas Instruments Ethernet Switch Driver
  3. *
  4. * Copyright (C) 2013 Texas Instruments
  5. *
  6. * Module Author: Mugunthan V N <[email protected]>
  7. *
  8. */
  9. #include <linux/platform_device.h>
  10. #include <linux/init.h>
  11. #include <linux/netdevice.h>
  12. #include <linux/phy.h>
  13. #include <linux/of.h>
  14. #include <linux/of_device.h>
  15. #include "cpsw.h"
  16. /* AM33xx SoC specific definitions for the CONTROL port */
  17. #define AM33XX_GMII_SEL_MODE_MII 0
  18. #define AM33XX_GMII_SEL_MODE_RMII 1
  19. #define AM33XX_GMII_SEL_MODE_RGMII 2
  20. #define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7)
  21. #define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6)
  22. #define AM33XX_GMII_SEL_RGMII2_IDMODE BIT(5)
  23. #define AM33XX_GMII_SEL_RGMII1_IDMODE BIT(4)
  24. #define GMII_SEL_MODE_MASK 0x3
  25. struct cpsw_phy_sel_priv {
  26. struct device *dev;
  27. u32 __iomem *gmii_sel;
  28. bool rmii_clock_external;
  29. void (*cpsw_phy_sel)(struct cpsw_phy_sel_priv *priv,
  30. phy_interface_t phy_mode, int slave);
  31. };
  32. static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
  33. phy_interface_t phy_mode, int slave)
  34. {
  35. u32 reg;
  36. u32 mask;
  37. u32 mode = 0;
  38. bool rgmii_id = false;
  39. reg = readl(priv->gmii_sel);
  40. switch (phy_mode) {
  41. case PHY_INTERFACE_MODE_RMII:
  42. mode = AM33XX_GMII_SEL_MODE_RMII;
  43. break;
  44. case PHY_INTERFACE_MODE_RGMII:
  45. mode = AM33XX_GMII_SEL_MODE_RGMII;
  46. break;
  47. case PHY_INTERFACE_MODE_RGMII_ID:
  48. case PHY_INTERFACE_MODE_RGMII_RXID:
  49. case PHY_INTERFACE_MODE_RGMII_TXID:
  50. mode = AM33XX_GMII_SEL_MODE_RGMII;
  51. rgmii_id = true;
  52. break;
  53. default:
  54. dev_warn(priv->dev,
  55. "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
  56. phy_modes(phy_mode));
  57. fallthrough;
  58. case PHY_INTERFACE_MODE_MII:
  59. mode = AM33XX_GMII_SEL_MODE_MII;
  60. break;
  61. }
  62. mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
  63. mask |= BIT(slave + 4);
  64. mode <<= slave * 2;
  65. if (priv->rmii_clock_external) {
  66. if (slave == 0)
  67. mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
  68. else
  69. mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
  70. }
  71. if (rgmii_id) {
  72. if (slave == 0)
  73. mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
  74. else
  75. mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
  76. }
  77. reg &= ~mask;
  78. reg |= mode;
  79. writel(reg, priv->gmii_sel);
  80. }
  81. static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
  82. phy_interface_t phy_mode, int slave)
  83. {
  84. u32 reg;
  85. u32 mask;
  86. u32 mode = 0;
  87. reg = readl(priv->gmii_sel);
  88. switch (phy_mode) {
  89. case PHY_INTERFACE_MODE_RMII:
  90. mode = AM33XX_GMII_SEL_MODE_RMII;
  91. break;
  92. case PHY_INTERFACE_MODE_RGMII:
  93. case PHY_INTERFACE_MODE_RGMII_ID:
  94. case PHY_INTERFACE_MODE_RGMII_RXID:
  95. case PHY_INTERFACE_MODE_RGMII_TXID:
  96. mode = AM33XX_GMII_SEL_MODE_RGMII;
  97. break;
  98. default:
  99. dev_warn(priv->dev,
  100. "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
  101. phy_modes(phy_mode));
  102. fallthrough;
  103. case PHY_INTERFACE_MODE_MII:
  104. mode = AM33XX_GMII_SEL_MODE_MII;
  105. break;
  106. }
  107. switch (slave) {
  108. case 0:
  109. mask = GMII_SEL_MODE_MASK;
  110. break;
  111. case 1:
  112. mask = GMII_SEL_MODE_MASK << 4;
  113. mode <<= 4;
  114. break;
  115. default:
  116. dev_err(priv->dev, "invalid slave number...\n");
  117. return;
  118. }
  119. if (priv->rmii_clock_external)
  120. dev_err(priv->dev, "RMII External clock is not supported\n");
  121. reg &= ~mask;
  122. reg |= mode;
  123. writel(reg, priv->gmii_sel);
  124. }
  125. static struct platform_driver cpsw_phy_sel_driver;
  126. static int match(struct device *dev, const void *data)
  127. {
  128. const struct device_node *node = (const struct device_node *)data;
  129. return dev->of_node == node &&
  130. dev->driver == &cpsw_phy_sel_driver.driver;
  131. }
  132. void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave)
  133. {
  134. struct device_node *node;
  135. struct cpsw_phy_sel_priv *priv;
  136. node = of_parse_phandle(dev->of_node, "cpsw-phy-sel", 0);
  137. if (!node) {
  138. node = of_get_child_by_name(dev->of_node, "cpsw-phy-sel");
  139. if (!node) {
  140. dev_err(dev, "Phy mode driver DT not found\n");
  141. return;
  142. }
  143. }
  144. dev = bus_find_device(&platform_bus_type, NULL, node, match);
  145. if (!dev) {
  146. dev_err(dev, "unable to find platform device for %pOF\n", node);
  147. goto out;
  148. }
  149. priv = dev_get_drvdata(dev);
  150. priv->cpsw_phy_sel(priv, phy_mode, slave);
  151. put_device(dev);
  152. out:
  153. of_node_put(node);
  154. }
  155. EXPORT_SYMBOL_GPL(cpsw_phy_sel);
  156. static const struct of_device_id cpsw_phy_sel_id_table[] = {
  157. {
  158. .compatible = "ti,am3352-cpsw-phy-sel",
  159. .data = &cpsw_gmii_sel_am3352,
  160. },
  161. {
  162. .compatible = "ti,dra7xx-cpsw-phy-sel",
  163. .data = &cpsw_gmii_sel_dra7xx,
  164. },
  165. {
  166. .compatible = "ti,am43xx-cpsw-phy-sel",
  167. .data = &cpsw_gmii_sel_am3352,
  168. },
  169. {}
  170. };
  171. static int cpsw_phy_sel_probe(struct platform_device *pdev)
  172. {
  173. const struct of_device_id *of_id;
  174. struct cpsw_phy_sel_priv *priv;
  175. of_id = of_match_node(cpsw_phy_sel_id_table, pdev->dev.of_node);
  176. if (!of_id)
  177. return -EINVAL;
  178. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  179. if (!priv) {
  180. dev_err(&pdev->dev, "unable to alloc memory for cpsw phy sel\n");
  181. return -ENOMEM;
  182. }
  183. priv->dev = &pdev->dev;
  184. priv->cpsw_phy_sel = of_id->data;
  185. priv->gmii_sel = devm_platform_ioremap_resource_byname(pdev, "gmii-sel");
  186. if (IS_ERR(priv->gmii_sel))
  187. return PTR_ERR(priv->gmii_sel);
  188. if (of_find_property(pdev->dev.of_node, "rmii-clock-ext", NULL))
  189. priv->rmii_clock_external = true;
  190. dev_set_drvdata(&pdev->dev, priv);
  191. return 0;
  192. }
  193. static struct platform_driver cpsw_phy_sel_driver = {
  194. .probe = cpsw_phy_sel_probe,
  195. .driver = {
  196. .name = "cpsw-phy-sel",
  197. .of_match_table = cpsw_phy_sel_id_table,
  198. },
  199. };
  200. builtin_platform_driver(cpsw_phy_sel_driver);