cdns-platform.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /**
  3. * cdns-platform.c - Platform driver for Cadence UFSHCI device
  4. *
  5. * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
  6. */
  7. #include <clk.h>
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <ufs.h>
  11. #include <dm/device_compat.h>
  12. #include <linux/bitops.h>
  13. #include <linux/err.h>
  14. #include "ufs.h"
  15. #define USEC_PER_SEC 1000000L
  16. #define CDNS_UFS_REG_HCLKDIV 0xFC
  17. #define CDNS_UFS_REG_PHY_XCFGD1 0x113C
  18. static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
  19. enum ufs_notify_change_status status)
  20. {
  21. hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
  22. switch (status) {
  23. case PRE_CHANGE:
  24. return ufshcd_dme_set(hba,
  25. UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
  26. 0);
  27. case POST_CHANGE:
  28. ;
  29. }
  30. return 0;
  31. }
  32. static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
  33. {
  34. struct clk clk;
  35. unsigned long core_clk_rate = 0;
  36. u32 core_clk_div = 0;
  37. int ret;
  38. ret = clk_get_by_name(hba->dev, "core_clk", &clk);
  39. if (ret) {
  40. dev_err(hba->dev, "failed to get core_clk clock\n");
  41. return ret;
  42. }
  43. core_clk_rate = clk_get_rate(&clk);
  44. if (IS_ERR_VALUE(core_clk_rate)) {
  45. dev_err(hba->dev, "%s: unable to find core_clk rate\n",
  46. __func__);
  47. return core_clk_rate;
  48. }
  49. core_clk_div = core_clk_rate / USEC_PER_SEC;
  50. ufshcd_writel(hba, core_clk_div, CDNS_UFS_REG_HCLKDIV);
  51. return 0;
  52. }
  53. static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
  54. enum ufs_notify_change_status status)
  55. {
  56. switch (status) {
  57. case PRE_CHANGE:
  58. return cdns_ufs_set_hclkdiv(hba);
  59. case POST_CHANGE:
  60. ;
  61. }
  62. return 0;
  63. }
  64. static int cdns_ufs_init(struct ufs_hba *hba)
  65. {
  66. u32 data;
  67. /* Increase RX_Advanced_Min_ActivateTime_Capability */
  68. data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1);
  69. data |= BIT(24);
  70. ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1);
  71. return 0;
  72. }
  73. static struct ufs_hba_ops cdns_pltfm_hba_ops = {
  74. .init = cdns_ufs_init,
  75. .hce_enable_notify = cdns_ufs_hce_enable_notify,
  76. .link_startup_notify = cdns_ufs_link_startup_notify,
  77. };
  78. static int cdns_ufs_pltfm_probe(struct udevice *dev)
  79. {
  80. int err = ufshcd_probe(dev, &cdns_pltfm_hba_ops);
  81. if (err)
  82. dev_err(dev, "ufshcd_probe() failed %d\n", err);
  83. return err;
  84. }
  85. static int cdns_ufs_pltfm_bind(struct udevice *dev)
  86. {
  87. struct udevice *scsi_dev;
  88. return ufs_scsi_bind(dev, &scsi_dev);
  89. }
  90. static const struct udevice_id cdns_ufs_pltfm_ids[] = {
  91. {
  92. .compatible = "cdns,ufshc-m31-16nm",
  93. },
  94. {},
  95. };
  96. U_BOOT_DRIVER(cdns_ufs_pltfm) = {
  97. .name = "cdns-ufs-pltfm",
  98. .id = UCLASS_UFS,
  99. .of_match = cdns_ufs_pltfm_ids,
  100. .probe = cdns_ufs_pltfm_probe,
  101. .bind = cdns_ufs_pltfm_bind,
  102. };