mdio-ipq4019.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2. /* Copyright (c) 2015, The Linux Foundation. All rights reserved. */
  3. /* Copyright (c) 2020 Sartura Ltd. */
  4. #include <linux/delay.h>
  5. #include <linux/io.h>
  6. #include <linux/iopoll.h>
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_mdio.h>
  11. #include <linux/phy.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/clk.h>
  14. #define MDIO_MODE_REG 0x40
  15. #define MDIO_MODE_MDC_MODE BIT(12)
  16. /* 0 = Clause 22, 1 = Clause 45 */
  17. #define MDIO_MODE_C45 BIT(8)
  18. #define MDIO_MODE_DIV_MASK GENMASK(7, 0)
  19. #define MDIO_MODE_DIV(x) FIELD_PREP(MDIO_MODE_DIV_MASK, (x) - 1)
  20. #define MDIO_MODE_DIV_1 0x0
  21. #define MDIO_MODE_DIV_2 0x1
  22. #define MDIO_MODE_DIV_4 0x3
  23. #define MDIO_MODE_DIV_8 0x7
  24. #define MDIO_MODE_DIV_16 0xf
  25. #define MDIO_MODE_DIV_32 0x1f
  26. #define MDIO_MODE_DIV_64 0x3f
  27. #define MDIO_MODE_DIV_128 0x7f
  28. #define MDIO_MODE_DIV_256 0xff
  29. #define MDIO_ADDR_REG 0x44
  30. #define MDIO_DATA_WRITE_REG 0x48
  31. #define MDIO_DATA_READ_REG 0x4c
  32. #define MDIO_CMD_REG 0x50
  33. #define MDIO_CMD_ACCESS_BUSY BIT(16)
  34. #define MDIO_CMD_ACCESS_START BIT(8)
  35. #define MDIO_CMD_ACCESS_CODE_READ 0
  36. #define MDIO_CMD_ACCESS_CODE_WRITE 1
  37. #define MDIO_CMD_ACCESS_CODE_C45_ADDR 0
  38. #define MDIO_CMD_ACCESS_CODE_C45_WRITE 1
  39. #define MDIO_CMD_ACCESS_CODE_C45_READ 2
  40. #define IPQ4019_MDIO_TIMEOUT 10000
  41. #define IPQ4019_MDIO_SLEEP 10
  42. /* MDIO clock source frequency is fixed to 100M */
  43. #define IPQ_MDIO_CLK_RATE 100000000
  44. #define IPQ_PHY_SET_DELAY_US 100000
  45. struct ipq4019_mdio_data {
  46. void __iomem *membase;
  47. void __iomem *eth_ldo_rdy;
  48. struct clk *mdio_clk;
  49. unsigned int mdc_rate;
  50. };
  51. static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
  52. {
  53. struct ipq4019_mdio_data *priv = bus->priv;
  54. unsigned int busy;
  55. return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
  56. (busy & MDIO_CMD_ACCESS_BUSY) == 0,
  57. IPQ4019_MDIO_SLEEP, IPQ4019_MDIO_TIMEOUT);
  58. }
  59. static int ipq4019_mdio_read_c45(struct mii_bus *bus, int mii_id, int mmd,
  60. int reg)
  61. {
  62. struct ipq4019_mdio_data *priv = bus->priv;
  63. unsigned int data;
  64. unsigned int cmd;
  65. if (ipq4019_mdio_wait_busy(bus))
  66. return -ETIMEDOUT;
  67. data = readl(priv->membase + MDIO_MODE_REG);
  68. data |= MDIO_MODE_C45;
  69. writel(data, priv->membase + MDIO_MODE_REG);
  70. /* issue the phy address and mmd */
  71. writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
  72. /* issue reg */
  73. writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
  74. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
  75. /* issue read command */
  76. writel(cmd, priv->membase + MDIO_CMD_REG);
  77. /* Wait read complete */
  78. if (ipq4019_mdio_wait_busy(bus))
  79. return -ETIMEDOUT;
  80. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_READ;
  81. writel(cmd, priv->membase + MDIO_CMD_REG);
  82. if (ipq4019_mdio_wait_busy(bus))
  83. return -ETIMEDOUT;
  84. /* Read and return data */
  85. return readl(priv->membase + MDIO_DATA_READ_REG);
  86. }
  87. static int ipq4019_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
  88. {
  89. struct ipq4019_mdio_data *priv = bus->priv;
  90. unsigned int data;
  91. unsigned int cmd;
  92. if (ipq4019_mdio_wait_busy(bus))
  93. return -ETIMEDOUT;
  94. data = readl(priv->membase + MDIO_MODE_REG);
  95. data &= ~MDIO_MODE_C45;
  96. writel(data, priv->membase + MDIO_MODE_REG);
  97. /* issue the phy address and reg */
  98. writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
  99. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
  100. /* issue read command */
  101. writel(cmd, priv->membase + MDIO_CMD_REG);
  102. /* Wait read complete */
  103. if (ipq4019_mdio_wait_busy(bus))
  104. return -ETIMEDOUT;
  105. /* Read and return data */
  106. return readl(priv->membase + MDIO_DATA_READ_REG);
  107. }
  108. static int ipq4019_mdio_write_c45(struct mii_bus *bus, int mii_id, int mmd,
  109. int reg, u16 value)
  110. {
  111. struct ipq4019_mdio_data *priv = bus->priv;
  112. unsigned int data;
  113. unsigned int cmd;
  114. if (ipq4019_mdio_wait_busy(bus))
  115. return -ETIMEDOUT;
  116. data = readl(priv->membase + MDIO_MODE_REG);
  117. data |= MDIO_MODE_C45;
  118. writel(data, priv->membase + MDIO_MODE_REG);
  119. /* issue the phy address and mmd */
  120. writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
  121. /* issue reg */
  122. writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
  123. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
  124. writel(cmd, priv->membase + MDIO_CMD_REG);
  125. if (ipq4019_mdio_wait_busy(bus))
  126. return -ETIMEDOUT;
  127. /* issue write data */
  128. writel(value, priv->membase + MDIO_DATA_WRITE_REG);
  129. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_WRITE;
  130. writel(cmd, priv->membase + MDIO_CMD_REG);
  131. /* Wait write complete */
  132. if (ipq4019_mdio_wait_busy(bus))
  133. return -ETIMEDOUT;
  134. return 0;
  135. }
  136. static int ipq4019_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
  137. u16 value)
  138. {
  139. struct ipq4019_mdio_data *priv = bus->priv;
  140. unsigned int data;
  141. unsigned int cmd;
  142. if (ipq4019_mdio_wait_busy(bus))
  143. return -ETIMEDOUT;
  144. /* Enter Clause 22 mode */
  145. data = readl(priv->membase + MDIO_MODE_REG);
  146. data &= ~MDIO_MODE_C45;
  147. writel(data, priv->membase + MDIO_MODE_REG);
  148. /* issue the phy address and reg */
  149. writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
  150. /* issue write data */
  151. writel(value, priv->membase + MDIO_DATA_WRITE_REG);
  152. /* issue write command */
  153. cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
  154. writel(cmd, priv->membase + MDIO_CMD_REG);
  155. /* Wait write complete */
  156. if (ipq4019_mdio_wait_busy(bus))
  157. return -ETIMEDOUT;
  158. return 0;
  159. }
  160. static int ipq4019_mdio_set_div(struct ipq4019_mdio_data *priv)
  161. {
  162. unsigned long ahb_rate;
  163. int div;
  164. u32 val;
  165. /* If we don't have a clock for AHB use the fixed value */
  166. ahb_rate = IPQ_MDIO_CLK_RATE;
  167. if (priv->mdio_clk)
  168. ahb_rate = clk_get_rate(priv->mdio_clk);
  169. /* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1)
  170. * While supported, internal documentation doesn't
  171. * assure correct functionality of the MDIO bus
  172. * with divider of 1, 2 or 4.
  173. */
  174. for (div = 8; div <= 256; div *= 2) {
  175. /* The requested rate is supported by the div */
  176. if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) {
  177. val = readl(priv->membase + MDIO_MODE_REG);
  178. val &= ~MDIO_MODE_DIV_MASK;
  179. val |= MDIO_MODE_DIV(div);
  180. writel(val, priv->membase + MDIO_MODE_REG);
  181. return 0;
  182. }
  183. }
  184. /* The requested rate is not supported */
  185. return -EINVAL;
  186. }
  187. static int ipq_mdio_reset(struct mii_bus *bus)
  188. {
  189. struct ipq4019_mdio_data *priv = bus->priv;
  190. u32 val;
  191. int ret;
  192. /* To indicate CMN_PLL that ethernet_ldo has been ready if platform resource 1
  193. * is specified in the device tree.
  194. */
  195. if (priv->eth_ldo_rdy) {
  196. val = readl(priv->eth_ldo_rdy);
  197. val |= BIT(0);
  198. writel(val, priv->eth_ldo_rdy);
  199. fsleep(IPQ_PHY_SET_DELAY_US);
  200. }
  201. /* Configure MDIO clock source frequency if clock is specified in the device tree */
  202. ret = clk_set_rate(priv->mdio_clk, IPQ_MDIO_CLK_RATE);
  203. if (ret)
  204. return ret;
  205. ret = clk_prepare_enable(priv->mdio_clk);
  206. if (ret)
  207. return ret;
  208. mdelay(10);
  209. /* Restore MDC rate */
  210. return ipq4019_mdio_set_div(priv);
  211. }
  212. static void ipq4019_mdio_select_mdc_rate(struct platform_device *pdev,
  213. struct ipq4019_mdio_data *priv)
  214. {
  215. unsigned long ahb_rate;
  216. int div;
  217. u32 val;
  218. /* MDC rate defined in DT, we don't have to decide a default value */
  219. if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
  220. &priv->mdc_rate))
  221. return;
  222. /* If we don't have a clock for AHB use the fixed value */
  223. ahb_rate = IPQ_MDIO_CLK_RATE;
  224. if (priv->mdio_clk)
  225. ahb_rate = clk_get_rate(priv->mdio_clk);
  226. /* Check what is the current div set */
  227. val = readl(priv->membase + MDIO_MODE_REG);
  228. div = FIELD_GET(MDIO_MODE_DIV_MASK, val);
  229. /* div is not set to the default value of /256
  230. * Probably someone changed that (bootloader, other drivers)
  231. * Keep this and don't overwrite it.
  232. */
  233. if (div != MDIO_MODE_DIV_256) {
  234. priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1);
  235. return;
  236. }
  237. /* If div is /256 assume nobody have set this value and
  238. * try to find one MDC rate that is close the 802.3 spec of
  239. * 2.5MHz
  240. */
  241. for (div = 256; div >= 8; div /= 2) {
  242. /* Stop as soon as we found a divider that
  243. * reached the closest value to 2.5MHz
  244. */
  245. if (DIV_ROUND_UP(ahb_rate, div) > 2500000)
  246. break;
  247. priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div);
  248. }
  249. }
  250. static int ipq4019_mdio_probe(struct platform_device *pdev)
  251. {
  252. struct ipq4019_mdio_data *priv;
  253. struct mii_bus *bus;
  254. struct resource *res;
  255. int ret;
  256. bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
  257. if (!bus)
  258. return -ENOMEM;
  259. priv = bus->priv;
  260. priv->membase = devm_platform_ioremap_resource(pdev, 0);
  261. if (IS_ERR(priv->membase))
  262. return PTR_ERR(priv->membase);
  263. priv->mdio_clk = devm_clk_get_optional(&pdev->dev, "gcc_mdio_ahb_clk");
  264. if (IS_ERR(priv->mdio_clk))
  265. return PTR_ERR(priv->mdio_clk);
  266. ipq4019_mdio_select_mdc_rate(pdev, priv);
  267. ret = ipq4019_mdio_set_div(priv);
  268. if (ret)
  269. return ret;
  270. /* The platform resource is provided on the chipset IPQ5018 */
  271. /* This resource is optional */
  272. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  273. if (res) {
  274. priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res);
  275. if (IS_ERR(priv->eth_ldo_rdy))
  276. return PTR_ERR(priv->eth_ldo_rdy);
  277. }
  278. bus->name = "ipq4019_mdio";
  279. bus->read = ipq4019_mdio_read_c22;
  280. bus->write = ipq4019_mdio_write_c22;
  281. bus->read_c45 = ipq4019_mdio_read_c45;
  282. bus->write_c45 = ipq4019_mdio_write_c45;
  283. bus->reset = ipq_mdio_reset;
  284. bus->parent = &pdev->dev;
  285. snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
  286. ret = of_mdiobus_register(bus, pdev->dev.of_node);
  287. if (ret) {
  288. dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
  289. return ret;
  290. }
  291. platform_set_drvdata(pdev, bus);
  292. return 0;
  293. }
  294. static void ipq4019_mdio_remove(struct platform_device *pdev)
  295. {
  296. struct mii_bus *bus = platform_get_drvdata(pdev);
  297. mdiobus_unregister(bus);
  298. }
  299. static const struct of_device_id ipq4019_mdio_dt_ids[] = {
  300. { .compatible = "qcom,ipq4019-mdio" },
  301. { .compatible = "qcom,ipq5018-mdio" },
  302. { }
  303. };
  304. MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
  305. static struct platform_driver ipq4019_mdio_driver = {
  306. .probe = ipq4019_mdio_probe,
  307. .remove = ipq4019_mdio_remove,
  308. .driver = {
  309. .name = "ipq4019-mdio",
  310. .of_match_table = ipq4019_mdio_dt_ids,
  311. },
  312. };
  313. module_platform_driver(ipq4019_mdio_driver);
  314. MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
  315. MODULE_AUTHOR("Qualcomm Atheros");
  316. MODULE_LICENSE("Dual BSD/GPL");