chipcHw_init.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*****************************************************************************
  2. * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
  3. *
  4. * Unless you and Broadcom execute a separate written software license
  5. * agreement governing use of this software, this software is licensed to you
  6. * under the terms of the GNU General Public License version 2, available at
  7. * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  8. *
  9. * Notwithstanding the above, under no circumstances may you combine this
  10. * software in any way with any other Broadcom software provided under a
  11. * license other than the GPL, without Broadcom's express prior written
  12. * consent.
  13. *****************************************************************************/
  14. /****************************************************************************/
  15. /**
  16. * @file chipcHw_init.c
  17. *
  18. * @brief Low level CHIPC PLL configuration functions
  19. *
  20. * @note
  21. *
  22. * These routines provide basic PLL controlling functionality only.
  23. */
  24. /****************************************************************************/
  25. /* ---- Include Files ---------------------------------------------------- */
  26. #include <linux/errno.h>
  27. #include <linux/types.h>
  28. #include <linux/export.h>
  29. #include <mach/csp/chipcHw_def.h>
  30. #include <mach/csp/chipcHw_inline.h>
  31. #include <mach/csp/reg.h>
  32. #include <linux/delay.h>
  33. /* ---- Private Constants and Types --------------------------------------- */
  34. /*
  35. Calculation for NDIV_i to obtain VCO frequency
  36. -----------------------------------------------
  37. Freq_vco = Freq_ref * (P2 / P1) * (PLL_NDIV_i + PLL_NDIV_f)
  38. for Freq_vco = VCO_FREQ_MHz
  39. Freq_ref = chipcHw_XTAL_FREQ_Hz
  40. PLL_P1 = PLL_P2 = 1
  41. and
  42. PLL_NDIV_f = 0
  43. We get:
  44. PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz
  45. Calculation for PLL MDIV to obtain frequency Freq_x for channel x
  46. -----------------------------------------------------------------
  47. Freq_x = chipcHw_XTAL_FREQ_Hz * PLL_NDIV_i / PLL_MDIV_x = VCO_FREQ_MHz / PLL_MDIV_x
  48. PLL_MDIV_x = VCO_FREQ_MHz / Freq_x
  49. */
  50. /* ---- Private Variables ------------------------------------------------- */
  51. /****************************************************************************/
  52. /**
  53. * @brief Initializes the PLL2
  54. *
  55. * This function initializes the PLL2
  56. *
  57. */
  58. /****************************************************************************/
  59. void chipcHw_pll2Enable(uint32_t vcoFreqHz)
  60. {
  61. uint32_t pllPreDivider2 = 0;
  62. {
  63. REG_LOCAL_IRQ_SAVE;
  64. writel(chipcHw_REG_PLL_CONFIG_D_RESET |
  65. chipcHw_REG_PLL_CONFIG_A_RESET,
  66. &pChipcHw->PLLConfig2);
  67. pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
  68. chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
  69. (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) <<
  70. chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
  71. (chipcHw_REG_PLL_PREDIVIDER_P1 <<
  72. chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
  73. (chipcHw_REG_PLL_PREDIVIDER_P2 <<
  74. chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
  75. /* Enable CHIPC registers to control the PLL */
  76. writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
  77. /* Set pre divider to get desired VCO frequency */
  78. writel(pllPreDivider2, &pChipcHw->PLLPreDivider2);
  79. /* Set NDIV Frac */
  80. writel(chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider2);
  81. /* This has to be removed once the default values are fixed for PLL2. */
  82. writel(0x38000700, &pChipcHw->PLLControl12);
  83. writel(0x00000015, &pChipcHw->PLLControl22);
  84. /* Reset PLL2 */
  85. if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
  86. writel(chipcHw_REG_PLL_CONFIG_D_RESET |
  87. chipcHw_REG_PLL_CONFIG_A_RESET |
  88. chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
  89. chipcHw_REG_PLL_CONFIG_POWER_DOWN,
  90. &pChipcHw->PLLConfig2);
  91. } else {
  92. writel(chipcHw_REG_PLL_CONFIG_D_RESET |
  93. chipcHw_REG_PLL_CONFIG_A_RESET |
  94. chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
  95. chipcHw_REG_PLL_CONFIG_POWER_DOWN,
  96. &pChipcHw->PLLConfig2);
  97. }
  98. REG_LOCAL_IRQ_RESTORE;
  99. }
  100. /* Insert certain amount of delay before deasserting ARESET. */
  101. udelay(1);
  102. {
  103. REG_LOCAL_IRQ_SAVE;
  104. /* Remove analog reset and Power on the PLL */
  105. writel(readl(&pChipcHw->PLLConfig2) &
  106. ~(chipcHw_REG_PLL_CONFIG_A_RESET |
  107. chipcHw_REG_PLL_CONFIG_POWER_DOWN),
  108. &pChipcHw->PLLConfig2);
  109. REG_LOCAL_IRQ_RESTORE;
  110. }
  111. /* Wait until PLL is locked */
  112. while (!(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
  113. ;
  114. {
  115. REG_LOCAL_IRQ_SAVE;
  116. /* Remove digital reset */
  117. writel(readl(&pChipcHw->PLLConfig2) &
  118. ~chipcHw_REG_PLL_CONFIG_D_RESET,
  119. &pChipcHw->PLLConfig2);
  120. REG_LOCAL_IRQ_RESTORE;
  121. }
  122. }
  123. EXPORT_SYMBOL(chipcHw_pll2Enable);
  124. /****************************************************************************/
  125. /**
  126. * @brief Initializes the PLL1
  127. *
  128. * This function initializes the PLL1
  129. *
  130. */
  131. /****************************************************************************/
  132. void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
  133. {
  134. uint32_t pllPreDivider = 0;
  135. {
  136. REG_LOCAL_IRQ_SAVE;
  137. writel(chipcHw_REG_PLL_CONFIG_D_RESET |
  138. chipcHw_REG_PLL_CONFIG_A_RESET,
  139. &pChipcHw->PLLConfig);
  140. /* Setting VCO frequency */
  141. if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
  142. pllPreDivider =
  143. chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8 |
  144. ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) -
  145. 1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
  146. (chipcHw_REG_PLL_PREDIVIDER_P1 <<
  147. chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
  148. (chipcHw_REG_PLL_PREDIVIDER_P2 <<
  149. chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
  150. } else {
  151. pllPreDivider = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
  152. chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
  153. (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) <<
  154. chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
  155. (chipcHw_REG_PLL_PREDIVIDER_P1 <<
  156. chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
  157. (chipcHw_REG_PLL_PREDIVIDER_P2 <<
  158. chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
  159. }
  160. /* Enable CHIPC registers to control the PLL */
  161. writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
  162. /* Set pre divider to get desired VCO frequency */
  163. writel(pllPreDivider, &pChipcHw->PLLPreDivider);
  164. /* Set NDIV Frac */
  165. if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
  166. writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f_SS, &pChipcHw->PLLDivider);
  167. } else {
  168. writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider);
  169. }
  170. /* Reset PLL1 */
  171. if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
  172. writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
  173. } else {
  174. writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_800_1600 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
  175. }
  176. REG_LOCAL_IRQ_RESTORE;
  177. /* Insert certain amount of delay before deasserting ARESET. */
  178. udelay(1);
  179. {
  180. REG_LOCAL_IRQ_SAVE;
  181. /* Remove analog reset and Power on the PLL */
  182. writel(readl(&pChipcHw->PLLConfig) & ~(chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_POWER_DOWN), &pChipcHw->PLLConfig);
  183. REG_LOCAL_IRQ_RESTORE;
  184. }
  185. /* Wait until PLL is locked */
  186. while (!(readl(&pChipcHw->PLLStatus) & chipcHw_REG_PLL_STATUS_LOCKED)
  187. || !(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
  188. ;
  189. /* Remove digital reset */
  190. {
  191. REG_LOCAL_IRQ_SAVE;
  192. writel(readl(&pChipcHw->PLLConfig) & ~chipcHw_REG_PLL_CONFIG_D_RESET, &pChipcHw->PLLConfig);
  193. REG_LOCAL_IRQ_RESTORE;
  194. }
  195. }
  196. }
  197. EXPORT_SYMBOL(chipcHw_pll1Enable);
  198. /****************************************************************************/
  199. /**
  200. * @brief Initializes the chipc module
  201. *
  202. * This function initializes the PLLs and core system clocks
  203. *
  204. */
  205. /****************************************************************************/
  206. void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam /* [ IN ] Misc chip initialization parameter */
  207. ) {
  208. #if !(defined(__KERNEL__) && !defined(STANDALONE))
  209. delay_init();
  210. #endif
  211. /* Do not program PLL, when warm reset */
  212. if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET)) {
  213. chipcHw_pll1Enable(initParam->pllVcoFreqHz,
  214. initParam->ssSupport);
  215. chipcHw_pll2Enable(initParam->pll2VcoFreqHz);
  216. } else {
  217. /* Clear sticky bits */
  218. chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET);
  219. }
  220. /* Clear sticky bits */
  221. chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
  222. /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
  223. writel((readl(&pChipcHw->ACLKClock) & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> armBusRatio & chipcHw_REG_ACLKClock_CLK_DIV_MASK), &pChipcHw->ACLKClock);
  224. /* Set various core component frequencies. The order in which this is done is important for some. */
  225. /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
  226. /* frequency to find its ratio with the BUS. Hence we must set the ARM first, followed by the BUS, */
  227. /* then VPM and RTBUS. */
  228. chipcHw_setClockFrequency(chipcHw_CLOCK_ARM,
  229. initParam->busClockFreqHz *
  230. initParam->armBusRatio);
  231. chipcHw_setClockFrequency(chipcHw_CLOCK_BUS, initParam->busClockFreqHz);
  232. chipcHw_setClockFrequency(chipcHw_CLOCK_VPM,
  233. initParam->busClockFreqHz *
  234. initParam->vpmBusRatio);
  235. chipcHw_setClockFrequency(chipcHw_CLOCK_DDR,
  236. initParam->busClockFreqHz *
  237. initParam->ddrBusRatio);
  238. chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS,
  239. initParam->busClockFreqHz / 2);
  240. }