swreg.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Copyright (c) 2017 - 2020, Broadcom
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <stdint.h>
  9. #include <common/debug.h>
  10. #include <drivers/delay_timer.h>
  11. #include <lib/mmio.h>
  12. #include <sr_utils.h>
  13. #include <swreg.h>
  14. #define MIN_VOLT 760000
  15. #define MAX_VOLT 1060000
  16. #define BSTI_WRITE 0x1
  17. #define BSTI_READ 0x2
  18. #define BSTI_COMMAND_TA 0x2
  19. #define BSTI_COMMAND_DATA 0xFF
  20. #define BSTI_CONTROL_VAL 0x81
  21. #define BSTI_CONTROL_BUSY 0x100
  22. #define BSTI_TOGGLE_BIT 0x2
  23. #define BSTI_CONFI_DONE_MASK 0xFFFFFFFD
  24. #define BSTI_REG_DATA_MASK 0xFFFF
  25. #define BSTI_CMD(sb, op, pa, ra, ta, data) \
  26. ((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \
  27. (((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \
  28. (((ta) & 0x3) << 16) | (data))
  29. #define PHY_REG0 0x0
  30. #define PHY_REG1 0x1
  31. #define PHY_REG4 0x4
  32. #define PHY_REG5 0x5
  33. #define PHY_REG6 0x6
  34. #define PHY_REG7 0x7
  35. #define PHY_REGC 0xc
  36. #define IHOST_VDDC_DATA 0x560
  37. #define DDR_CORE_DATA 0x2560
  38. #define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1))
  39. /*
  40. * Formula for SR A2 reworked board:
  41. * step = ((vol/(1.4117 * 0.98)) - 500000)/3125
  42. * where,
  43. * vol - input voltage
  44. * 500000 - Reference voltage
  45. * 3125 - one step value
  46. */
  47. #define A2_VOL_REF 500000
  48. #define ONE_STEP_VALUE 3125
  49. #define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull)
  50. #define STEP_VALUE(vol) \
  51. ((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4)
  52. #define B0_VOL_REF ((500000/100)*98)
  53. #define B0_ONE_STEP_VALUE 3125
  54. /*
  55. * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE
  56. * step = ((vol/1.56) - (500000 * 0.98))/3125
  57. * where,
  58. * vol - input voltage
  59. * 500000 - Reference voltage
  60. * 3125 - one step value
  61. */
  62. #define B0_VOL_DIV(vol) (((vol)*100ull)/156)
  63. #define B0_STEP_VALUE(vol) \
  64. ((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
  65. & 0xFF) << 8) | 4)
  66. /*
  67. * Formula for SR B0 chip for DDR-CORE
  68. * step = ((vol/1) - (500000 * 0.98))/3125
  69. * where,
  70. * vol - input voltage
  71. * 500000 - Reference voltage
  72. * 3125 - one step value
  73. */
  74. #define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1)
  75. #define B0_DDR_VDDC_STEP_VALUE(vol) \
  76. ((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
  77. & 0xFF) << 8) | 4)
  78. #define MAX_SWREG_CNT 8
  79. #define MAX_ADDR_PER_SWREG 16
  80. #define MAX_REG_ADDR 0xF
  81. #define MIN_REG_ADDR 0x0
  82. static const char *sw_reg_name[MAX_SWREG_CNT] = {
  83. "DDR_VDDC",
  84. "IHOST03",
  85. "IHOST12",
  86. "IHOST_ARRAY",
  87. "DDRIO_SLAVE",
  88. "VDDC_CORE",
  89. "VDDC1",
  90. "DDRIO_MASTER"
  91. };
  92. /* firmware values for all SWREG for 3.3V input operation */
  93. static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = {
  94. /* DDR logic: Power Domains independent of 12v or 3p3v */
  95. {0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0,
  96. 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000},
  97. /* ihost03, 3p3V */
  98. {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
  99. 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
  100. /* ihost12 3p3v */
  101. {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
  102. 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
  103. /* ihost array */
  104. {0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0,
  105. 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000},
  106. /* ddr io slave : 3p3v */
  107. {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
  108. 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
  109. /* core master 3p3v */
  110. {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
  111. 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
  112. /* core slave 3p3v */
  113. {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
  114. 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
  115. /* ddr io master : 3p3v */
  116. {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
  117. 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
  118. };
  119. #define FM_DATA swreg_fm_data_bx
  120. static int swreg_poll(void)
  121. {
  122. uint32_t data;
  123. int retry = 100;
  124. do {
  125. data = mmio_read_32(BSTI_CONTROL_OFFSET);
  126. if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY)
  127. return 0;
  128. retry--;
  129. udelay(1);
  130. } while (retry > 0);
  131. return -ETIMEDOUT;
  132. }
  133. static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data)
  134. {
  135. uint32_t cmd;
  136. int ret;
  137. cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data);
  138. mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
  139. mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
  140. ret = swreg_poll();
  141. if (ret) {
  142. ERROR("Failed to write swreg %s addr 0x%x\n",
  143. sw_reg_name[reg_id-1], addr);
  144. return ret;
  145. }
  146. return ret;
  147. }
  148. static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data)
  149. {
  150. uint32_t cmd;
  151. int ret;
  152. cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0);
  153. mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
  154. mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
  155. ret = swreg_poll();
  156. if (ret) {
  157. ERROR("Failed to read swreg %s addr 0x%x\n",
  158. sw_reg_name[reg_id-1], addr);
  159. return ret;
  160. }
  161. *data = mmio_read_32(BSTI_COMMAND_OFFSET);
  162. *data &= BSTI_REG_DATA_MASK;
  163. return ret;
  164. }
  165. static int swreg_config_done(enum sw_reg reg_id)
  166. {
  167. uint32_t read_data;
  168. int ret;
  169. ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
  170. if (ret)
  171. return ret;
  172. read_data &= BSTI_CONFI_DONE_MASK;
  173. read_data |= BSTI_TOGGLE_BIT;
  174. ret = write_swreg_config(reg_id, PHY_REG0, read_data);
  175. if (ret)
  176. return ret;
  177. ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
  178. if (ret)
  179. return ret;
  180. read_data &= BSTI_CONFI_DONE_MASK;
  181. ret = write_swreg_config(reg_id, PHY_REG0, read_data);
  182. if (ret)
  183. return ret;
  184. return ret;
  185. }
  186. #ifdef DUMP_SWREG
  187. static void dump_swreg_firmware(void)
  188. {
  189. enum sw_reg reg_id;
  190. uint32_t data;
  191. int addr;
  192. int ret;
  193. for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
  194. INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]);
  195. for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
  196. ret = read_swreg_config(reg_id, addr, &data);
  197. if (ret)
  198. ERROR("Failed to read offset %d\n", addr);
  199. INFO("\t0x%x: 0x%04x\n", addr, data);
  200. }
  201. }
  202. }
  203. #endif
  204. int set_swreg(enum sw_reg reg_id, uint32_t micro_volts)
  205. {
  206. uint32_t step, programmed_step;
  207. uint32_t data = IHOST_VDDC_DATA;
  208. int ret;
  209. if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) {
  210. ERROR("input voltage out-of-range\n");
  211. ret = -EINVAL;
  212. goto failed;
  213. }
  214. ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step);
  215. if (ret)
  216. goto failed;
  217. if (reg_id == DDR_VDDC)
  218. step = B0_DDR_VDDC_STEP_VALUE(micro_volts);
  219. else
  220. step = B0_STEP_VALUE(micro_volts);
  221. if ((step >> 8) != (programmed_step >> 8)) {
  222. ret = write_swreg_config(reg_id, PHY_REGC, step);
  223. if (ret)
  224. goto failed;
  225. if (reg_id == DDR_VDDC)
  226. data = DDR_CORE_DATA;
  227. ret = write_swreg_config(reg_id, PHY_REG0,
  228. UPDATE_POS_EDGE(data, 1));
  229. if (ret)
  230. goto failed;
  231. ret = write_swreg_config(reg_id, PHY_REG0,
  232. UPDATE_POS_EDGE(data, 0));
  233. if (ret)
  234. goto failed;
  235. }
  236. INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1],
  237. micro_volts);
  238. return ret;
  239. failed:
  240. /*
  241. * Stop booting if voltages are not set
  242. * correctly. Booting will fail at random point
  243. * if we continue with wrong voltage settings.
  244. */
  245. ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1],
  246. micro_volts);
  247. assert(0);
  248. return ret;
  249. }
  250. /* Update SWREG firmware for all power domain for A2 chip */
  251. int swreg_firmware_update(void)
  252. {
  253. enum sw_reg reg_id;
  254. uint32_t data;
  255. int addr;
  256. int ret;
  257. /* write firmware values */
  258. for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
  259. /* write higher location first */
  260. for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) {
  261. ret = write_swreg_config(reg_id, addr,
  262. FM_DATA[reg_id - 1][addr]);
  263. if (ret)
  264. goto exit;
  265. }
  266. }
  267. /* trigger SWREG firmware update */
  268. for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
  269. /*
  270. * Slave regulator doesn't have to be updated,
  271. * Updating Master is enough
  272. */
  273. if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1))
  274. continue;
  275. ret = swreg_config_done(reg_id);
  276. if (ret) {
  277. ERROR("Failed to trigger SWREG firmware update for %s\n"
  278. , sw_reg_name[reg_id-1]);
  279. return ret;
  280. }
  281. }
  282. for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
  283. /*
  284. * IHOST_ARRAY will be used on some boards like STRATUS and
  285. * there will not be any issue even if it is updated on other
  286. * boards where it is not used.
  287. */
  288. if (reg_id == IHOST_ARRAY)
  289. continue;
  290. for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
  291. ret = read_swreg_config(reg_id, addr, &data);
  292. if (ret || (!ret &&
  293. (data != FM_DATA[reg_id - 1][addr]))) {
  294. ERROR("swreg fm update failed: %s at off %d\n",
  295. sw_reg_name[reg_id - 1], addr);
  296. ERROR("Read val: 0x%x, expected val: 0x%x\n",
  297. data, FM_DATA[reg_id - 1][addr]);
  298. return -1;
  299. }
  300. }
  301. }
  302. INFO("Updated SWREG firmware\n");
  303. #ifdef DUMP_SWREG
  304. dump_swreg_firmware();
  305. #endif
  306. return ret;
  307. exit:
  308. /*
  309. * Stop booting if swreg firmware update fails.
  310. * Booting will fail at random point if we
  311. * continue with wrong voltage settings.
  312. */
  313. ERROR("Failed to update firmware for %s SWREG\n",
  314. sw_reg_name[reg_id-1]);
  315. assert(0);
  316. return ret;
  317. }