cpsw-phy-sel.c 5.7 KB

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