c66x: PLL init code update based on latest review
[keystone-rtos/ibl.git] / src / hw / plls / pll014phi / pll.c
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     asm (" nop ");
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, reg;
52   UINT32 secctl;
53   UINT32 status;
54   UINT32 alnctl;
55   UINT32 pmult;
56   UINT32 pdiv;
57   UINT32 pllBase;
58   UINT32 i;
59   SINT16 ret = 0;
60   UINT32 pllm_min = 10, plld_min =0, outputdiv = 9;
61   UINT32 div2=3, div5=5, div8=64;
63   /* Mutliplier/divider values of 0 are invalid */
64   if (prediv == 0)
65     prediv = 1;
67   if (mult == 0)
68     mult = 1;
70   if (postdiv == 0)
71     postdiv = 1;
73   /* Get the base address of the pll */
74   pllBase = (UINT32) DEVICE_PLL_BASE(pllNum);
76  /* Wait for Stabilization time (min 100 us) */
77  /* assuming max device speed, 1.4GHz, 1 cycle = 0.714 ns *
78   * so, 100 us = 100000 ns = 140056 cycles */
79   hw_pll_delay (140056);
81   /* Program pllen=0 (pll bypass), pllrst=1 (reset pll), pllsrc = 0 */
82   ctl = DEVICE_REG32_R (pllBase + PLL_REG_CTL);
84  /* Check if PLL BYPASS is turned off previously */
85   secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
87   if ( (secctl & PLL_REG_SECCTL_FIELD_BYPASS) != 0 ) {
88     /* PLL BYPASS is turned on */
90         /* Set the ENSAT Bit */
91         /* Usage Note 9: For optimal PLL operation, the ENSAT bit in the PLL control
92          * registers for the Main PLL, DDR3 PLL, and PA PLL should be set to 1.
93          * The PLL initialization sequence in the boot ROM sets this bit to 0 and
94          * could lead to non-optimal PLL operation. Software can set the bit to the
95          * optimal value of 1 after boot
96          */
97         reg = DEVICE_REG32_R (DEVICE_MAIN_PLL_CTL_1);
98         reg = reg | (1 << 6);
99         DEVICE_REG32_W (DEVICE_MAIN_PLL_CTL_1, reg);
101         /* Clear the PLLENSRC bit */
102         ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLENSRC);
103         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
105         /* Clear the PLLEN bit */
106         ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLEN);
107         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
109         
110         /* Wait for 4 Ref clocks */
111         /* The slowest clock can be at 24MHz, so min:160ns delay */
112         hw_pll_delay(225);
114         /* Put the PLL in Bypass mode to perform the power down mode */
115         secctl = secctl | PLL_REG_SECCTL_FIELD_BYPASS;
116         DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
118         /* Advisory 8: Multiple PLLs May Not Lock After Power-on Reset Issue
119          * In order to ensure proper PLL startup, the PLL power_down pin needs to be
120          * toggled. This is accomplished by toggling the PLLPWRDN bit in the PLLCTL
121          * register. This needs to be done before the main PLL initialization
122          * sequence
123          */
124         ctl = ctl | 2;
125         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
127         /* Stay in a loop such that the bit is set for 5 ┬Ás (minimum) and
128          * then clear the bit.
129          */
130         hw_pll_delay (14005); /* waiting 10 us */
132         /* Power up the PLL */
133         ctl = ctl & ~2;
134         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
135         
136   }
138         /* Assert PLL Reset */
139         ctl = ctl | (PLL_REG_CTL_FIELD_PLLRST);
140         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
142         /* Program the necessary multipliers/dividers and BW adjustments
143          * This routine will subtract 1 from the mult value
144          */
145         pmult = chipPllExternalMult(pllNum, mult);
146         pmult   = pmult & PLL_REG_PLLM_FIELD_MULTm1;
147         DEVICE_REG32_W (pllBase + PLL_REG_PLLM, pmult);
149         /* set the BWADJ */
150         chipPllExternalBwAdj (pllNum, mult);
152         /* Set the PLL Divider */
153         chipPllSetExternalPrediv(pllNum, prediv - 1);  
155         /* set the output divide */
156         secctl = BOOT_SET_BITFIELD(secctl, 1 & 0x000f, 22, 19);
157         DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl); 
158         
159         /* WAIT FOR THE go STAT BIT HERE (50 us) */
160         hw_pll_delay (140056 >> 1);   
161         /* wait for the GOSTAT, but don't trap if lock is never read */
162         for (i = 0; i < 100; i++)  {
163                 hw_pll_delay (300);
164                 status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
165                 if ( (status & PLL_REG_STATUS_FIELD_GOSTAT) == 0 )
166                         break;
167         }
169         /* Enable the pll even if the lock failed. Return a warning. */
170         if (i == 100)  
171                 ret = -1;
172   
173         /* Set PLL dividers if needed */
174         reg = 0x8000 | (div2 -1);
175         DEVICE_REG32_W (pllBase + PLL_REG_DIV2, reg);
177         reg = 0x8000 | (div5 -1);
178         DEVICE_REG32_W (pllBase + PLL_REG_DIV5, reg);
180         reg = 0x8000 | (div8 -1);
181         DEVICE_REG32_W (pllBase + PLL_REG_DIV8, reg);
183         /* Program ALNCTLn registers */
184         alnctl = DEVICE_REG32_R (pllBase + PLL_REG_ALNCTL);
185         alnctl = alnctl | ((1 << 1) | (1 << 4) | (1 << 7));
186         DEVICE_REG32_W (pllBase + PLL_REG_ALNCTL, alnctl);
188         /* Set GOSET bit in PLLCMD to initiate the GO operation to change the divide *   
189          * values and align the SYSCLKs as programmed                                */
190         reg = DEVICE_REG32_R (pllBase + PLL_REG_CMD);
191         reg = reg | 1;
192         DEVICE_REG32_W (pllBase + PLL_REG_CMD, reg);
194         /* wait for the GOSTAT, but don't trap if lock is never read */
195         for (i = 0; i < 100; i++)  {
196                 hw_pll_delay (300);
197                 status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
198                 if ( (status & PLL_REG_STATUS_FIELD_GOSTAT) == 0 )
199                         break;
200         }
202         /* Wait for 7 us, use 10 us*/
203         hw_pll_delay (14006);
205         /* Release PLL from Reset */
206         ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLRST);
207         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
209         /* Wait for PLL Lock time (min 50 us) */
210         hw_pll_delay (140056 >> 1);  
211    
212         /* wait for the pll to lock, but don't trap if lock is never read */
213         for (i = 0; i < 100; i++)  {
214                 hw_pll_delay (2000/7);
215                 status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
216                 if ( (status & PLL_REG_STATUS_FIELD_LOCK) != 0 )
217                         break;
218         }
220         /* Enable the pll even if the lock failed. Return a warning. */
221         if (i == 100)  
222                 ret = -1;
224         /* Clear the secondary controller bypass bit */
225         secctl = secctl & ~PLL_REG_SECCTL_FIELD_BYPASS;
226         DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
229         /* Set pllen to 1 to enable pll mode */
230         ctl = ctl | PLL_REG_CTL_FIELD_PLLEN;
231         DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
232   
233         return (ret);
234 } /* hwPllSetPll */