hbmc-am654.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
  4. // Author: Vignesh Raghavendra <vigneshr@ti.com>
  5. #include <common.h>
  6. #include <asm/io.h>
  7. #include <dm.h>
  8. #include <regmap.h>
  9. #include <syscon.h>
  10. #include <dm/device_compat.h>
  11. #define FSS_SYSC_REG 0x4
  12. #define HYPERBUS_CALIB_COUNT 25
  13. struct am654_hbmc_priv {
  14. void __iomem *mmiobase;
  15. bool calibrated;
  16. };
  17. /* Calibrate by looking for "QRY" string within the CFI space */
  18. static int am654_hyperbus_calibrate(struct udevice *dev)
  19. {
  20. struct am654_hbmc_priv *priv = dev_get_priv(dev);
  21. int count = HYPERBUS_CALIB_COUNT;
  22. int pass_count = 0;
  23. u16 qry[3];
  24. if (priv->calibrated)
  25. return 0;
  26. writew(0xF0, priv->mmiobase);
  27. writew(0x98, priv->mmiobase + 0xaa);
  28. while (count--) {
  29. qry[0] = readw(priv->mmiobase + 0x20);
  30. qry[1] = readw(priv->mmiobase + 0x22);
  31. qry[2] = readw(priv->mmiobase + 0x24);
  32. if (qry[0] == 'Q' && qry[1] == 'R' && qry[2] == 'Y')
  33. pass_count++;
  34. else
  35. pass_count = 0;
  36. if (pass_count == 5)
  37. break;
  38. }
  39. writew(0xF0, priv->mmiobase);
  40. writew(0xFF, priv->mmiobase);
  41. return pass_count == 5;
  42. }
  43. static int am654_select_hbmc(struct udevice *dev)
  44. {
  45. struct regmap *regmap = syscon_get_regmap(dev_get_parent(dev));
  46. return regmap_update_bits(regmap, FSS_SYSC_REG, 0x2, 0x2);
  47. }
  48. static int am654_hbmc_bind(struct udevice *dev)
  49. {
  50. return dm_scan_fdt_dev(dev);
  51. }
  52. static int am654_hbmc_probe(struct udevice *dev)
  53. {
  54. struct am654_hbmc_priv *priv = dev_get_priv(dev);
  55. int ret;
  56. priv->mmiobase = devfdt_remap_addr_index(dev, 1);
  57. if (dev_read_bool(dev, "mux-controls")) {
  58. ret = am654_select_hbmc(dev);
  59. if (ret) {
  60. dev_err(dev, "Failed to select HBMC mux\n");
  61. return ret;
  62. }
  63. }
  64. if (!priv->calibrated) {
  65. ret = am654_hyperbus_calibrate(dev);
  66. if (!ret) {
  67. dev_err(dev, "Calibration Failed\n");
  68. return -EIO;
  69. }
  70. }
  71. priv->calibrated = true;
  72. return 0;
  73. }
  74. static const struct udevice_id am654_hbmc_dt_ids[] = {
  75. {
  76. .compatible = "ti,am654-hbmc",
  77. },
  78. { /* end of table */ }
  79. };
  80. U_BOOT_DRIVER(hbmc_am654) = {
  81. .name = "hbmc-am654",
  82. .id = UCLASS_MTD,
  83. .of_match = am654_hbmc_dt_ids,
  84. .probe = am654_hbmc_probe,
  85. .bind = am654_hbmc_bind,
  86. .priv_auto = sizeof(struct am654_hbmc_priv),
  87. };