phy-tegra194-p2u.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * P2U (PIPE to UPHY) driver for Tegra T194 SoC
  4. *
  5. * Copyright (C) 2019-2022 NVIDIA Corporation.
  6. *
  7. * Author: Vidya Sagar <vidyas@nvidia.com>
  8. */
  9. #include <linux/err.h>
  10. #include <linux/io.h>
  11. #include <linux/module.h>
  12. #include <linux/of.h>
  13. #include <linux/phy/phy.h>
  14. #include <linux/platform_device.h>
  15. #define P2U_CONTROL_CMN 0x74
  16. #define P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE BIT(13)
  17. #define P2U_CONTROL_CMN_SKP_SIZE_PROTECTION_EN BIT(20)
  18. #define P2U_PERIODIC_EQ_CTRL_GEN3 0xc0
  19. #define P2U_PERIODIC_EQ_CTRL_GEN3_PERIODIC_EQ_EN BIT(0)
  20. #define P2U_PERIODIC_EQ_CTRL_GEN3_INIT_PRESET_EQ_TRAIN_EN BIT(1)
  21. #define P2U_PERIODIC_EQ_CTRL_GEN4 0xc4
  22. #define P2U_PERIODIC_EQ_CTRL_GEN4_INIT_PRESET_EQ_TRAIN_EN BIT(1)
  23. #define P2U_RX_DEBOUNCE_TIME 0xa4
  24. #define P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_MASK 0xffff
  25. #define P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_VAL 160
  26. #define P2U_DIR_SEARCH_CTRL 0xd4
  27. #define P2U_DIR_SEARCH_CTRL_GEN4_FINE_GRAIN_SEARCH_TWICE BIT(18)
  28. struct tegra_p2u_of_data {
  29. bool one_dir_search;
  30. };
  31. struct tegra_p2u {
  32. void __iomem *base;
  33. bool skip_sz_protection_en; /* Needed to support two retimers */
  34. struct tegra_p2u_of_data *of_data;
  35. };
  36. static inline void p2u_writel(struct tegra_p2u *phy, const u32 value,
  37. const u32 reg)
  38. {
  39. writel_relaxed(value, phy->base + reg);
  40. }
  41. static inline u32 p2u_readl(struct tegra_p2u *phy, const u32 reg)
  42. {
  43. return readl_relaxed(phy->base + reg);
  44. }
  45. static int tegra_p2u_power_on(struct phy *x)
  46. {
  47. struct tegra_p2u *phy = phy_get_drvdata(x);
  48. u32 val;
  49. if (phy->skip_sz_protection_en) {
  50. val = p2u_readl(phy, P2U_CONTROL_CMN);
  51. val |= P2U_CONTROL_CMN_SKP_SIZE_PROTECTION_EN;
  52. p2u_writel(phy, val, P2U_CONTROL_CMN);
  53. }
  54. val = p2u_readl(phy, P2U_PERIODIC_EQ_CTRL_GEN3);
  55. val &= ~P2U_PERIODIC_EQ_CTRL_GEN3_PERIODIC_EQ_EN;
  56. val |= P2U_PERIODIC_EQ_CTRL_GEN3_INIT_PRESET_EQ_TRAIN_EN;
  57. p2u_writel(phy, val, P2U_PERIODIC_EQ_CTRL_GEN3);
  58. val = p2u_readl(phy, P2U_PERIODIC_EQ_CTRL_GEN4);
  59. val |= P2U_PERIODIC_EQ_CTRL_GEN4_INIT_PRESET_EQ_TRAIN_EN;
  60. p2u_writel(phy, val, P2U_PERIODIC_EQ_CTRL_GEN4);
  61. val = p2u_readl(phy, P2U_RX_DEBOUNCE_TIME);
  62. val &= ~P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_MASK;
  63. val |= P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_VAL;
  64. p2u_writel(phy, val, P2U_RX_DEBOUNCE_TIME);
  65. if (phy->of_data->one_dir_search) {
  66. val = p2u_readl(phy, P2U_DIR_SEARCH_CTRL);
  67. val &= ~P2U_DIR_SEARCH_CTRL_GEN4_FINE_GRAIN_SEARCH_TWICE;
  68. p2u_writel(phy, val, P2U_DIR_SEARCH_CTRL);
  69. }
  70. return 0;
  71. }
  72. static int tegra_p2u_calibrate(struct phy *x)
  73. {
  74. struct tegra_p2u *phy = phy_get_drvdata(x);
  75. u32 val;
  76. val = p2u_readl(phy, P2U_CONTROL_CMN);
  77. val |= P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE;
  78. p2u_writel(phy, val, P2U_CONTROL_CMN);
  79. return 0;
  80. }
  81. static const struct phy_ops ops = {
  82. .power_on = tegra_p2u_power_on,
  83. .calibrate = tegra_p2u_calibrate,
  84. .owner = THIS_MODULE,
  85. };
  86. static int tegra_p2u_probe(struct platform_device *pdev)
  87. {
  88. struct phy_provider *phy_provider;
  89. struct device *dev = &pdev->dev;
  90. struct phy *generic_phy;
  91. struct tegra_p2u *phy;
  92. phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
  93. if (!phy)
  94. return -ENOMEM;
  95. phy->of_data =
  96. (struct tegra_p2u_of_data *)of_device_get_match_data(dev);
  97. if (!phy->of_data)
  98. return -EINVAL;
  99. phy->base = devm_platform_ioremap_resource_byname(pdev, "ctl");
  100. if (IS_ERR(phy->base))
  101. return PTR_ERR(phy->base);
  102. phy->skip_sz_protection_en =
  103. of_property_read_bool(dev->of_node,
  104. "nvidia,skip-sz-protect-en");
  105. platform_set_drvdata(pdev, phy);
  106. generic_phy = devm_phy_create(dev, NULL, &ops);
  107. if (IS_ERR(generic_phy))
  108. return PTR_ERR(generic_phy);
  109. phy_set_drvdata(generic_phy, phy);
  110. phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
  111. if (IS_ERR(phy_provider))
  112. return PTR_ERR(phy_provider);
  113. return 0;
  114. }
  115. static const struct tegra_p2u_of_data tegra194_p2u_of_data = {
  116. .one_dir_search = false,
  117. };
  118. static const struct tegra_p2u_of_data tegra234_p2u_of_data = {
  119. .one_dir_search = true,
  120. };
  121. static const struct of_device_id tegra_p2u_id_table[] = {
  122. {
  123. .compatible = "nvidia,tegra194-p2u",
  124. .data = &tegra194_p2u_of_data,
  125. },
  126. {
  127. .compatible = "nvidia,tegra234-p2u",
  128. .data = &tegra234_p2u_of_data,
  129. },
  130. {}
  131. };
  132. MODULE_DEVICE_TABLE(of, tegra_p2u_id_table);
  133. static struct platform_driver tegra_p2u_driver = {
  134. .probe = tegra_p2u_probe,
  135. .driver = {
  136. .name = "tegra194-p2u",
  137. .of_match_table = tegra_p2u_id_table,
  138. },
  139. };
  140. module_platform_driver(tegra_p2u_driver);
  141. MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
  142. MODULE_DESCRIPTION("NVIDIA Tegra194 PIPE2UPHY PHY driver");
  143. MODULE_LICENSE("GPL v2");