From 75dd82407980a227a39aef70b383090778361f70 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 21 Dec 2023 15:16:48 +0100 Subject: bsp/tms570: Add errata SSWF021#45 handling Update #4982. --- .../tms570/include/bsp/ti_herc/errata_SSWF021_45.h | 56 ++++ bsps/arm/tms570/include/bsp/ti_herc/reg_dcc.h | 6 + bsps/arm/tms570/start/bspstarthooks-hwinit.c | 9 + bsps/arm/tms570/start/errata_SSWF021_45.c | 366 +++++++++++++++++++++ 4 files changed, 437 insertions(+) create mode 100755 bsps/arm/tms570/include/bsp/ti_herc/errata_SSWF021_45.h create mode 100755 bsps/arm/tms570/start/errata_SSWF021_45.c (limited to 'bsps/arm') diff --git a/bsps/arm/tms570/include/bsp/ti_herc/errata_SSWF021_45.h b/bsps/arm/tms570/include/bsp/ti_herc/errata_SSWF021_45.h new file mode 100755 index 0000000000..e1821f8e6e --- /dev/null +++ b/bsps/arm/tms570/include/bsp/ti_herc/errata_SSWF021_45.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsARMTMS570 + * + * @brief This header file provides errata SSWF021#45 interfaces. + * + * Pulled in from Halcogen v4.7.1. This is a rare but high-severity errata + * that should always be checked for at system start. + */ + +/* +* 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. +* +*/ +#ifndef INCLUDE_ERRATA_SSWF021_45_H_ +#define INCLUDE_ERRATA_SSWF021_45_H_ +#include + +uint32_t _errata_SSWF021_45_both_plls(uint32_t count); +uint32_t _errata_SSWF021_45_pll1(uint32_t count); +uint32_t _errata_SSWF021_45_pll2(uint32_t count); + + +#endif /* INCLUDE_HL_ERRATA_SSWF021_45_H_ */ diff --git a/bsps/arm/tms570/include/bsp/ti_herc/reg_dcc.h b/bsps/arm/tms570/include/bsp/ti_herc/reg_dcc.h index f5d35719fa..12edca3eb1 100644 --- a/bsps/arm/tms570/include/bsp/ti_herc/reg_dcc.h +++ b/bsps/arm/tms570/include/bsp/ti_herc/reg_dcc.h @@ -51,6 +51,12 @@ #include +enum tms570_dcc1_cnt0_clksrc { + DCC1_CNT0_HF_LPO = 0x5U, /**< Alias for DCC1 CNT 0 CLOCK SOURCE 0*/ + DCC1_CNT0_TCK = 0xAU, /**< Alias for DCC1 CNT 0 CLOCK SOURCE 1*/ + DCC1_CNT0_OSCIN = 0xFU, /**< Alias for DCC1 CNT 0 CLOCK SOURCE 2*/ +}; + typedef struct{ uint32_t GCTRL; /*DCC Global Control Register*/ uint32_t REV; /*DCC Revision Id Register*/ diff --git a/bsps/arm/tms570/start/bspstarthooks-hwinit.c b/bsps/arm/tms570/start/bspstarthooks-hwinit.c index 561e6a18e6..8ac53a3d44 100644 --- a/bsps/arm/tms570/start/bspstarthooks-hwinit.c +++ b/bsps/arm/tms570/start/bspstarthooks-hwinit.c @@ -46,6 +46,7 @@ #include #include #include +#include #define PBIST_March13N_SP 0x00000008U /**< March13 N Algo for 1 Port mem */ @@ -65,6 +66,14 @@ BSP_START_TEXT_SECTION void bsp_start_hook_0( void ) } #endif +#if TMS570_VARIANT == 4357 + uint32_t pll_result; + + do { + pll_result = _errata_SSWF021_45_both_plls(10); + } while (pll_result != 0 && pll_result != 4); +#endif + /* Enable CPU Event Export */ /* This allows the CPU to signal any single-bit or double-bit errors detected * by its ECC logic for accesses to program flash or data RAM. diff --git a/bsps/arm/tms570/start/errata_SSWF021_45.c b/bsps/arm/tms570/start/errata_SSWF021_45.c new file mode 100755 index 0000000000..1591e64798 --- /dev/null +++ b/bsps/arm/tms570/start/errata_SSWF021_45.c @@ -0,0 +1,366 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsARMTMS570 + * + * @brief This source file contains errata SSWF021#45 workaround + * implementation. + */ + +/* + * 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 +#include + +#define SYS_CLKSRC_PLL1 0x00000002U +#define SYS_CLKSRC_PLL2 0x00000040U +#define SYS_CLKCNTRL_PENA 0x00000100U +#define ESM_SR1_PLL1SLIP 0x400U +#define ESM_SR4_PLL2SLIP 0x400U +#define PLL1 0x08 +#define PLL2 0x80 +#define dcc1CNT1_CLKSRC_PLL1 0x0000A000U +#define dcc1CNT1_CLKSRC_PLL2 0x0000A001U + +static uint32_t check_frequency(uint32_t cnt1_clksrc); +static uint32_t disable_plls(uint32_t plls); + +/** @fn uint32_t _errata_SSWF021_45_both_plls(uint32_t 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_t _errata_SSWF021_45_both_plls(uint32_t count) { + uint32_t failCode, retries, clkCntlSav; + + /* save CLKCNTL */ + clkCntlSav = TMS570_SYS1.CLKCNTL; + /* First set VCLK2 = HCLK */ + TMS570_SYS1.CLKCNTL = clkCntlSav & 0x000F0100U; + /* Now set VCLK = HCLK and enable peripherals */ + TMS570_SYS1.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 */ + TMS570_SYS1.GLBSTAT = 0x00000301U; + /* Clear the ESM PLL slip flags */ + TMS570_ESM.SR[0U] = ESM_SR1_PLL1SLIP; + TMS570_ESM.SR4 = ESM_SR4_PLL2SLIP; + /* set both PLLs to OSCIN/1*27/(2*1) */ + TMS570_SYS1.PLLCTL1 = 0x20001A00U; + TMS570_SYS1.PLLCTL2 = 0x3FC0723DU; + TMS570_SYS2.PLLCTL3 = 0x20001A00U; + TMS570_SYS1.CSDISCLR = SYS_CLKSRC_PLL1 | SYS_CLKSRC_PLL2; + /* Check for (PLL1 valid or PLL1 slip) and (PLL2 valid or PLL2 slip) */ + while ((((TMS570_SYS1.CSVSTAT & SYS_CLKSRC_PLL1) == 0U) && + ((TMS570_ESM.SR[0U] & ESM_SR1_PLL1SLIP) == 0U)) || + (((TMS570_SYS1.CSVSTAT & SYS_CLKSRC_PLL2) == 0U) && + ((TMS570_ESM.SR4 & ESM_SR4_PLL2SLIP) == 0U))) { + /* Wait */ + } + /* If PLL1 valid, check the frequency */ + if (((TMS570_ESM.SR[0U] & ESM_SR1_PLL1SLIP) != 0U) || + ((TMS570_SYS1.GLBSTAT & 0x00000300U) != 0U)) { + failCode |= 1U; + } else { + failCode |= check_frequency(dcc1CNT1_CLKSRC_PLL1); + } + /* If PLL2 valid, check the frequency */ + if (((TMS570_ESM.SR4 & ESM_SR4_PLL2SLIP) != 0U) || + ((TMS570_SYS1.GLBSTAT & 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 */ + TMS570_SYS1.CLKCNTL = (clkCntlSav & 0x000F0100U); + /* restore CLKCNTL, VCLK2R */ + TMS570_SYS1.CLKCNTL = clkCntlSav; + return failCode; +} + +/** @fn uint32_t _errata_SSWF021_45_pll1(uint32_t 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_t _errata_SSWF021_45_pll1(uint32_t count) { + uint32_t failCode, retries, clkCntlSav; + + /* save CLKCNTL */ + clkCntlSav = TMS570_SYS1.CLKCNTL; + /* First set VCLK2 = HCLK */ + TMS570_SYS1.CLKCNTL = clkCntlSav & 0x000F0100U; + /* Now set VCLK = HCLK and enable peripherals */ + TMS570_SYS1.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 */ + TMS570_SYS1.GLBSTAT = 0x00000301U; + /* Clear the ESM PLL slip flags */ + TMS570_ESM.SR[0U] = ESM_SR1_PLL1SLIP; + /* set PLL1 to OSCIN/1*27/(2*1) */ + TMS570_SYS1.PLLCTL1 = 0x20001A00U; + TMS570_SYS1.PLLCTL2 = 0x3FC0723DU; + TMS570_SYS1.CSDISCLR = SYS_CLKSRC_PLL1; + /* Check for PLL1 valid or PLL1 slip*/ + while (((TMS570_SYS1.CSVSTAT & SYS_CLKSRC_PLL1) == 0U) && + ((TMS570_ESM.SR[0U] & ESM_SR1_PLL1SLIP) == 0U)) { + /* Wait */ + } + /* If PLL1 valid, check the frequency */ + if (((TMS570_ESM.SR[0U] & ESM_SR1_PLL1SLIP) != 0U) || + ((TMS570_SYS1.GLBSTAT & 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 */ + TMS570_SYS1.CLKCNTL = (clkCntlSav & 0x000F0100U); + /* restore CLKCNTL, VCLK2R */ + TMS570_SYS1.CLKCNTL = clkCntlSav; + return failCode; +} + +/** @fn uint32_t _errata_SSWF021_45_pll2(uint32_t 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_t _errata_SSWF021_45_pll2(uint32_t count) { + uint32_t failCode, retries, clkCntlSav; + + /* save CLKCNTL */ + clkCntlSav = TMS570_SYS1.CLKCNTL; + /* First set VCLK2 = HCLK */ + TMS570_SYS1.CLKCNTL = clkCntlSav & 0x000F0100U; + /* Now set VCLK = HCLK and enable peripherals */ + TMS570_SYS1.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 */ + TMS570_SYS1.GLBSTAT = 0x00000301U; + /* Clear the ESM PLL slip flags */ + TMS570_ESM.SR4 = ESM_SR4_PLL2SLIP; + /* set PLL2 to OSCIN/1*27/(2*1) */ + TMS570_SYS2.PLLCTL3 = 0x20001A00U; + TMS570_SYS1.CSDISCLR = SYS_CLKSRC_PLL2; + /* Check for PLL2 valid or PLL2 slip */ + while (((TMS570_SYS1.CSVSTAT & SYS_CLKSRC_PLL2) == 0U) && + ((TMS570_ESM.SR4 & ESM_SR4_PLL2SLIP) == 0U)) { + /* Wait */ + } + /* If PLL2 valid, check the frequency */ + if (((TMS570_ESM.SR4 & ESM_SR4_PLL2SLIP) != 0U) || + ((TMS570_SYS1.GLBSTAT & 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 */ + TMS570_SYS1.CLKCNTL = (clkCntlSav & 0x000F0100U); + /* restore CLKCNTL, VCLK2R */ + TMS570_SYS1.CLKCNTL = clkCntlSav; + return failCode; +} + +/** @fn uint32_t check_frequency(uint32_t 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_t check_frequency(uint32_t cnt1_clksrc) { + /* Setup DCC1 */ + /** DCC1 Global Control register configuration */ + TMS570_DCC1.GCTRL = + (uint32_t)0x5U | /** Disable DCC1 */ + (uint32_t)((uint32_t)0x5U << 4U) | /** No Error Interrupt */ + (uint32_t)((uint32_t)0xAU << 8U) | /** Single Shot mode */ + (uint32_t)((uint32_t)0x5U << 12U); /** No Done Interrupt */ + /* Clear ERR and DONE bits */ + TMS570_DCC1.STAT = 3U; + /** DCC1 Clock0 Counter Seed value configuration */ + TMS570_DCC1.CNT0SEED = 68U; + /** DCC1 Clock0 Valid Counter Seed value configuration */ + TMS570_DCC1.VALID0SEED = 4U; + /** DCC1 Clock1 Counter Seed value configuration */ + TMS570_DCC1.CNT1SEED = 972U; + /** DCC1 Clock1 Source 1 Select */ + TMS570_DCC1.CNT1CLKSRC = + (uint32_t)((uint32_t)10U << 12U) | /** DCC Enable / Disable Key */ + (uint32_t)cnt1_clksrc; /** DCC1 Clock Source 1 */ + + TMS570_DCC1.CNT0CLKSRC = + (uint32_t)DCC1_CNT0_OSCIN; /** DCC1 Clock Source 0 */ + + /** DCC1 Global Control register configuration */ + TMS570_DCC1.GCTRL = + (uint32_t)0xAU | /** Enable DCC1 */ + (uint32_t)((uint32_t)0x5U << 4U) | /** No Error Interrupt */ + (uint32_t)((uint32_t)0xAU << 8U) | /** Single Shot mode */ + (uint32_t)((uint32_t)0x5U << 12U); /** No Done Interrupt */ + while (TMS570_DCC1.STAT == 0U) { + /* Wait */ + } + return (TMS570_DCC1.STAT & 0x01U); +} + +/** @fn uint32_t disable_plls(uint32_t 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_t disable_plls(uint32_t plls) { + uint32_t timeout, failCode; + + TMS570_SYS1.CSDISSET = plls; + failCode = 0U; + timeout = 0x10U; + timeout--; + while (((TMS570_SYS1.CSVSTAT & (plls)) != 0U) && (timeout != 0U)) { + /* Clear ESM and GLBSTAT PLL slip flags */ + TMS570_SYS1.GLBSTAT = 0x00000300U; + + if ((plls & SYS_CLKSRC_PLL1) == SYS_CLKSRC_PLL1) { + TMS570_ESM.SR[0U] = ESM_SR1_PLL1SLIP; + } + if ((plls & SYS_CLKSRC_PLL2) == SYS_CLKSRC_PLL2) { + TMS570_ESM.SR4 = ESM_SR4_PLL2SLIP; + } + timeout--; + /* Wait */ + } + if (timeout == 0U) { + failCode = 4U; + } else { + failCode = 0U; + } + return failCode; +} -- cgit v1.2.3