dm_qe_uec_phy.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * QE UEC ethernet phy controller driver
  4. *
  5. * based on phy parts of drivers/qe/uec.c and drivers/qe/uec_phy.c
  6. * from NXP
  7. *
  8. * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
  9. */
  10. #include <common.h>
  11. #include <dm.h>
  12. #include <errno.h>
  13. #include <miiphy.h>
  14. #include <phy.h>
  15. #include <asm/io.h>
  16. #include <linux/ioport.h>
  17. #include "dm_qe_uec.h"
  18. struct qe_uec_mdio_priv {
  19. struct ucc_mii_mng *base;
  20. };
  21. static int
  22. qe_uec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
  23. {
  24. struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  25. struct ucc_mii_mng *regs = priv->base;
  26. u32 tmp_reg;
  27. u16 value;
  28. debug("%s: regs: %p addr: %x devad: %x reg: %x\n", __func__, regs,
  29. addr, devad, reg);
  30. /* Setting up the MII management Address Register */
  31. tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
  32. out_be32(&regs->miimadd, tmp_reg);
  33. /* clear MII management command cycle */
  34. out_be32(&regs->miimcom, 0);
  35. sync();
  36. /* Perform an MII management read cycle */
  37. out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
  38. /* Wait till MII management write is complete */
  39. while ((in_be32(&regs->miimind)) &
  40. (MIIMIND_NOT_VALID | MIIMIND_BUSY))
  41. ;
  42. /* Read MII management status */
  43. value = (u16)in_be32(&regs->miimstat);
  44. if (value == 0xffff)
  45. return -EINVAL;
  46. return value;
  47. };
  48. static int
  49. qe_uec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
  50. u16 value)
  51. {
  52. struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  53. struct ucc_mii_mng *regs = priv->base;
  54. u32 tmp_reg;
  55. debug("%s: regs: %p addr: %x devad: %x reg: %x val: %x\n", __func__,
  56. regs, addr, devad, reg, value);
  57. /* Stop the MII management read cycle */
  58. out_be32(&regs->miimcom, 0);
  59. /* Setting up the MII management Address Register */
  60. tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
  61. out_be32(&regs->miimadd, tmp_reg);
  62. /* Setting up the MII management Control Register with the value */
  63. out_be32(&regs->miimcon, (u32)value);
  64. sync();
  65. /* Wait till MII management write is complete */
  66. while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
  67. ;
  68. return 0;
  69. };
  70. static const struct mdio_ops qe_uec_mdio_ops = {
  71. .read = qe_uec_mdio_read,
  72. .write = qe_uec_mdio_write,
  73. };
  74. static int qe_uec_mdio_probe(struct udevice *dev)
  75. {
  76. struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  77. fdt_size_t base;
  78. ofnode node;
  79. u32 num = 0;
  80. int ret = -ENODEV;
  81. priv->base = (struct ucc_mii_mng *)dev_read_addr(dev);
  82. base = (fdt_size_t)priv->base;
  83. /*
  84. * idea from linux:
  85. * drivers/net/ethernet/freescale/fsl_pq_mdio.c
  86. *
  87. * Find the UCC node that controls the given MDIO node
  88. *
  89. * For some reason, the QE MDIO nodes are not children of the UCC
  90. * devices that control them. Therefore, we need to scan all UCC
  91. * nodes looking for the one that encompases the given MDIO node.
  92. * We do this by comparing physical addresses. The 'start' and
  93. * 'end' addresses of the MDIO node are passed, and the correct
  94. * UCC node will cover the entire address range.
  95. */
  96. node = ofnode_by_compatible(ofnode_null(), "ucc_geth");
  97. while (ofnode_valid(node)) {
  98. fdt_size_t size;
  99. fdt_addr_t addr;
  100. addr = ofnode_get_addr_index(node, 0);
  101. ret = ofnode_get_addr_size_index(node, 0, &size);
  102. if (addr == FDT_ADDR_T_NONE) {
  103. node = ofnode_by_compatible(node, "ucc_geth");
  104. continue;
  105. }
  106. /* check if priv->base in start end */
  107. if (base > addr && base < (addr + size)) {
  108. ret = ofnode_read_u32(node, "cell-index", &num);
  109. if (ret)
  110. ret = ofnode_read_u32(node, "device-id",
  111. &num);
  112. break;
  113. }
  114. node = ofnode_by_compatible(node, "ucc_geth");
  115. }
  116. if (ret) {
  117. printf("%s: no cell-index nor device-id found!", __func__);
  118. return ret;
  119. }
  120. /* Setup MII master clock source */
  121. qe_set_mii_clk_src(num - 1);
  122. return 0;
  123. }
  124. static const struct udevice_id qe_uec_mdio_ids[] = {
  125. { .compatible = "fsl,ucc-mdio" },
  126. { }
  127. };
  128. U_BOOT_DRIVER(mvmdio) = {
  129. .name = "qe_uec_mdio",
  130. .id = UCLASS_MDIO,
  131. .of_match = qe_uec_mdio_ids,
  132. .probe = qe_uec_mdio_probe,
  133. .ops = &qe_uec_mdio_ops,
  134. .priv_auto_alloc_size = sizeof(struct qe_uec_mdio_priv),
  135. };