1 /*************************************************************************************
2 * FILE PURPOSE: Provide PLL control functions
3 *************************************************************************************
4 * FILE NAME: pll.c
5 *
6 * DESCRIPTION: Provides functions to control the pll
7 *
8 *************************************************************************************/
9 #include "types.h"
10 #include "ibl.h"
11 #include "pllloc.h"
12 #include "pllapi.h"
13 #include "target.h"
15 #define DEVICE_REG32_W(x,y) *(volatile unsigned int *)(x)=(y)
16 #define DEVICE_REG32_R(x) (*(volatile unsigned int *)(x))
18 #define BOOTBITMASK(x,y) ( ( ( ((UINT32)1 << (((UINT32)x)-((UINT32)y)+(UINT32)1) ) - (UINT32)1 ) ) << ((UINT32)y) )
19 #define BOOT_READ_BITFIELD(z,x,y) (((UINT32)z) & BOOTBITMASK(x,y)) >> (y)
20 #define BOOT_SET_BITFIELD(z,f,x,y) (((UINT32)z) & ~BOOTBITMASK(x,y)) | ( (((UINT32)f) << (y)) & BOOTBITMASK(x,y) )
23 typedef enum {
24 HW_PLL_DO_NOT_ENABLE_PLL,
25 HW_PLL_ENABLE_PLL
26 } hwPllEnable_t;
28 /*********************************************************************************
29 * FUNCTION PURPOSE: Provide a delay loop
30 *********************************************************************************
31 * DESCRIPTION: Generates a delay, units of cycles
32 *********************************************************************************/
33 void hw_pll_delay (UINT32 del)
34 {
35 UINT32 i;
36 volatile UINT32 j;
38 for (i = j = 0; i < del; i++)
39 j = j + 1;
41 } /* hw_pll_delay */
44 /**********************************************************************************
45 * FUNCTION PURPOSE: Enables the pll to the specified multiplier
46 **********************************************************************************
47 * DESCRIPTION: Sets up the pll
48 **********************************************************************************/
49 SINT16 hwPllSetPll (UINT32 pllNum, UINT32 prediv, UINT32 mult, UINT32 postdiv)
50 {
51 UINT32 ctl;
52 UINT32 secctl;
53 UINT32 status;
54 UINT32 pmult;
55 UINT32 pdiv;
56 UINT32 pllBase;
57 UINT32 i;
58 SINT16 ret = 0;
61 /* Mutliplier/divider values of 0 are invalid */
62 if (prediv == 0)
63 prediv = 1;
65 if (mult == 0)
66 mult = 1;
68 if (postdiv == 0)
69 postdiv = 1;
71 /* Get the base address of the pll */
72 pllBase = (UINT32) DEVICE_PLL_BASE(pllNum);
74 /* Program pllen=0 (pll bypass), pllrst=1 (reset pll), pllsrc = 0 */
75 ctl = DEVICE_REG32_R (pllBase + PLL_REG_CTL);
76 ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLEN | PLL_REG_CTL_FIELD_PLLENSRC | PLL_REG_CTL_FIELD_PLLDIS);
77 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
80 /* Enable secondary controller pll bypass */
81 secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
82 secctl = secctl | PLL_REG_SECCTL_FIELD_BYPASS;
83 DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
86 /* Reset the PLL, wait at least 5 us, release reset */
87 ctl = ctl | 2;
88 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
89 hw_pll_delay (500 * 5 * 20);
91 ctl = ctl & ~2;
92 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
93 hw_pll_delay (500 * 5 * 20);
95 /* Reset the PLL */
96 ctl = ctl | PLL_REG_CTL_FIELD_PLLRST;
97 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
99 /* Enable the pll divider */
100 secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
101 secctl = PLL_REG_SECCTL_SET_POSTDIV(secctl,postdiv-1);
102 secctl = PLL_REG_SECCTL_ENABLE_POSTDIV(secctl);
103 DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
106 /* Some PLLs like the rpll used in Nysh have an external (chip register) PLL predivider */
107 if (chipPllExternalPrediv(pllNum) == FALSE) {
108 pdiv = (UINT32) (((prediv-1) & PLL_REG_PREDIV_FIELD_RATIOm1) | PLL_REG_PREDIV_FIELD_ENABLE);
109 DEVICE_REG32_W (pllBase + PLL_REG_PREDIV, pdiv);
110 } else
111 chipPllSetExternalPrediv(pllNum, prediv - 1);
113 /* The rpll used in Nysh has both external and internal multiplier components. The external
114 * is set first because it modifies the internal. The value returned by chipPllExternalMult
115 * will be modified to take into account the value programed by the chip regsiters. This
116 * mult value input into chipPllExternalMult is the actual desired multiplier value, not
117 * the desired value - 1 */
118 pmult = chipPllExternalMult(pllNum, mult);
119 pmult = pmult & PLL_REG_PLLM_FIELD_MULTm1;
120 DEVICE_REG32_W (pllBase + PLL_REG_PLLM, pmult);
122 /* Some PLLs like the rpll used in Nysh require bandwidth adjustment which is controlled
123 * through a chip level register. Devices that don't require this simply define
124 * this function to an empty statement */
125 chipPllExternalBwAdj (pllNum, mult);
128 /* Wait a while for the pll to reset */
129 hw_pll_delay (2000/7);
131 /* set pllrst to 0 to deassert pll reset */
132 ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLRST);
133 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
136 /* wait for the pll to lock, but don't trap if lock is never read */
137 for (i = 0; i < 100; i++) {
138 hw_pll_delay (2000/7);
139 status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
140 if ( (status & PLL_REG_STATUS_FIELD_LOCK) != 0 )
141 break;
142 }
144 /* Enable the pll even if the lock failed. Return a warning. */
145 if (i == 100)
146 ret = -1;
148 /* Clear the secondary controller bypass bit */
149 secctl = secctl & ~PLL_REG_SECCTL_FIELD_BYPASS;
150 DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
153 /* Set pllen to 1 to enable pll mode */
154 ctl = ctl | PLL_REG_CTL_FIELD_PLLEN;
155 DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
157 return (ret);
160 } /* hwPllSetPll */