094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. From caaa71fac36ec8c19145dbf8262a9b77ab09f1a1 Mon Sep 17 00:00:00 2001
  2. From: Ansuel Smith <[email protected]>
  3. Date: Wed, 4 Mar 2020 22:38:32 +0100
  4. Subject: net: mdio: add ipq8064 mdio driver
  5. Currently ipq806x soc use generic bitbang driver to
  6. comunicate with the gmac ethernet interface.
  7. Add a dedicated driver created by chunkeey to fix this.
  8. Co-developed-by: Christian Lamparter <[email protected]>
  9. Signed-off-by: Christian Lamparter <[email protected]>
  10. Signed-off-by: Ansuel Smith <[email protected]>
  11. Signed-off-by: David S. Miller <[email protected]>
  12. ---
  13. drivers/net/phy/Kconfig | 8 ++
  14. drivers/net/phy/Makefile | 1 +
  15. drivers/net/phy/mdio-ipq8064.c | 166 +++++++++++++++++++++++++++++++++++++++++
  16. 3 files changed, 175 insertions(+)
  17. create mode 100644 drivers/net/phy/mdio-ipq8064.c
  18. --- a/drivers/net/phy/Kconfig
  19. +++ b/drivers/net/phy/Kconfig
  20. @@ -156,6 +156,14 @@ config MDIO_I2C
  21. This is library mode.
  22. +config MDIO_IPQ8064
  23. + tristate "Qualcomm IPQ8064 MDIO interface support"
  24. + depends on HAS_IOMEM && OF_MDIO
  25. + depends on MFD_SYSCON
  26. + help
  27. + This driver supports the MDIO interface found in the network
  28. + interface units of the IPQ8064 SoC
  29. +
  30. config MDIO_MOXART
  31. tristate "MOXA ART MDIO interface support"
  32. depends on ARCH_MOXART || COMPILE_TEST
  33. --- a/drivers/net/phy/Makefile
  34. +++ b/drivers/net/phy/Makefile
  35. @@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium
  36. obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
  37. obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o
  38. obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o
  39. +obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o
  40. obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
  41. obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
  42. obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
  43. --- /dev/null
  44. +++ b/drivers/net/phy/mdio-ipq8064.c
  45. @@ -0,0 +1,166 @@
  46. +// SPDX-License-Identifier: GPL-2.0
  47. +/* Qualcomm IPQ8064 MDIO interface driver
  48. + *
  49. + * Copyright (C) 2019 Christian Lamparter <[email protected]>
  50. + * Copyright (C) 2020 Ansuel Smith <[email protected]>
  51. + */
  52. +
  53. +#include <linux/delay.h>
  54. +#include <linux/kernel.h>
  55. +#include <linux/module.h>
  56. +#include <linux/regmap.h>
  57. +#include <linux/of_mdio.h>
  58. +#include <linux/phy.h>
  59. +#include <linux/platform_device.h>
  60. +#include <linux/mfd/syscon.h>
  61. +
  62. +/* MII address register definitions */
  63. +#define MII_ADDR_REG_ADDR 0x10
  64. +#define MII_BUSY BIT(0)
  65. +#define MII_WRITE BIT(1)
  66. +#define MII_CLKRANGE_60_100M (0 << 2)
  67. +#define MII_CLKRANGE_100_150M (1 << 2)
  68. +#define MII_CLKRANGE_20_35M (2 << 2)
  69. +#define MII_CLKRANGE_35_60M (3 << 2)
  70. +#define MII_CLKRANGE_150_250M (4 << 2)
  71. +#define MII_CLKRANGE_250_300M (5 << 2)
  72. +#define MII_CLKRANGE_MASK GENMASK(4, 2)
  73. +#define MII_REG_SHIFT 6
  74. +#define MII_REG_MASK GENMASK(10, 6)
  75. +#define MII_ADDR_SHIFT 11
  76. +#define MII_ADDR_MASK GENMASK(15, 11)
  77. +
  78. +#define MII_DATA_REG_ADDR 0x14
  79. +
  80. +#define MII_MDIO_DELAY_USEC (1000)
  81. +#define MII_MDIO_RETRY_MSEC (10)
  82. +
  83. +struct ipq8064_mdio {
  84. + struct regmap *base; /* NSS_GMAC0_BASE */
  85. +};
  86. +
  87. +static int
  88. +ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv)
  89. +{
  90. + u32 busy;
  91. +
  92. + return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy,
  93. + !(busy & MII_BUSY), MII_MDIO_DELAY_USEC,
  94. + MII_MDIO_RETRY_MSEC * USEC_PER_MSEC);
  95. +}
  96. +
  97. +static int
  98. +ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset)
  99. +{
  100. + u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M;
  101. + struct ipq8064_mdio *priv = bus->priv;
  102. + u32 ret_val;
  103. + int err;
  104. +
  105. + /* Reject clause 45 */
  106. + if (reg_offset & MII_ADDR_C45)
  107. + return -EOPNOTSUPP;
  108. +
  109. + miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) |
  110. + ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
  111. +
  112. + regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
  113. + usleep_range(8, 10);
  114. +
  115. + err = ipq8064_mdio_wait_busy(priv);
  116. + if (err)
  117. + return err;
  118. +
  119. + regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val);
  120. + return (int)ret_val;
  121. +}
  122. +
  123. +static int
  124. +ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)
  125. +{
  126. + u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M;
  127. + struct ipq8064_mdio *priv = bus->priv;
  128. +
  129. + /* Reject clause 45 */
  130. + if (reg_offset & MII_ADDR_C45)
  131. + return -EOPNOTSUPP;
  132. +
  133. + regmap_write(priv->base, MII_DATA_REG_ADDR, data);
  134. +
  135. + miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) |
  136. + ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
  137. +
  138. + regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
  139. + usleep_range(8, 10);
  140. +
  141. + return ipq8064_mdio_wait_busy(priv);
  142. +}
  143. +
  144. +static int
  145. +ipq8064_mdio_probe(struct platform_device *pdev)
  146. +{
  147. + struct device_node *np = pdev->dev.of_node;
  148. + struct ipq8064_mdio *priv;
  149. + struct mii_bus *bus;
  150. + int ret;
  151. +
  152. + bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
  153. + if (!bus)
  154. + return -ENOMEM;
  155. +
  156. + bus->name = "ipq8064_mdio_bus";
  157. + bus->read = ipq8064_mdio_read;
  158. + bus->write = ipq8064_mdio_write;
  159. + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
  160. + bus->parent = &pdev->dev;
  161. +
  162. + priv = bus->priv;
  163. + priv->base = device_node_to_regmap(np);
  164. + if (IS_ERR(priv->base)) {
  165. + if (priv->base == ERR_PTR(-EPROBE_DEFER))
  166. + return -EPROBE_DEFER;
  167. +
  168. + dev_err(&pdev->dev, "error getting device regmap, error=%pe\n",
  169. + priv->base);
  170. + return PTR_ERR(priv->base);
  171. + }
  172. +
  173. + ret = of_mdiobus_register(bus, np);
  174. + if (ret)
  175. + return ret;
  176. +
  177. + platform_set_drvdata(pdev, bus);
  178. + return 0;
  179. +}
  180. +
  181. +static int
  182. +ipq8064_mdio_remove(struct platform_device *pdev)
  183. +{
  184. + struct mii_bus *bus = platform_get_drvdata(pdev);
  185. +
  186. + mdiobus_unregister(bus);
  187. +
  188. + return 0;
  189. +}
  190. +
  191. +static const struct of_device_id ipq8064_mdio_dt_ids[] = {
  192. + { .compatible = "qcom,ipq8064-mdio" },
  193. + { }
  194. +};
  195. +MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids);
  196. +
  197. +static struct platform_driver ipq8064_mdio_driver = {
  198. + .probe = ipq8064_mdio_probe,
  199. + .remove = ipq8064_mdio_remove,
  200. + .driver = {
  201. + .name = "ipq8064-mdio",
  202. + .of_match_table = ipq8064_mdio_dt_ids,
  203. + },
  204. +};
  205. +
  206. +module_platform_driver(ipq8064_mdio_driver);
  207. +
  208. +MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver");
  209. +MODULE_AUTHOR("Christian Lamparter <[email protected]>");
  210. +MODULE_AUTHOR("Ansuel Smith <[email protected]>");
  211. +MODULE_LICENSE("GPL");