cmds.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * sl28 extension commands
  4. *
  5. * Copyright (c) 2020 Kontron Europe GmbH
  6. */
  7. #include <common.h>
  8. #include <command.h>
  9. #include <i2c.h>
  10. #include <linux/delay.h>
  11. #define CPLD_I2C_ADDR 0x4a
  12. #define REG_UFM_CTRL 0x02
  13. #define UFM_CTRL_DCLK BIT(1)
  14. #define UFM_CTRL_DIN BIT(2)
  15. #define UFM_CTRL_PROGRAM BIT(3)
  16. #define UFM_CTRL_ERASE BIT(4)
  17. #define UFM_CTRL_DSHIFT BIT(5)
  18. #define UFM_CTRL_DOUT BIT(6)
  19. #define UFM_CTRL_BUSY BIT(7)
  20. static int ufm_shift_data(struct udevice *dev, u16 data_in, u16 *data_out)
  21. {
  22. int i;
  23. int ret;
  24. u16 data = 0;
  25. /* latch data */
  26. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, 0);
  27. if (ret < 0)
  28. return ret;
  29. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
  30. if (ret < 0)
  31. return ret;
  32. /* assert drshift */
  33. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
  34. UFM_CTRL_DSHIFT | UFM_CTRL_DCLK);
  35. if (ret < 0)
  36. return ret;
  37. /* clock 16 data bits, reverse order */
  38. for (i = 15; i >= 0; i--) {
  39. u8 din = (data_in & (1 << i)) ? UFM_CTRL_DIN : 0;
  40. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DSHIFT
  41. | din);
  42. if (ret < 0)
  43. return ret;
  44. if (data_out) {
  45. ret = dm_i2c_reg_read(dev, REG_UFM_CTRL);
  46. if (ret < 0)
  47. return ret;
  48. if (ret & UFM_CTRL_DOUT)
  49. data |= (1 << i);
  50. }
  51. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
  52. UFM_CTRL_DSHIFT | UFM_CTRL_DCLK | din);
  53. if (ret < 0)
  54. return ret;
  55. }
  56. /* deassert drshift */
  57. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
  58. if (ret < 0)
  59. return ret;
  60. if (data_out)
  61. *data_out = data;
  62. return ret;
  63. }
  64. static int ufm_erase(struct udevice *dev)
  65. {
  66. int ret;
  67. /* erase, tEPMX is 500ms */
  68. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
  69. UFM_CTRL_DCLK | UFM_CTRL_ERASE);
  70. if (ret < 0)
  71. return ret;
  72. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
  73. if (ret < 0)
  74. return ret;
  75. mdelay(500);
  76. return 0;
  77. }
  78. static int ufm_program(struct udevice *dev)
  79. {
  80. int ret;
  81. /* program, tPPMX is 100us */
  82. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
  83. UFM_CTRL_DCLK | UFM_CTRL_PROGRAM);
  84. if (ret < 0)
  85. return ret;
  86. ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
  87. if (ret < 0)
  88. return ret;
  89. udelay(100);
  90. return 0;
  91. }
  92. static int ufm_write(struct udevice *dev, u16 data)
  93. {
  94. int ret;
  95. ret = ufm_shift_data(dev, data, NULL);
  96. if (ret < 0)
  97. return ret;
  98. ret = ufm_erase(dev);
  99. if (ret < 0)
  100. return ret;
  101. return ufm_program(dev);
  102. }
  103. static int ufm_read(struct udevice *dev, u16 *data)
  104. {
  105. return ufm_shift_data(dev, 0, data);
  106. }
  107. static int do_sl28_nvm(struct cmd_tbl *cmdtp, int flag, int argc,
  108. char *const argv[])
  109. {
  110. struct udevice *dev;
  111. u16 nvm;
  112. int ret;
  113. char *endp;
  114. if (i2c_get_chip_for_busnum(0, CPLD_I2C_ADDR, 1, &dev))
  115. return CMD_RET_FAILURE;
  116. if (argc > 1) {
  117. nvm = hextoul(argv[1], &endp);
  118. if (*endp != '\0') {
  119. printf("ERROR: argument is not a valid number\n");
  120. ret = -EINVAL;
  121. goto out;
  122. }
  123. /*
  124. * We swap all bits, because the a zero bit in hardware means the
  125. * feature is enabled. But this is hard for the user.
  126. */
  127. nvm ^= 0xffff;
  128. ret = ufm_write(dev, nvm);
  129. if (ret)
  130. goto out;
  131. printf("New settings will be activated after the next power cycle!\n");
  132. } else {
  133. ret = ufm_read(dev, &nvm);
  134. if (ret)
  135. goto out;
  136. nvm ^= 0xffff;
  137. printf("%04hx\n", nvm);
  138. }
  139. return CMD_RET_SUCCESS;
  140. out:
  141. printf("command failed (%d)\n", ret);
  142. return CMD_RET_FAILURE;
  143. }
  144. static char sl28_help_text[] =
  145. "nvm [<hex>] - display/set the 16 non-volatile bits\n";
  146. U_BOOT_CMD_WITH_SUBCMDS(sl28, "SMARC-sAL28 specific", sl28_help_text,
  147. U_BOOT_SUBCMD_MKENT(nvm, 2, 1, do_sl28_nvm));