cvmx-helper-jtag.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 Marvell International Ltd.
  4. *
  5. * Helper utilities for qlm_jtag.
  6. */
  7. #include <log.h>
  8. #include <asm/global_data.h>
  9. #include <linux/delay.h>
  10. #include <mach/cvmx-regs.h>
  11. #include <mach/octeon-model.h>
  12. #include <mach/cvmx-fuse.h>
  13. #include <mach/octeon-feature.h>
  14. #include <mach/cvmx-qlm.h>
  15. #include <mach/octeon_qlm.h>
  16. #include <mach/cvmx-pcie.h>
  17. #include <mach/cvmx-ciu-defs.h>
  18. DECLARE_GLOBAL_DATA_PTR;
  19. /**
  20. * Initialize the internal QLM JTAG logic to allow programming
  21. * of the JTAG chain by the cvmx_helper_qlm_jtag_*() functions.
  22. * These functions should only be used at the direction of Cavium
  23. * Networks. Programming incorrect values into the JTAG chain
  24. * can cause chip damage.
  25. */
  26. void cvmx_helper_qlm_jtag_init(void)
  27. {
  28. union cvmx_ciu_qlm_jtgc jtgc;
  29. int clock_div = 0;
  30. int divisor;
  31. divisor = gd->bus_clk / (1000000 * (OCTEON_IS_MODEL(OCTEON_CN68XX) ? 10 : 25));
  32. divisor = (divisor - 1) >> 2;
  33. /* Convert the divisor into a power of 2 shift */
  34. while (divisor) {
  35. clock_div++;
  36. divisor >>= 1;
  37. }
  38. /*
  39. * Clock divider for QLM JTAG operations. sclk is divided by
  40. * 2^(CLK_DIV + 2)
  41. */
  42. jtgc.u64 = 0;
  43. jtgc.s.clk_div = clock_div;
  44. jtgc.s.mux_sel = 0;
  45. if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX))
  46. jtgc.s.bypass = 0x7;
  47. else
  48. jtgc.s.bypass = 0xf;
  49. if (OCTEON_IS_MODEL(OCTEON_CN68XX))
  50. jtgc.s.bypass_ext = 1;
  51. csr_wr(CVMX_CIU_QLM_JTGC, jtgc.u64);
  52. csr_rd(CVMX_CIU_QLM_JTGC);
  53. }
  54. /**
  55. * Write up to 32bits into the QLM jtag chain. Bits are shifted
  56. * into the MSB and out the LSB, so you should shift in the low
  57. * order bits followed by the high order bits. The JTAG chain for
  58. * CN52XX and CN56XX is 4 * 268 bits long, or 1072. The JTAG chain
  59. * for CN63XX is 4 * 300 bits long, or 1200.
  60. *
  61. * @param qlm QLM to shift value into
  62. * @param bits Number of bits to shift in (1-32).
  63. * @param data Data to shift in. Bit 0 enters the chain first, followed by
  64. * bit 1, etc.
  65. *
  66. * Return: The low order bits of the JTAG chain that shifted out of the
  67. * circle.
  68. */
  69. uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data)
  70. {
  71. union cvmx_ciu_qlm_jtgc jtgc;
  72. union cvmx_ciu_qlm_jtgd jtgd;
  73. jtgc.u64 = csr_rd(CVMX_CIU_QLM_JTGC);
  74. jtgc.s.mux_sel = qlm;
  75. csr_wr(CVMX_CIU_QLM_JTGC, jtgc.u64);
  76. csr_rd(CVMX_CIU_QLM_JTGC);
  77. jtgd.u64 = 0;
  78. jtgd.s.shift = 1;
  79. jtgd.s.shft_cnt = bits - 1;
  80. jtgd.s.shft_reg = data;
  81. jtgd.s.select = 1 << qlm;
  82. csr_wr(CVMX_CIU_QLM_JTGD, jtgd.u64);
  83. do {
  84. jtgd.u64 = csr_rd(CVMX_CIU_QLM_JTGD);
  85. } while (jtgd.s.shift);
  86. return jtgd.s.shft_reg >> (32 - bits);
  87. }
  88. /**
  89. * Shift long sequences of zeros into the QLM JTAG chain. It is
  90. * common to need to shift more than 32 bits of zeros into the
  91. * chain. This function is a convience wrapper around
  92. * cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of
  93. * zeros at a time.
  94. *
  95. * @param qlm QLM to shift zeros into
  96. * @param bits
  97. */
  98. void cvmx_helper_qlm_jtag_shift_zeros(int qlm, int bits)
  99. {
  100. while (bits > 0) {
  101. int n = bits;
  102. if (n > 32)
  103. n = 32;
  104. cvmx_helper_qlm_jtag_shift(qlm, n, 0);
  105. bits -= n;
  106. }
  107. }
  108. /**
  109. * Program the QLM JTAG chain into all lanes of the QLM. You must
  110. * have already shifted in the proper number of bits into the
  111. * JTAG chain. Updating invalid values can possibly cause chip damage.
  112. *
  113. * @param qlm QLM to program
  114. */
  115. void cvmx_helper_qlm_jtag_update(int qlm)
  116. {
  117. union cvmx_ciu_qlm_jtgc jtgc;
  118. union cvmx_ciu_qlm_jtgd jtgd;
  119. jtgc.u64 = csr_rd(CVMX_CIU_QLM_JTGC);
  120. jtgc.s.mux_sel = qlm;
  121. csr_wr(CVMX_CIU_QLM_JTGC, jtgc.u64);
  122. csr_rd(CVMX_CIU_QLM_JTGC);
  123. /* Update the new data */
  124. jtgd.u64 = 0;
  125. jtgd.s.update = 1;
  126. jtgd.s.select = 1 << qlm;
  127. csr_wr(CVMX_CIU_QLM_JTGD, jtgd.u64);
  128. do {
  129. jtgd.u64 = csr_rd(CVMX_CIU_QLM_JTGD);
  130. } while (jtgd.s.update);
  131. }
  132. /**
  133. * Load the QLM JTAG chain with data from all lanes of the QLM.
  134. *
  135. * @param qlm QLM to program
  136. */
  137. void cvmx_helper_qlm_jtag_capture(int qlm)
  138. {
  139. union cvmx_ciu_qlm_jtgc jtgc;
  140. union cvmx_ciu_qlm_jtgd jtgd;
  141. jtgc.u64 = csr_rd(CVMX_CIU_QLM_JTGC);
  142. jtgc.s.mux_sel = qlm;
  143. csr_wr(CVMX_CIU_QLM_JTGC, jtgc.u64);
  144. csr_rd(CVMX_CIU_QLM_JTGC);
  145. jtgd.u64 = 0;
  146. jtgd.s.capture = 1;
  147. jtgd.s.select = 1 << qlm;
  148. csr_wr(CVMX_CIU_QLM_JTGD, jtgd.u64);
  149. do {
  150. jtgd.u64 = csr_rd(CVMX_CIU_QLM_JTGD);
  151. } while (jtgd.s.capture);
  152. }