Updated PLL sequence and 66x and 665x devices and updated version
[keystone-rtos/ibl.git] / src / hw / plls / pll014phi / pll.c
index d709d113c8f9aeae69df48e3469485522c1a7d18..2ba013227bedde6fc877c110b264e9d248ac0062 100644 (file)
@@ -36,7 +36,7 @@ void hw_pll_delay (UINT32 del)
   volatile UINT32 j;
 
   for (i = j = 0; i < del; i++)
   volatile UINT32 j;
 
   for (i = j = 0; i < del; i++)
-    j = j + 1;
+    asm (" nop ");
 
 } /* hw_pll_delay */
 
 
 } /* hw_pll_delay */
 
@@ -48,15 +48,17 @@ void hw_pll_delay (UINT32 del)
  **********************************************************************************/
 SINT16 hwPllSetPll (UINT32 pllNum, UINT32 prediv, UINT32 mult, UINT32 postdiv)
 {
  **********************************************************************************/
 SINT16 hwPllSetPll (UINT32 pllNum, UINT32 prediv, UINT32 mult, UINT32 postdiv)
 {
-  UINT32 ctl;
+  UINT32 ctl, reg;
   UINT32 secctl;
   UINT32 status;
   UINT32 secctl;
   UINT32 status;
+  UINT32 alnctl;
   UINT32 pmult;
   UINT32 pdiv;
   UINT32 pllBase;
   UINT32 i;
   SINT16 ret = 0;
   UINT32 pmult;
   UINT32 pdiv;
   UINT32 pllBase;
   UINT32 i;
   SINT16 ret = 0;
-
+  UINT32 pllm_min = 10, plld_min =0, outputdiv = 9;
+  UINT32 div2=3, div5=5, div8=64;
 
   /* Mutliplier/divider values of 0 are invalid */
   if (prediv == 0)
 
   /* Mutliplier/divider values of 0 are invalid */
   if (prediv == 0)
@@ -71,82 +73,179 @@ SINT16 hwPllSetPll (UINT32 pllNum, UINT32 prediv, UINT32 mult, UINT32 postdiv)
   /* Get the base address of the pll */
   pllBase = (UINT32) DEVICE_PLL_BASE(pllNum);
 
   /* Get the base address of the pll */
   pllBase = (UINT32) DEVICE_PLL_BASE(pllNum);
 
-  /* Program pllen=0 (pll bypass), pllrst=1 (reset pll), pllsrc = 0 */
-  ctl = DEVICE_REG32_R (pllBase + PLL_REG_CTL);
-  ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLEN | PLL_REG_CTL_FIELD_PLLENSRC | PLL_REG_CTL_FIELD_PLLDIS);
-  DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+ /* 1. Wait for Stabilization time (min 100 us)             *
+  * assuming max device speed, 1.4GHz, 1 cycle = 0.714 ns   *
+  * so, 100 us = 100000 ns = 140056 cycles                  */
+  hw_pll_delay (140056);
 
 
+  /* Get the value of PLLCTL */
+  ctl = DEVICE_REG32_R (pllBase + PLL_REG_CTL);
 
 
-  /* Enable secondary controller pll bypass */
+ /* 2. Check the status of BYPASS bit in SECCTL register,                   *
+  *    execute the following steps if                                       *
+  *    BYPASS == 1 (if bypass enabled), if BYPASS==0 then Jump to Step 3    */
   secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
   secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
-  secctl = secctl | PLL_REG_SECCTL_FIELD_BYPASS;
-  DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
 
 
-  /* Reset the PLL */
-  ctl = ctl | PLL_REG_CTL_FIELD_PLLRST;
-  DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
-
-  /* Enable the pll divider */
-  secctl = DEVICE_REG32_R (pllBase + PLL_REG_SECCTL);
-  secctl = PLL_REG_SECCTL_SET_POSTDIV(secctl,postdiv-1);
-  secctl = PLL_REG_SECCTL_ENABLE_POSTDIV(secctl);
-  DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
-
-
-  /* Some PLLs like the rpll used in Nysh have an external (chip register) PLL predivider */
-  if (chipPllExternalPrediv(pllNum) == FALSE)  {
-    pdiv    = (UINT32) (((prediv-1) & PLL_REG_PREDIV_FIELD_RATIOm1) | PLL_REG_PREDIV_FIELD_ENABLE);
-    DEVICE_REG32_W (pllBase + PLL_REG_PREDIV,  pdiv);
-  }  else
-    chipPllSetExternalPrediv(pllNum, prediv - 1);
-
-  /* The rpll used in Nysh has both external and internal multiplier components. The external
-   * is set first because it modifies the internal. The value returned by chipPllExternalMult
-   * will be modified to take into account the value programed by the chip regsiters. This
-   * mult value input into chipPllExternalMult is the actual desired multiplier value, not
-   * the desired value - 1 */
-  pmult = chipPllExternalMult(pllNum, mult);
-  pmult   = pmult & PLL_REG_PLLM_FIELD_MULTm1;
-  DEVICE_REG32_W (pllBase + PLL_REG_PLLM, pmult);
-
-  /* Some PLLs like the rpll used in Nysh require bandwidth adjustment which is controlled
-   * through a chip level register. Devices that don't require this simply define
-   * this function to an empty statement */
-  chipPllExternalBwAdj (pllNum, mult);
-
-
-  /* Wait a while for the pll to reset */
-  hw_pll_delay (2000/7);
-
-  /* set pllrst to 0 to deassert pll reset */
-  ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLRST);
-  DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
-
-
-  /* wait for the pll to lock, but don't trap if lock is never read */
-  for (i = 0; i < 100; i++)  {
-    hw_pll_delay (2000/7);
-    status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
-    if ( (status & PLL_REG_STATUS_FIELD_LOCK) != 0 )
-      break;
+  if ( (secctl & PLL_REG_SECCTL_FIELD_BYPASS) != 0 ) {
+    /* PLL BYPASS is turned on */
+
+       /* 2a. Set the ENSAT Bit */
+       /* Usage Note 9: For optimal PLL operation, the ENSAT bit in the PLL control
+        * registers for the Main PLL, DDR3 PLL, and PA PLL should be set to 1.
+        * The PLL initialization sequence in the silicon sets this bit to 0 and
+        * could lead to non-optimal PLL operation. Software can set the bit to the
+        * optimal value of 1 after boot
+     * |31...7   |6     |5 4       |3...0      |
+     * |Reserved |ENSAT |Reserved  |BWADJ[11:8]|
+        */
+    reg = DEVICE_REG32_R (DEVICE_MAIN_PLL_CTL_1);   // Read MAINPLLCTL
+    reg = reg | (1 << 6);                           // Set bit 6 (ENSAT)
+    DEVICE_REG32_W (DEVICE_MAIN_PLL_CTL_1, reg);    // Write to MAINPLLCTL
+    
+    /* 2b. Clear the PLLEN bit */
+       ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLEN);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+
+       /* 2c. Clear the PLLENSRC bit */
+       ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLENSRC);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+
+       
+       /* 2d. Wait for 4 Ref clocks */
+       /* The slowest clock can be at 25MHz, so min:160ns delay */
+       hw_pll_delay(225);
+
+       /* 2e. Put the PLL in Bypass mode to perform the power down mode */
+       secctl = secctl | PLL_REG_SECCTL_FIELD_BYPASS;
+       DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
+
+       /* 2f. Advisory 8: Multiple PLLs May Not Lock After Power-on Reset Issue
+         * In order to ensure proper PLL startup, the PLL power_down pin needs to be
+         * toggled. This is accomplished by toggling the PLLPWRDN bit in the PLLCTL
+         * register. This needs to be done before the main PLL initialization
+         * sequence
+        */
+       ctl = ctl | 0x00000002;
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+
+       /* 2g. Stay in a loop such that the bit is set for 5 ┬Ás (minimum) and
+        * then clear the bit.
+        */
+       hw_pll_delay (14005); /* waiting 10 us */
+
+       /* 2h. Power up the PLL */
+       ctl = ctl & ~(0x00000002);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+       
+  }
+  else
+  {
+    /* 3. Enable BYPASS in the PLL controller */
+    
+    /* 3a. Clear PLLEN bit (bypass enabled in PLL controller mux) */
+    ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLEN);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+    
+    /* 3b. Clear PLLENSRC bit (enable PLLEN to control PLL controller mux) */
+    ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLENSRC);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+    
+    /* 3c. Wait for 4 RefClks (to make sure the PLL controller *
+     * mux switches properly to bypass)                        *
+     * Assuming slowest Ref clock of 25MHz, min: 160 ns delay  */
+     hw_pll_delay(225);
   }
 
   }
 
-  /* Enable the pll even if the lock failed. Return a warning. */
-  if (i == 100)  
-    ret = -1;
-
-  /* Clear the secondary controller bypass bit */
-  secctl = secctl & ~PLL_REG_SECCTL_FIELD_BYPASS;
-  DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
-
-
-  /* Set pllen to 1 to enable pll mode */
-  ctl = ctl | PLL_REG_CTL_FIELD_PLLEN;
-  DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
-
-  return (ret);
-
-
+       /* Program the necessary multipliers/dividers and BW adjustments
+        * This routine will subtract 1 from the mult value
+        */
+    /* 4. Program Multipliers */
+       pmult = chipPllExternalMult(pllNum, mult);
+       pmult   = pmult & PLL_REG_PLLM_FIELD_MULTm1;
+       DEVICE_REG32_W (pllBase + PLL_REG_PLLM, pmult);
+
+       /* 5. set the BWADJ */
+       chipPllExternalBwAdj (pllNum, mult);
+
+       /* 6. Set the PLL Divider */
+       chipPllSetExternalPrediv(pllNum, prediv - 1);  
+
+       /* 7. set the output divide */
+       secctl = BOOT_SET_BITFIELD(secctl, 1 & 0x000f, 22, 19);
+       DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
+
+    /* 8. Program PLLDIVn */
+  
+       /* part of 8, wait for the GOSTAT, but don't trap if lock is never read */
+       for (i = 0; i < 100; i++)  {
+               hw_pll_delay (300);
+               status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
+               if ( (status & PLL_REG_STATUS_FIELD_GOSTAT) == 0 )
+                       break;
+       }
+
+       /* Enable the pll even if the lock failed. Return a warning. */
+       if (i == 100)  
+               ret = -1;
+  
+       /* part of 8, Set PLL dividers if needed */
+       reg = 0x8000 | (div2 -1);
+       DEVICE_REG32_W (pllBase + PLL_REG_DIV2, reg);
+
+       reg = 0x8000 | (div5 -1);
+       DEVICE_REG32_W (pllBase + PLL_REG_DIV5, reg);
+
+       reg = 0x8000 | (div8 -1);
+       DEVICE_REG32_W (pllBase + PLL_REG_DIV8, reg);
+
+       /* part of 8, Program ALNCTLn registers */
+       alnctl = DEVICE_REG32_R (pllBase + PLL_REG_ALNCTL);
+       alnctl = alnctl | ((1 << 1) | (1 << 4) | (1 << 7));
+       DEVICE_REG32_W (pllBase + PLL_REG_ALNCTL, alnctl);
+
+       /* part of 8, Set GOSET bit in PLLCMD to initiate the GO operation to change the divide *   
+        * values and align the SYSCLKs as programmed                                           */
+       reg = DEVICE_REG32_R (pllBase + PLL_REG_CMD);
+       reg = reg | 1;
+       DEVICE_REG32_W (pllBase + PLL_REG_CMD, reg);
+
+       /* part of 8, wait for the GOSTAT, but don't trap if lock is never read */
+       for (i = 0; i < 100; i++)  {
+               hw_pll_delay (300);
+               status = DEVICE_REG32_R (pllBase + PLL_REG_PLLSTAT);
+               if ( (status & PLL_REG_STATUS_FIELD_GOSTAT) == 0 )
+                       break;
+       }
+
+       if (i == 100)  
+               ret = -1;
+        
+    /* 9. Assert PLL Reset */
+       ctl = ctl | (PLL_REG_CTL_FIELD_PLLRST);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+
+       /* 10. Wait for a minimum of 7 us*/
+       hw_pll_delay (14006);
+
+       /* 11. Release PLL from Reset */
+       ctl = ctl & ~(PLL_REG_CTL_FIELD_PLLRST);
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+
+       /* 12. Wait for PLL Lock time (min 50 us) */
+       hw_pll_delay (140056 >> 1);
+
+       /* 13. Clear the secondary controller bypass bit */
+       secctl = secctl & ~PLL_REG_SECCTL_FIELD_BYPASS;
+       DEVICE_REG32_W (pllBase + PLL_REG_SECCTL, secctl);
+
+
+       /* 14. Set pllen to 1 to enable pll mode */
+       ctl = ctl | PLL_REG_CTL_FIELD_PLLEN;
+       DEVICE_REG32_W (pllBase + PLL_REG_CTL, ctl);
+    
+    /* 15. The PLL and PLL Controller are now initialized in PLL mode - Complete */
+  
+       return (ret);
 } /* hwPllSetPll */
 
 
 } /* hwPllSetPll */