Initial c661x version
[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     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);
85   /* Reset the PLL */
86   ctl = ctl | PLL_REG_CTL_FIELD_PLLRST;
87   DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
89   /* Enable the pll divider */
90   secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
91   secctl = PLL_REG_SECCTL_SET_POSTDIV(secctl,postdiv-1);
92   secctl = PLL_REG_SECCTL_ENABLE_POSTDIV(secctl);
93   DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
96   /* Some PLLs like the rpll used in Nysh have an external (chip register) PLL predivider */
97   if (chipPllExternalPrediv(pllNum) == FALSE)  {
98     pdiv    = (UINT32) (((prediv-1) & PLL_REG_PREDIV_FIELD_RATIOm1) | PLL_REG_PREDIV_FIELD_ENABLE);
99     DEVICE_REG32_W (pllBase + PLL_REG_PREDIV,  pdiv);
100   }  else
101     chipPllSetExternalPrediv(pllNum, prediv - 1);
103   /* The rpll used in Nysh has both external and internal multiplier components. The external
104    * is set first because it modifies the internal. The value returned by chipPllExternalMult
105    * will be modified to take into account the value programed by the chip regsiters. This
106    * mult value input into chipPllExternalMult is the actual desired multiplier value, not
107    * the desired value - 1 */
108   pmult = chipPllExternalMult(pllNum, mult);
109   pmult   = pmult & PLL_REG_PLLM_FIELD_MULTm1;
110   DEVICE_REG32_W (pllBase + PLL_REG_PLLM, pmult);
112   /* Some PLLs like the rpll used in Nysh require bandwidth adjustment which is controlled
113    * through a chip level register. Devices that don't require this simply define
114    * this function to an empty statement */
115   chipPllExternalBwAdj (pllNum, mult);
118   /* Wait a while for the pll to reset */
119   hw_pll_delay (2000/7);
121   /* set pllrst to 0 to deassert pll reset */
122   ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLRST);
123   DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
126   /* wait for the pll to lock, but don't trap if lock is never read */
127   for (i = 0; i < 100; i++)  {
128     hw_pll_delay (2000/7);
129     status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
130     if ( (status & PLL_REG_STATUS_FIELD_LOCK) != 0 )
131       break;
132   }
134   /* Enable the pll even if the lock failed. Return a warning. */
135   if (i == 100)  
136     ret = -1;
138   /* Clear the secondary controller bypass bit */
139   secctl = secctl & ~PLL_REG_SECCTL_FIELD_BYPASS;
140   DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
143   /* Set pllen to 1 to enable pll mode */
144   ctl = ctl | PLL_REG_CTL_FIELD_PLLEN;
145   DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
147   return (ret);
150 } /* hwPllSetPll */