mdio-mux-bcm-iproc.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Copyright 2016 Broadcom
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License, version 2, as
  6. * published by the Free Software Foundation (the "GPL").
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * General Public License version 2 (GPLv2) for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * version 2 (GPLv2) along with this source code.
  15. */
  16. #include <linux/clk.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/device.h>
  19. #include <linux/of_mdio.h>
  20. #include <linux/module.h>
  21. #include <linux/phy.h>
  22. #include <linux/mdio-mux.h>
  23. #include <linux/delay.h>
  24. #define MDIO_RATE_ADJ_EXT_OFFSET 0x000
  25. #define MDIO_RATE_ADJ_INT_OFFSET 0x004
  26. #define MDIO_RATE_ADJ_DIVIDENT_SHIFT 16
  27. #define MDIO_SCAN_CTRL_OFFSET 0x008
  28. #define MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR 28
  29. #define MDIO_PARAM_OFFSET 0x23c
  30. #define MDIO_PARAM_MIIM_CYCLE 29
  31. #define MDIO_PARAM_INTERNAL_SEL 25
  32. #define MDIO_PARAM_BUS_ID 22
  33. #define MDIO_PARAM_C45_SEL 21
  34. #define MDIO_PARAM_PHY_ID 16
  35. #define MDIO_PARAM_PHY_DATA 0
  36. #define MDIO_READ_OFFSET 0x240
  37. #define MDIO_READ_DATA_MASK 0xffff
  38. #define MDIO_ADDR_OFFSET 0x244
  39. #define MDIO_CTRL_OFFSET 0x248
  40. #define MDIO_CTRL_WRITE_OP 0x1
  41. #define MDIO_CTRL_READ_OP 0x2
  42. #define MDIO_STAT_OFFSET 0x24c
  43. #define MDIO_STAT_DONE 1
  44. #define BUS_MAX_ADDR 32
  45. #define EXT_BUS_START_ADDR 16
  46. #define MDIO_REG_ADDR_SPACE_SIZE 0x250
  47. #define MDIO_OPERATING_FREQUENCY 11000000
  48. #define MDIO_RATE_ADJ_DIVIDENT 1
  49. struct iproc_mdiomux_desc {
  50. void *mux_handle;
  51. void __iomem *base;
  52. struct device *dev;
  53. struct mii_bus *mii_bus;
  54. struct clk *core_clk;
  55. };
  56. static void mdio_mux_iproc_config(struct iproc_mdiomux_desc *md)
  57. {
  58. u32 divisor;
  59. u32 val;
  60. /* Disable external mdio master access */
  61. val = readl(md->base + MDIO_SCAN_CTRL_OFFSET);
  62. val |= BIT(MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR);
  63. writel(val, md->base + MDIO_SCAN_CTRL_OFFSET);
  64. if (md->core_clk) {
  65. /* use rate adjust regs to derrive the mdio's operating
  66. * frequency from the specified core clock
  67. */
  68. divisor = clk_get_rate(md->core_clk) / MDIO_OPERATING_FREQUENCY;
  69. divisor = divisor / (MDIO_RATE_ADJ_DIVIDENT + 1);
  70. val = divisor;
  71. val |= MDIO_RATE_ADJ_DIVIDENT << MDIO_RATE_ADJ_DIVIDENT_SHIFT;
  72. writel(val, md->base + MDIO_RATE_ADJ_EXT_OFFSET);
  73. writel(val, md->base + MDIO_RATE_ADJ_INT_OFFSET);
  74. }
  75. }
  76. static int iproc_mdio_wait_for_idle(void __iomem *base, bool result)
  77. {
  78. unsigned int timeout = 1000; /* loop for 1s */
  79. u32 val;
  80. do {
  81. val = readl(base + MDIO_STAT_OFFSET);
  82. if ((val & MDIO_STAT_DONE) == result)
  83. return 0;
  84. usleep_range(1000, 2000);
  85. } while (timeout--);
  86. return -ETIMEDOUT;
  87. }
  88. /* start_miim_ops- Program and start MDIO transaction over mdio bus.
  89. * @base: Base address
  90. * @phyid: phyid of the selected bus.
  91. * @reg: register offset to be read/written.
  92. * @val :0 if read op else value to be written in @reg;
  93. * @op: Operation that need to be carried out.
  94. * MDIO_CTRL_READ_OP: Read transaction.
  95. * MDIO_CTRL_WRITE_OP: Write transaction.
  96. *
  97. * Return value: Successful Read operation returns read reg values and write
  98. * operation returns 0. Failure operation returns negative error code.
  99. */
  100. static int start_miim_ops(void __iomem *base,
  101. u16 phyid, u32 reg, u16 val, u32 op)
  102. {
  103. u32 param;
  104. int ret;
  105. writel(0, base + MDIO_CTRL_OFFSET);
  106. ret = iproc_mdio_wait_for_idle(base, 0);
  107. if (ret)
  108. goto err;
  109. param = readl(base + MDIO_PARAM_OFFSET);
  110. param |= phyid << MDIO_PARAM_PHY_ID;
  111. param |= val << MDIO_PARAM_PHY_DATA;
  112. if (reg & MII_ADDR_C45)
  113. param |= BIT(MDIO_PARAM_C45_SEL);
  114. writel(param, base + MDIO_PARAM_OFFSET);
  115. writel(reg, base + MDIO_ADDR_OFFSET);
  116. writel(op, base + MDIO_CTRL_OFFSET);
  117. ret = iproc_mdio_wait_for_idle(base, 1);
  118. if (ret)
  119. goto err;
  120. if (op == MDIO_CTRL_READ_OP)
  121. ret = readl(base + MDIO_READ_OFFSET) & MDIO_READ_DATA_MASK;
  122. err:
  123. return ret;
  124. }
  125. static int iproc_mdiomux_read(struct mii_bus *bus, int phyid, int reg)
  126. {
  127. struct iproc_mdiomux_desc *md = bus->priv;
  128. int ret;
  129. ret = start_miim_ops(md->base, phyid, reg, 0, MDIO_CTRL_READ_OP);
  130. if (ret < 0)
  131. dev_err(&bus->dev, "mdiomux read operation failed!!!");
  132. return ret;
  133. }
  134. static int iproc_mdiomux_write(struct mii_bus *bus,
  135. int phyid, int reg, u16 val)
  136. {
  137. struct iproc_mdiomux_desc *md = bus->priv;
  138. int ret;
  139. /* Write val at reg offset */
  140. ret = start_miim_ops(md->base, phyid, reg, val, MDIO_CTRL_WRITE_OP);
  141. if (ret < 0)
  142. dev_err(&bus->dev, "mdiomux write operation failed!!!");
  143. return ret;
  144. }
  145. static int mdio_mux_iproc_switch_fn(int current_child, int desired_child,
  146. void *data)
  147. {
  148. struct iproc_mdiomux_desc *md = data;
  149. u32 param, bus_id;
  150. bool bus_dir;
  151. /* select bus and its properties */
  152. bus_dir = (desired_child < EXT_BUS_START_ADDR);
  153. bus_id = bus_dir ? desired_child : (desired_child - EXT_BUS_START_ADDR);
  154. param = (bus_dir ? 1 : 0) << MDIO_PARAM_INTERNAL_SEL;
  155. param |= (bus_id << MDIO_PARAM_BUS_ID);
  156. writel(param, md->base + MDIO_PARAM_OFFSET);
  157. return 0;
  158. }
  159. static int mdio_mux_iproc_probe(struct platform_device *pdev)
  160. {
  161. struct iproc_mdiomux_desc *md;
  162. struct mii_bus *bus;
  163. struct resource *res;
  164. int rc;
  165. md = devm_kzalloc(&pdev->dev, sizeof(*md), GFP_KERNEL);
  166. if (!md)
  167. return -ENOMEM;
  168. md->dev = &pdev->dev;
  169. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  170. if (res->start & 0xfff) {
  171. /* For backward compatibility in case the
  172. * base address is specified with an offset.
  173. */
  174. dev_info(&pdev->dev, "fix base address in dt-blob\n");
  175. res->start &= ~0xfff;
  176. res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1;
  177. }
  178. md->base = devm_ioremap_resource(&pdev->dev, res);
  179. if (IS_ERR(md->base)) {
  180. dev_err(&pdev->dev, "failed to ioremap register\n");
  181. return PTR_ERR(md->base);
  182. }
  183. md->mii_bus = devm_mdiobus_alloc(&pdev->dev);
  184. if (!md->mii_bus) {
  185. dev_err(&pdev->dev, "mdiomux bus alloc failed\n");
  186. return -ENOMEM;
  187. }
  188. md->core_clk = devm_clk_get(&pdev->dev, NULL);
  189. if (md->core_clk == ERR_PTR(-ENOENT) ||
  190. md->core_clk == ERR_PTR(-EINVAL))
  191. md->core_clk = NULL;
  192. else if (IS_ERR(md->core_clk))
  193. return PTR_ERR(md->core_clk);
  194. rc = clk_prepare_enable(md->core_clk);
  195. if (rc) {
  196. dev_err(&pdev->dev, "failed to enable core clk\n");
  197. return rc;
  198. }
  199. bus = md->mii_bus;
  200. bus->priv = md;
  201. bus->name = "iProc MDIO mux bus";
  202. snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
  203. bus->parent = &pdev->dev;
  204. bus->read = iproc_mdiomux_read;
  205. bus->write = iproc_mdiomux_write;
  206. bus->phy_mask = ~0;
  207. bus->dev.of_node = pdev->dev.of_node;
  208. rc = mdiobus_register(bus);
  209. if (rc) {
  210. dev_err(&pdev->dev, "mdiomux registration failed\n");
  211. goto out_clk;
  212. }
  213. platform_set_drvdata(pdev, md);
  214. rc = mdio_mux_init(md->dev, md->dev->of_node, mdio_mux_iproc_switch_fn,
  215. &md->mux_handle, md, md->mii_bus);
  216. if (rc) {
  217. dev_info(md->dev, "mdiomux initialization failed\n");
  218. goto out_register;
  219. }
  220. mdio_mux_iproc_config(md);
  221. dev_info(md->dev, "iProc mdiomux registered\n");
  222. return 0;
  223. out_register:
  224. mdiobus_unregister(bus);
  225. out_clk:
  226. clk_disable_unprepare(md->core_clk);
  227. return rc;
  228. }
  229. static int mdio_mux_iproc_remove(struct platform_device *pdev)
  230. {
  231. struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
  232. mdio_mux_uninit(md->mux_handle);
  233. mdiobus_unregister(md->mii_bus);
  234. clk_disable_unprepare(md->core_clk);
  235. return 0;
  236. }
  237. #ifdef CONFIG_PM_SLEEP
  238. static int mdio_mux_iproc_suspend(struct device *dev)
  239. {
  240. struct platform_device *pdev = to_platform_device(dev);
  241. struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
  242. clk_disable_unprepare(md->core_clk);
  243. return 0;
  244. }
  245. static int mdio_mux_iproc_resume(struct device *dev)
  246. {
  247. struct platform_device *pdev = to_platform_device(dev);
  248. struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
  249. int rc;
  250. rc = clk_prepare_enable(md->core_clk);
  251. if (rc) {
  252. dev_err(md->dev, "failed to enable core clk\n");
  253. return rc;
  254. }
  255. mdio_mux_iproc_config(md);
  256. return 0;
  257. }
  258. #endif
  259. static SIMPLE_DEV_PM_OPS(mdio_mux_iproc_pm_ops,
  260. mdio_mux_iproc_suspend, mdio_mux_iproc_resume);
  261. static const struct of_device_id mdio_mux_iproc_match[] = {
  262. {
  263. .compatible = "brcm,mdio-mux-iproc",
  264. },
  265. {},
  266. };
  267. MODULE_DEVICE_TABLE(of, mdio_mux_iproc_match);
  268. static struct platform_driver mdiomux_iproc_driver = {
  269. .driver = {
  270. .name = "mdio-mux-iproc",
  271. .of_match_table = mdio_mux_iproc_match,
  272. .pm = &mdio_mux_iproc_pm_ops,
  273. },
  274. .probe = mdio_mux_iproc_probe,
  275. .remove = mdio_mux_iproc_remove,
  276. };
  277. module_platform_driver(mdiomux_iproc_driver);
  278. MODULE_DESCRIPTION("iProc MDIO Mux Bus Driver");
  279. MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
  280. MODULE_LICENSE("GPL v2");