armpll.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2014 Broadcom Corporation.
  4. */
  5. #include <common.h>
  6. #include <asm/io.h>
  7. #include <asm/iproc-common/armpll.h>
  8. #include <asm/iproc-common/sysmap.h>
  9. #define NELEMS(x) (sizeof(x) / sizeof(x[0]))
  10. struct armpll_parameters {
  11. unsigned int mode;
  12. unsigned int ndiv_int;
  13. unsigned int ndiv_frac;
  14. unsigned int pdiv;
  15. unsigned int freqid;
  16. };
  17. struct armpll_parameters armpll_clk_tab[] = {
  18. { 25, 64, 1, 1, 0},
  19. { 100, 64, 1, 1, 2},
  20. { 400, 64, 1, 1, 6},
  21. { 448, 71, 713050, 1, 6},
  22. { 500, 80, 1, 1, 6},
  23. { 560, 89, 629145, 1, 6},
  24. { 600, 96, 1, 1, 6},
  25. { 800, 64, 1, 1, 7},
  26. { 896, 71, 713050, 1, 7},
  27. { 1000, 80, 1, 1, 7},
  28. { 1100, 88, 1, 1, 7},
  29. { 1120, 89, 629145, 1, 7},
  30. { 1200, 96, 1, 1, 7},
  31. };
  32. uint32_t armpll_config(uint32_t clkmhz)
  33. {
  34. uint32_t freqid;
  35. uint32_t ndiv_frac;
  36. uint32_t pll;
  37. uint32_t status = 1;
  38. uint32_t timeout_countdown;
  39. int i;
  40. for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
  41. if (armpll_clk_tab[i].mode == clkmhz) {
  42. status = 0;
  43. break;
  44. }
  45. }
  46. if (status) {
  47. printf("Error: Clock configuration not supported\n");
  48. goto armpll_config_done;
  49. }
  50. /* Enable write access */
  51. writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
  52. if (clkmhz == 25)
  53. freqid = 0;
  54. else
  55. freqid = 2;
  56. /* Bypass ARM clock and run on sysclk */
  57. writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
  58. freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
  59. freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
  60. freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
  61. freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
  62. IHOST_PROC_CLK_POLICY_FREQ);
  63. writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
  64. 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
  65. IHOST_PROC_CLK_POLICY_CTL);
  66. /* Poll CCU until operation complete */
  67. timeout_countdown = 0x100000;
  68. while (readl(IHOST_PROC_CLK_POLICY_CTL) &
  69. (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
  70. timeout_countdown--;
  71. if (timeout_countdown == 0) {
  72. printf("CCU polling timedout\n");
  73. status = 1;
  74. goto armpll_config_done;
  75. }
  76. }
  77. if (clkmhz == 25 || clkmhz == 100) {
  78. status = 0;
  79. goto armpll_config_done;
  80. }
  81. /* Now it is safe to program the PLL */
  82. pll = readl(IHOST_PROC_CLK_PLLARMB);
  83. pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
  84. ndiv_frac =
  85. ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
  86. (armpll_clk_tab[i].ndiv_frac <<
  87. IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
  88. pll |= ndiv_frac;
  89. writel(pll, IHOST_PROC_CLK_PLLARMB);
  90. writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
  91. armpll_clk_tab[i].ndiv_int <<
  92. IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
  93. armpll_clk_tab[i].pdiv <<
  94. IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
  95. 1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
  96. IHOST_PROC_CLK_PLLARMA);
  97. /* Poll ARM PLL Lock until operation complete */
  98. timeout_countdown = 0x100000;
  99. while (readl(IHOST_PROC_CLK_PLLARMA) &
  100. (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
  101. timeout_countdown--;
  102. if (timeout_countdown == 0) {
  103. printf("ARM PLL lock failed\n");
  104. status = 1;
  105. goto armpll_config_done;
  106. }
  107. }
  108. pll = readl(IHOST_PROC_CLK_PLLARMA);
  109. pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
  110. writel(pll, IHOST_PROC_CLK_PLLARMA);
  111. /* Set the policy */
  112. writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
  113. armpll_clk_tab[i].freqid <<
  114. IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
  115. armpll_clk_tab[i].freqid <<
  116. IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
  117. armpll_clk_tab[i].freqid <<
  118. IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
  119. armpll_clk_tab[i+4].freqid <<
  120. IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
  121. IHOST_PROC_CLK_POLICY_FREQ);
  122. writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
  123. writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
  124. writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
  125. writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
  126. writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
  127. writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
  128. 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
  129. IHOST_PROC_CLK_POLICY_CTL);
  130. /* Poll CCU until operation complete */
  131. timeout_countdown = 0x100000;
  132. while (readl(IHOST_PROC_CLK_POLICY_CTL) &
  133. (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
  134. timeout_countdown--;
  135. if (timeout_countdown == 0) {
  136. printf("CCU polling failed\n");
  137. status = 1;
  138. goto armpll_config_done;
  139. }
  140. }
  141. status = 0;
  142. armpll_config_done:
  143. /* Disable access to PLL registers */
  144. writel(0, IHOST_PROC_CLK_WR_ACCESS);
  145. return status;
  146. }