mdio_mux_mmioreg.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) Copyright 2021 BayLibre, SAS
  4. * Author: Neil Armstrong <narmstrong@baylibre.com>
  5. *
  6. * Based on linux/drivers/net/phy/mdio-mux-mmioreg.c :
  7. * Copyright 2012 Freescale Semiconductor, Inc.
  8. */
  9. #include <dm.h>
  10. #include <errno.h>
  11. #include <log.h>
  12. #include <miiphy.h>
  13. #include <linux/io.h>
  14. struct mdio_mux_mmioreg_priv {
  15. struct udevice *chip;
  16. phys_addr_t phys;
  17. unsigned int iosize;
  18. unsigned int mask;
  19. };
  20. static int mdio_mux_mmioreg_select(struct udevice *mux, int cur, int sel)
  21. {
  22. struct mdio_mux_mmioreg_priv *priv = dev_get_priv(mux);
  23. debug("%s: %x -> %x\n", __func__, (u32)cur, (u32)sel);
  24. /* if last selection didn't change we're good to go */
  25. if (cur == sel)
  26. return 0;
  27. switch (priv->iosize) {
  28. case sizeof(u8): {
  29. u8 x, y;
  30. x = ioread8((void *)priv->phys);
  31. y = (x & ~priv->mask) | (u32)sel;
  32. if (x != y) {
  33. iowrite8((x & ~priv->mask) | sel, (void *)priv->phys);
  34. debug("%s: %02x -> %02x\n", __func__, x, y);
  35. }
  36. break;
  37. }
  38. case sizeof(u16): {
  39. u16 x, y;
  40. x = ioread16((void *)priv->phys);
  41. y = (x & ~priv->mask) | (u32)sel;
  42. if (x != y) {
  43. iowrite16((x & ~priv->mask) | sel, (void *)priv->phys);
  44. debug("%s: %04x -> %04x\n", __func__, x, y);
  45. }
  46. break;
  47. }
  48. case sizeof(u32): {
  49. u32 x, y;
  50. x = ioread32((void *)priv->phys);
  51. y = (x & ~priv->mask) | (u32)sel;
  52. if (x != y) {
  53. iowrite32((x & ~priv->mask) | sel, (void *)priv->phys);
  54. debug("%s: %08x -> %08x\n", __func__, x, y);
  55. }
  56. break;
  57. }
  58. }
  59. return 0;
  60. }
  61. static const struct mdio_mux_ops mdio_mux_mmioreg_ops = {
  62. .select = mdio_mux_mmioreg_select,
  63. };
  64. static int mdio_mux_mmioreg_probe(struct udevice *dev)
  65. {
  66. struct mdio_mux_mmioreg_priv *priv = dev_get_priv(dev);
  67. phys_addr_t reg_base, reg_size;
  68. u32 reg_mask;
  69. int err;
  70. reg_base = ofnode_get_addr_size_index(dev_ofnode(dev), 0, &reg_size);
  71. if (reg_base == FDT_ADDR_T_NONE)
  72. return -EINVAL;
  73. if (reg_size != sizeof(u8) &&
  74. reg_size != sizeof(u16) &&
  75. reg_size != sizeof(u32)) {
  76. printf("%s: only 8/16/32-bit registers are supported\n", __func__);
  77. return -EINVAL;
  78. }
  79. err = dev_read_u32(dev, "mux-mask", &reg_mask);
  80. if (err) {
  81. debug("%s: error reading mux-mask property\n", __func__);
  82. return err;
  83. }
  84. if (reg_mask >= BIT(reg_size * 8)) {
  85. printf("%s: mask doesn't fix in register width\n", __func__);
  86. return -EINVAL;
  87. }
  88. priv->phys = reg_base;
  89. priv->iosize = reg_size;
  90. priv->mask = reg_mask;
  91. debug("%s: %llx@%lld / %x\n", __func__, reg_base, reg_size, reg_mask);
  92. return 0;
  93. }
  94. static const struct udevice_id mdio_mux_mmioreg_ids[] = {
  95. { .compatible = "mdio-mux-mmioreg" },
  96. { }
  97. };
  98. U_BOOT_DRIVER(mdio_mux_mmioreg) = {
  99. .name = "mdio_mux_mmioreg",
  100. .id = UCLASS_MDIO_MUX,
  101. .of_match = mdio_mux_mmioreg_ids,
  102. .probe = mdio_mux_mmioreg_probe,
  103. .ops = &mdio_mux_mmioreg_ops,
  104. .priv_auto = sizeof(struct mdio_mux_mmioreg_priv),
  105. };