/** @file errata_SSWF021_45.c * @brief errata for PLLs * @date 11-Dec-2018 * @version 04.07.01 * */ /* * Copyright (C) 2009-2018 Texas Instruments Incorporated - www.ti.com * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "errata_SSWF021_45_defs.h" #include "errata_SSWF021_45.h" static uint32 check_frequency(uint32 cnt1_clksrc); static uint32 disable_plls(uint32 plls); /** @fn uint32 _errata_SSWF021_45_both_plls(uint32 count) * @brief This handles the errata for PLL1 and PLL2. This function is called in device startup * * @param[in] count : Number of retries until both PLLs are locked successfully * Minimum value recommended is 5 * * @return 0 = Success (the PLL or both PLLs have successfully locked and then been disabled) * 1 = PLL1 failed to successfully lock in "count" tries * 2 = PLL2 failed to successfully lock in "count" tries * 3 = Neither PLL1 nor PLL2 successfully locked in "count" tries * 4 = The workaround function was not able to disable at least one of the PLLs. The most likely reason is that a PLL is already being used as a clock source. This can be caused by the workaround function being called from the wrong place in the code. */ uint32 _errata_SSWF021_45_both_plls(uint32 count) { uint32 failCode,retries,clkCntlSav; /* save CLKCNTL */ clkCntlSav = systemREG1->CLKCNTL; /* First set VCLK2 = HCLK */ systemREG1->CLKCNTL = clkCntlSav & 0x000F0100U; /* Now set VCLK = HCLK and enable peripherals */ systemREG1->CLKCNTL = SYS_CLKCNTRL_PENA; failCode = 0U; for(retries = 0U;(retries < count);retries++) { failCode = 0U; /* Disable PLL1 and PLL2 */ failCode = disable_plls(SYS_CLKSRC_PLL1 | SYS_CLKSRC_PLL2); if(failCode != 0U) { break; } /* Clear Global Status Register */ systemREG1->GBLSTAT = 0x00000301U; /* Clear the ESM PLL slip flags */ esmREG->SR1[0U] = ESM_SR1_PLL1SLIP; esmREG->SR4[0U] = ESM_SR4_PLL2SLIP; /* set both PLLs to OSCIN/1*27/(2*1) */ systemREG1->PLLCTL1 = 0x20001A00U; systemREG1->PLLCTL2 = 0x3FC0723DU; systemREG2->PLLCTL3 = 0x20001A00U; systemREG1->CSDISCLR = SYS_CLKSRC_PLL1 | SYS_CLKSRC_PLL2; /* Check for (PLL1 valid or PLL1 slip) and (PLL2 valid or PLL2 slip) */ while ((((systemREG1->CSVSTAT & SYS_CLKSRC_PLL1) == 0U) && ((esmREG->SR1[0U] & ESM_SR1_PLL1SLIP) == 0U)) || (((systemREG1->CSVSTAT & SYS_CLKSRC_PLL2) == 0U) && ((esmREG->SR4[0U] & ESM_SR4_PLL2SLIP) == 0U))) { /* Wait */ } /* If PLL1 valid, check the frequency */ if(((esmREG->SR1[0U] & ESM_SR1_PLL1SLIP) != 0U) || ((systemREG1->GBLSTAT & 0x00000300U) != 0U)) { failCode |= 1U; } else { failCode |= check_frequency(dcc1CNT1_CLKSRC_PLL1); } /* If PLL2 valid, check the frequency */ if(((esmREG->SR4[0U] & ESM_SR4_PLL2SLIP) != 0U) || ((systemREG1->GBLSTAT & 0x00000300U) != 0U)) { failCode |= 2U; } else { failCode |= (check_frequency(dcc1CNT1_CLKSRC_PLL2) << 1U); } if (failCode == 0U) { break; } } /* To avoid MISRA violation 382S (void)missing for discarded return value */ failCode = disable_plls(SYS_CLKSRC_PLL1 | SYS_CLKSRC_PLL2); /* restore CLKCNTL, VCLKR and PENA first */ systemREG1->CLKCNTL = (clkCntlSav & 0x000F0100U); /* restore CLKCNTL, VCLK2R */ systemREG1->CLKCNTL = clkCntlSav; return failCode; } /** @fn uint32 _errata_SSWF021_45_pll1(uint32 count) * @brief This handles the errata for PLL1. This function is called in device startup * * @param[in] count : Number of retries until both PLL1 is locked successfully * Minimum value recommended is 5 * * @return 0 = Success (the PLL or both PLLs have successfully locked and then been disabled) * 1 = PLL1 failed to successfully lock in "count" tries * 2 = PLL2 failed to successfully lock in "count" tries * 3 = Neither PLL1 nor PLL2 successfully locked in "count" tries * 4 = The workaround function was not able to disable at least one of the PLLs. The most likely reason is that a PLL is already being used as a clock source. This can be caused by the workaround function being called from the wrong place in the code. */ uint32 _errata_SSWF021_45_pll1(uint32 count) { uint32 failCode,retries,clkCntlSav; /* save CLKCNTL */ clkCntlSav = systemREG1->CLKCNTL; /* First set VCLK2 = HCLK */ systemREG1->CLKCNTL = clkCntlSav & 0x000F0100U; /* Now set VCLK = HCLK and enable peripherals */ systemREG1->CLKCNTL = SYS_CLKCNTRL_PENA; failCode = 0U; for(retries = 0U;(retries < count);retries++) { failCode = 0U; /* Disable PLL1 */ failCode = disable_plls(SYS_CLKSRC_PLL1); if(failCode != 0U) { break; } /* Clear Global Status Register */ systemREG1->GBLSTAT = 0x00000301U; /* Clear the ESM PLL slip flags */ esmREG->SR1[0U] = ESM_SR1_PLL1SLIP; /* set PLL1 to OSCIN/1*27/(2*1) */ systemREG1->PLLCTL1 = 0x20001A00U; systemREG1->PLLCTL2 = 0x3FC0723DU; systemREG1->CSDISCLR = SYS_CLKSRC_PLL1; /* Check for PLL1 valid or PLL1 slip*/ while(((systemREG1->CSVSTAT & SYS_CLKSRC_PLL1) == 0U) && ((esmREG->SR1[0U] & ESM_SR1_PLL1SLIP) == 0U)) { /* Wait */ } /* If PLL1 valid, check the frequency */ if(((esmREG->SR1[0U] & ESM_SR1_PLL1SLIP) != 0U) || ((systemREG1->GBLSTAT & 0x00000300U) != 0U)) { failCode |= 1U; } else { failCode |= check_frequency(dcc1CNT1_CLKSRC_PLL1); } if (failCode == 0U) { break; } } /* To avoid MISRA violation 382S (void)missing for discarded return value */ failCode = disable_plls(SYS_CLKSRC_PLL1); /* restore CLKCNTL, VCLKR and PENA first */ systemREG1->CLKCNTL = (clkCntlSav & 0x000F0100U); /* restore CLKCNTL, VCLK2R */ systemREG1->CLKCNTL = clkCntlSav; return failCode; } /** @fn uint32 _errata_SSWF021_45_pll2(uint32 count) * @brief This handles the errata for PLL2. This function is called in device startup * * @param[in] count : Number of retries until PLL2 is locked successfully * Minimum value recommended is 5 * * @return 0 = Success (the PLL or both PLLs have successfully locked and then been disabled) * 1 = PLL1 failed to successfully lock in "count" tries * 2 = PLL2 failed to successfully lock in "count" tries * 3 = Neither PLL1 nor PLL2 successfully locked in "count" tries * 4 = The workaround function was not able to disable at least one of the PLLs. The most likely reason is that a PLL is already being used as a clock source. This can be caused by the workaround function being called from the wrong place in the code. */ uint32 _errata_SSWF021_45_pll2(uint32 count) { uint32 failCode,retries,clkCntlSav; /* save CLKCNTL */ clkCntlSav = systemREG1->CLKCNTL; /* First set VCLK2 = HCLK */ systemREG1->CLKCNTL = clkCntlSav & 0x000F0100U; /* Now set VCLK = HCLK and enable peripherals */ systemREG1->CLKCNTL = SYS_CLKCNTRL_PENA; failCode = 0U; for(retries = 0U;(retries < count);retries++) { failCode = 0U; /* Disable PLL2 */ failCode = disable_plls(SYS_CLKSRC_PLL2); if(failCode != 0U) { break; } /* Clear Global Status Register */ systemREG1->GBLSTAT = 0x00000301U; /* Clear the ESM PLL slip flags */ esmREG->SR4[0U] = ESM_SR4_PLL2SLIP; /* set PLL2 to OSCIN/1*27/(2*1) */ systemREG2->PLLCTL3 = 0x20001A00U; systemREG1->CSDISCLR = SYS_CLKSRC_PLL2; /* Check for PLL2 valid or PLL2 slip */ while (((systemREG1->CSVSTAT & SYS_CLKSRC_PLL2) == 0U) && ((esmREG->SR4[0U] & ESM_SR4_PLL2SLIP) == 0U)) { /* Wait */ } /* If PLL2 valid, check the frequency */ if(((esmREG->SR4[0U] & ESM_SR4_PLL2SLIP) != 0U) || ((systemREG1->GBLSTAT & 0x00000300U) != 0U)) { failCode |= 2U; } else { failCode |= (check_frequency(dcc1CNT1_CLKSRC_PLL2) << 1U); } if (failCode == 0U) { break; } } /* To avoid MISRA violation 382S (void)missing for discarded return value */ failCode = disable_plls(SYS_CLKSRC_PLL2); /* restore CLKCNTL, VCLKR and PENA first */ systemREG1->CLKCNTL = (clkCntlSav & 0x000F0100U); /* restore CLKCNTL, VCLK2R */ systemREG1->CLKCNTL = clkCntlSav; return failCode; } /** @fn uint32 check_frequency(uint32 cnt1_clksrc) * @brief This function checks for the PLL frequency. * * @param[in] cnt1_clksrc : Clock source for Counter1 * 0U - PLL1 (clock source 0) * 1U - PLL2 (clock source 1) * * @return DCC Error status * 0 - DCC error has not occurred * 1 - DCC error has occurred */ static uint32 check_frequency(uint32 cnt1_clksrc) { /* Setup DCC1 */ /** DCC1 Global Control register configuration */ dccREG1->GCTRL = (uint32)0x5U | /** Disable DCC1 */ (uint32)((uint32)0x5U << 4U) | /** No Error Interrupt */ (uint32)((uint32)0xAU << 8U) | /** Single Shot mode */ (uint32)((uint32)0x5U << 12U); /** No Done Interrupt */ /* Clear ERR and DONE bits */ dccREG1->STAT = 3U; /** DCC1 Clock0 Counter Seed value configuration */ dccREG1->CNT0SEED = 68U; /** DCC1 Clock0 Valid Counter Seed value configuration */ dccREG1->VALID0SEED = 4U; /** DCC1 Clock1 Counter Seed value configuration */ dccREG1->CNT1SEED = 972U; /** DCC1 Clock1 Source 1 Select */ dccREG1->CNT1CLKSRC = (uint32)((uint32)10U << 12U) | /** DCC Enable / Disable Key */ (uint32) cnt1_clksrc; /** DCC1 Clock Source 1 */ dccREG1->CNT0CLKSRC = (uint32)DCC1_CNT0_OSCIN; /** DCC1 Clock Source 0 */ /** DCC1 Global Control register configuration */ dccREG1->GCTRL = (uint32)0xAU | /** Enable DCC1 */ (uint32)((uint32)0x5U << 4U) | /** No Error Interrupt */ (uint32)((uint32)0xAU << 8U) | /** Single Shot mode */ (uint32)((uint32)0x5U << 12U); /** No Done Interrupt */ while(dccREG1->STAT == 0U) { /* Wait */ } return (dccREG1->STAT & 0x01U); } /** @fn uint32 disable_plls(uint32 plls) * @brief This function disables plls and clears the respective ESM flags. * * @param[in] plls : Clock source for Counter1 * 2U - PLL1 * 40U - PLL2 * * @return failCode * 0 = Success (the PLL or both PLLs have successfully locked and then been disabled) * 4 = The workaround function was not able to disable at least one of the PLLs. The most likely reason * is that a PLL is already being used as a clock source. This can be caused by the workaround function * being called from the wrong place in the code. */ static uint32 disable_plls(uint32 plls) { uint32 timeout,failCode; systemREG1->CSDISSET = plls; failCode = 0U; timeout = 0x10U; timeout --; while(((systemREG1->CSVSTAT & (plls)) != 0U) && (timeout != 0U)) { /* Clear ESM and GLBSTAT PLL slip flags */ systemREG1->GBLSTAT = 0x00000300U; if ((plls & SYS_CLKSRC_PLL1) == SYS_CLKSRC_PLL1) { esmREG->SR1[0U] = ESM_SR1_PLL1SLIP; } if ((plls & SYS_CLKSRC_PLL2) == SYS_CLKSRC_PLL2) { esmREG->SR4[0U] = ESM_SR4_PLL2SLIP; } timeout --; /* Wait */ } if(timeout == 0U) { failCode = 4U; } else { failCode = 0U; } return failCode; }