cdns-platform.c 2.6 KB

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