diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a26bab..4788d95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(simplelink) add_subdirectory(simplelink_lpf3) add_subdirectory(mspm0) +add_subdirectory(hercules/tms570lc43) diff --git a/hercules/tms570lc43/CMakeLists.txt b/hercules/tms570lc43/CMakeLists.txt new file mode 100644 index 0000000..16f150e --- /dev/null +++ b/hercules/tms570lc43/CMakeLists.txt @@ -0,0 +1,13 @@ +if(CONFIG_HAS_TMS570_HALCOGEN_CODE) + zephyr_include_directories( + include + ) + + zephyr_library() + zephyr_library_compile_definitions(${COMPILER}) + zephyr_library_sources( + source/soc_init.c + source/asm_funcs.S + source/soc_pll_errata.c + ) +endif() \ No newline at end of file diff --git a/hercules/tms570lc43/README.md b/hercules/tms570lc43/README.md new file mode 100644 index 0000000..5d7898d --- /dev/null +++ b/hercules/tms570lc43/README.md @@ -0,0 +1,13 @@ +Halcogen exported code for TMS570LC43xx MCU +=========================================== + +There is no HAL available from TI to download and include for TMS570 +or hercules series per se, we have code generated by their tool Halcogen +fo this family if chips. + +This directory contains code exported and adapted from that, and the +reason to include it here is simply due to licensing of the said code. + +The modifications are mainly to make the code less verbose while still +mostly keeping it similar. The assembly portions in particular are +mostly as is. diff --git a/hercules/tms570lc43/source/asm_funcs.S b/hercules/tms570lc43/source/asm_funcs.S new file mode 100644 index 0000000..61edf99 --- /dev/null +++ b/hercules/tms570lc43/source/asm_funcs.S @@ -0,0 +1,286 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 2025 ispace, inc. + * + * 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 +#include + +/* Exports */ +GTEXT(_mpuInit_) +GTEXT(soc_reset_hook) + +#define MINITGCR =#0xFFFFFF5C +#define MSIENA =#0xFFFFFF60 +#define MSTCGSTAT =#0xFFFFFF68 + +#define r1Base =#0x00000000 +#define r2Base =#0x00000000 +#define r3Base =#0x08000000 +#define r4Base =#0xF8000000 +#define r5Base =#0x60000000 +#define r6Base =#0x80000000 +#define r7Base =#0xF0000000 +#define r8Base =#0x00000000 +#define r9Base =#0x00000000 +#define r10Base =#0x00000000 +#define r11Base =#0x00000000 +#define r12Base =#0x00000000 +#define r13Base =#0x00000000 +#define r14Base =#0x00000000 +#define r15Base =#0x00000000 +#define r16Base =#0xFFF80000 + +/** + * initialise memory areas (adapted from _memInit_ generated by Halcogen) + * NOTE: do not use callee saved registers + */ +SECTION_FUNC(TEXT, soc_reset_hook) + ldr r12, MINITGCR /* Load MINITGCR register address */ + mov r10, #0xA + str r10, [r12] /* Enable global memory hardware initialization */ + + ldr r11, MSIENA /* Load MSIENA register address */ + mov r10, #0x1 /* Bit position 0 of MSIENA corresponds to SRAM */ + str r10, [r11] /* Enable auto hardware initalisation for SRAM */ +mloop: /* Loop till memory hardware initialization comletes */ + ldr r9, MSTCGSTAT /* check MSTCGSTAT */ + ldr r10, [r9] + tst r10, #0x100 + beq mloop + + ldr r11, MSIENA /* Load MSIENA register address */ + mov r10, #0x4 /* Bit position 2 of MSIENA corresponds to VIM RAM */ + str r10, [r11] /* Enable auto hardware initalisation for VIM RAM */ +mloop2: /* Loop till memory hardware initialization comletes */ + ldr r9, MSTCGSTAT /* check MSTCGSTAT */ + ldr r10, [r9] + tst r10, #0x100 + beq mloop2 + + mov r10, #5 + str r10, [r12] /* Disable global memory hardware initialization */ + + /* now stack is usable */ + push {lr} + bl soc_platform_init + pop {lr} + + bx lr + +SECTION_FUNC(TEXT, _mpuInit_) + /* Disable mpu */ + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + dsb + mcr p15, #0, r0, c1, c0, #0 + isb + /* Disable background region */ + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x20000 + mcr p15, #0, r0, c1, c0, #0 + /* Setup region 1 */ + mov r0, #0 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r1Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0008 + orr r0, r0, #0x1000 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((1 << 15) + (1 << 14) + (1 << 13) + (1 << 12) + (1 << 11) + (1 << 10) + (1 << 9) + (1 << 8) + (0x1F << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 2 */ + mov r0, #1 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r2Base + mcr p15, #0, r0, c6, c1, #0 + /* non cached flash */ + mov r0, #0x000C + /* cached flash */ + /* mov r0, #0x0002 */ + orr r0, r0, #0x0600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x15 << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 3 */ + mov r0, #2 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r3Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x000B + orr r0, r0, #0x1300 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x12 << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 4 */ + mov r0, #3 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r4Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0010 + orr r0, r0, #0x1300 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (1 << 10) + (1 << 9) + (1 << 8) + (0x1A << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 5 */ + mov r0, #4 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r5Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0000 + orr r0, r0, #0x0300 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((1 << 15) + (1 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x1B << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 6 */ + mov r0, #5 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r6Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x0300 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x1A << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 7 */ + mov r0, #6 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r7Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0008 + orr r0, r0, #0x1200 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x16 << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 8 */ + mov r0, #7 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r8Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0010 + orr r0, r0, #0x1200 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 9 */ + mov r0, #8 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r9Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x1200 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 10 */ + mov r0, #9 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r10Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x000C + orr r0, r0, #0x1300 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 11 */ + mov r0, #10 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r11Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x0600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 12 */ + mov r0, #11 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r12Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x1600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 13 */ + mov r0, #12 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r13Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x1600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 14 */ + mov r0, #13 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r14Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x1600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 15 */ + mov r0, #14 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r15Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0006 + orr r0, r0, #0x1600 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x04 << 1) + (0)) + mcr p15, #0, r0, c6, c1, #2 + /* Setup region 16 */ + mov r0, #15 + mcr p15, #0, r0, c6, c2, #0 + ldr r0, r16Base + mcr p15, #0, r0, c6, c1, #0 + mov r0, #0x0010 + orr r0, r0, #0x1200 + mcr p15, #0, r0, c6, c1, #4 + movw r0, #((0 << 15) + (0 << 14) + (0 << 13) + (0 << 12) + (0 << 11) + (0 << 10) + (0 << 9) + (0 << 8) + (0x12 << 1) + (1)) + mcr p15, #0, r0, c6, c1, #2 + + /* Enable mpu */ + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #1 + dsb + mcr p15, #0, r0, c1, c0, #0 + isb + bx lr diff --git a/hercules/tms570lc43/source/soc_init.c b/hercules/tms570lc43/source/soc_init.c new file mode 100644 index 0000000..446f052 --- /dev/null +++ b/hercules/tms570lc43/source/soc_init.c @@ -0,0 +1,363 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 2025 ispace, inc. + * + * 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 +#include +#include +#include "soc_internal.h" +#include "soc_defaults.h" + +#define TMS570_RST_BIT (0x02 << 14) + +void sys_arch_reboot(int type) +{ + /* clear the reset reason before going into reset */ + sys_write32(0xFFFF, REG_SYSESR); + + /* we need to disable POM register before we reset CPU */ + sys_write32(0, REG_POMGLBCTRL); + sys_write32(TMS570_RST_BIT, REG_SYSECR); +} + +static void system_init(void) +{ + uint32_t _csvstat, _csdis, _clkcntl; + + /* disable PLL1 and PLL2 */ + sys_write32(CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2, REG_SYS1_CSDISSET); + while ((sys_read32(REG_SYS1_CSDIS) & (CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2)) + != (CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2)) { + /* wait */ + } + + sys_write32((GLBSTAT_OSCFAIL | GLBSTAT_RFSLIP | GLBSTAT_FBSLIP), + REG_SYS1_GBLSTAT); + sys_write32(PLLCTL1_INIT_VALUE, REG_SYS1_PLLCTL1); + sys_write32(PLLCTL2_INIT_VALUE, REG_SYS1_PLLCTL2); + sys_write32(PLLCTL3_INIT_VALUE, REG_SYS2_PLLCTL3); + + /* Enable PLL(s) to start up or Lock */ + sys_write32((~(CSDIS_SRC_OSC | CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2 | + CSDIS_SRC_LFLPO | CSDIS_SRC_HFLPO)) & CSDIS_SRC_MASK, + REG_SYS1_CSDIS); + sys_write32(CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2, REG_SYS1_CSDISCLR); + + /* Disable Peripherals before peripheral powerup */ + sys_write32(sys_read32(REG_SYS1_CLKCNTL) & ~CLKCNTL_PENA, + REG_SYS1_CLKCNTL); + + /* Release peripherals from reset, enable clocks to all peripherals */ + /* Power-up all peripherals */ + sys_write32(0xffffffff, REG_PCR1_PSPWRDWNCLR0); + sys_write32(0xffffffff, REG_PCR1_PSPWRDWNCLR1); + sys_write32(0xffffffff, REG_PCR1_PSPWRDWNCLR2); + sys_write32(0xffffffff, REG_PCR1_PSPWRDWNCLR3); + + sys_write32(0xffffffff, REG_PCR2_PSPWRDWNCLR0); + sys_write32(0xffffffff, REG_PCR2_PSPWRDWNCLR1); + sys_write32(0xffffffff, REG_PCR2_PSPWRDWNCLR2); + sys_write32(0xffffffff, REG_PCR2_PSPWRDWNCLR3); + + sys_write32(0xffffffff, REG_PCR3_PSPWRDWNCLR0); + sys_write32(0xffffffff, REG_PCR3_PSPWRDWNCLR1); + sys_write32(0xffffffff, REG_PCR3_PSPWRDWNCLR2); + sys_write32(0xffffffff, REG_PCR3_PSPWRDWNCLR3); + + /* Enable Peripherals */ + sys_write32(sys_read32(REG_SYS1_CLKCNTL) | CLKCNTL_PERIPHENA, + REG_SYS1_CLKCNTL); + + /* Setup flash read mode, address wait states and data wait states */ + sys_write32(FRDCNTL_INIT_VALUE, REG_FCR_FRDCNTL); + sys_write32(FSM_WR_ENA_ENABLE_VAL, REG_FCR_FSM_WR_ENA); + sys_write32(EEPROM_CONFIG_INIT_VALUE, REG_FCR_EEPROM_CONFIG); + sys_write32(FSM_WR_ENA_DISABLE_VAL, REG_FCR_FSM_WR_ENA); + /** - Setup flash bank power modes */ + sys_write32(FBPWRMODE_INIT_VALUE, REG_FCR_FBPWRMODE); + + /* Initialize Clock Tree */ + /* Setup system clock divider for HCLK */ + sys_write32(1 << HCLKCNTL_HCLKR_OFFSET, REG_SYS2_HCLKCNTL); + /* Disable / Enable clock domain */ + sys_write32(CDDIS_VCLKA2, REG_SYS1_CDDIS); + /* Wait for until clocks are locked */ + do { + _csvstat = sys_read32(REG_SYS1_CSVSTAT); + _csdis = sys_read32(REG_SYS1_CSDIS); + } while ((_csvstat & ((_csdis ^ 0xFF) & 0xFF)) + != ((_csdis ^ 0xFFU) & 0xFFU)); + + /* + * All clock domains are working off the default clock sources until now. + * Setup GCLK, HCLK and VCLK clock source for normal operation, power down + * mode and after wakeup + */ + sys_write32(GHVSRC_INIT_VALUE, REG_SYS1_GHVSRC); + /* Setup RTICLK1 */ + sys_write32(RCLKSRC_INIT_VALUE, REG_SYS1_RCLKSRC); + /* Setup asynchronous peripheral clock sources for AVCLK1 and AVCLK2 */ + sys_write32(VCLKASRC_INIT_VALUE, REG_SYS1_VCLKASRC); + + /* Setup synchronous peripheral clock dividers for VCLK1, VCLK2, VCLK3 */ + /** + * Please check the note about VCLK and VCLK2 clock ratio + * restrictions in TRM. The default value is the same as what we are + * setting it to, but the order of setting matters, and both cannot be + * set together. + */ + _clkcntl = sys_read32(REG_SYS1_CLKCNTL); + sys_write32((1 << CLKCNTL_VCLKR_OFFSET) | (_clkcntl & ~CLKCNTL_VCLK2R_MASK), + REG_SYS1_CLKCNTL); + sys_write32((1 << CLKCNTL_VCLK2R_OFFSET) | (_clkcntl & ~CLKCNTL_VCLKR_MASK), + REG_SYS1_CLKCNTL); + sys_write32((1 << CLK2CNTRL_VCLK3R_OFFSET) | (sys_read32(REG_SYS2_CLK2CNTRL) + & ~CLK2CNTRL_VCLK3R_MASK), REG_SYS2_CLK2CNTRL); + sys_write32(VCLKACON1_INIT_VALUE, REG_SYS2_VCLKACON1); + + /* Now the PLLs are locked and the PLL outputs can be sped up */ + /* The R-divider was programmed to be 0x1F. The divider is now changed to programmed value */ + sys_write32((0 << PLLCTL1_PLLDIV_OFFSET) | (sys_read32(REG_SYS1_PLLCTL1) + & PLLCTL1_PLLDIV_MASK), REG_SYS1_PLLCTL1); + sys_write32((0 << PLLCTL3_PLLDIV2_OFFSET) | (sys_read32(REG_SYS2_PLLCTL3) + & PLLCTL3_PLLDIV2_MASK), REG_SYS2_PLLCTL3); +} + +static resetSource_t get_reset_source(void) +{ + resetSource_t rst_source; + + if ((sys_read32(REG_SYSESR) & (uint32_t)POWERON_RESET) != 0U) { + /* power-on reset condition */ + rst_source = POWERON_RESET; + /* Clear all exception status Flag and proceed since it's power up */ + sys_write32(0x0000FFFFU, REG_SYSESR); + } + + else if ((sys_read32(REG_SYSESR) & (uint32_t)EXT_RESET) != 0U) { + sys_write32((uint32_t)EXT_RESET, REG_SYSESR); + + /*** Check for other causes of EXT_RESET that would take precedence **/ + if ((sys_read32(REG_SYSESR) & (uint32_t)OSC_FAILURE_RESET) != 0U) { + /** + * Reset caused due to oscillator failure. + * Add user code here to handle oscillator failure + */ + rst_source = OSC_FAILURE_RESET; + sys_write32((uint32_t)OSC_FAILURE_RESET, REG_SYSESR); + } else if ((sys_read32(REG_SYSESR) & (uint32_t)WATCHDOG_RESET) != 0U) { + /* Reset caused due watchdog violation */ + rst_source = WATCHDOG_RESET; + sys_write32((uint32_t)WATCHDOG_RESET, REG_SYSESR); + } else if ((sys_read32(REG_SYSESR) & (uint32_t)WATCHDOG2_RESET) != 0U) { + /* Reset caused due watchdog violation */ + rst_source = WATCHDOG2_RESET; + sys_write32((uint32_t)WATCHDOG2_RESET, REG_SYSESR); + } else if ((sys_read32(REG_SYSESR) & (uint32_t)SW_RESET) != 0U) { + /* Reset caused due to software reset. */ + rst_source = SW_RESET; + sys_write32((uint32_t)SW_RESET, REG_SYSESR); + } else { + /* Reset caused due to External reset. */ + rst_source = EXT_RESET; + } + } else if ((sys_read32(REG_SYSESR) & (uint32_t)DEBUG_RESET) != 0U) { + /* Reset caused due Debug reset request */ + rst_source = DEBUG_RESET; + sys_write32((uint32_t)DEBUG_RESET, REG_SYSESR); + } else if ((sys_read32(REG_SYSESR) & (uint32_t)CPU0_RESET) != 0U) { + /** + * Reset caused due to CPU0 reset. CPU reset can be caused by CPU self-test + * completion, or by toggling the "CPU RESET" bit of the CPU Reset Control Register. + */ + rst_source = CPU0_RESET; + sys_write32((uint32_t)CPU0_RESET, REG_SYSESR); + } else { + /* No_reset occurred. */ + rst_source = NO_RESET; + } + + return rst_source; +} + +static void esm_init(void) +{ + /** - Disable error pin channels */ + sys_write32(0xFFFFFFFFU, REG_ESM_DEPAPR1); + sys_write32(0xFFFFFFFFU, REG_ESM_IEPCR4); + sys_write32(0xFFFFFFFFU, REG_ESM_IEPCR7); + + /** - Disable interrupts */ + sys_write32(0xFFFFFFFFU, REG_ESM_IECR1); + sys_write32(0xFFFFFFFFU, REG_ESM_IECR4); + sys_write32(0xFFFFFFFFU, REG_ESM_IECR7); + + /** - Clear error status flags */ + sys_write32(0xFFFFFFFFU, REG_ESM_SR1_0); + sys_write32(0xFFFFFFFFU, REG_ESM_SR1_1); + sys_write32(0xFFFFFFFFU, REG_ESM_SSR2); + sys_write32(0xFFFFFFFFU, REG_ESM_SR1_2); + sys_write32(0xFFFFFFFFU, REG_ESM_SR4_0); + sys_write32(0xFFFFFFFFU, REG_ESM_SR7_0); + + /** - Setup LPC preload */ + sys_write32(16384U - 1U, REG_ESM_LTCPR); + + /** - Reset error pin */ + if (sys_read32(REG_ESM_EPSR) == 0U) { + sys_write32(0x00000005U, REG_ESM_EKR); + } else { + sys_write32(0x00000000U, REG_ESM_EKR); + } + + /** - Clear interrupt level */ + sys_write32(0xFFFFFFFFU, REG_ESM_ILCR1); + sys_write32(0xFFFFFFFFU, REG_ESM_ILCR4); + sys_write32(0xFFFFFFFFU, REG_ESM_ILCR7); + + /** - Set interrupt level */ + sys_write32(0, REG_ESM_ILSR1); + sys_write32(0, REG_ESM_ILSR4); + sys_write32(0, REG_ESM_ILSR7); + + /** - Enable error pin channels */ + sys_write32(0, REG_ESM_EEPAPR1); + sys_write32(0, REG_ESM_IEPSR4); + sys_write32(0, REG_ESM_IEPSR7); + + /** - Enable interrupts */ + sys_write32(0, REG_ESM_IESR1); + sys_write32(0, REG_ESM_IESR4); + sys_write32(0, REG_ESM_IESR7); +} + +static void cache_enable(void) +{ + if (IS_ENABLED(CONFIG_ICACHE)) { + if (!(__get_SCTLR() & SCTLR_I_Msk)) { + L1C_InvalidateICacheAll(); + __set_SCTLR(__get_SCTLR() | SCTLR_I_Msk); + barrier_isync_fence_full(); + } + } + + if (IS_ENABLED(CONFIG_DCACHE)) { + if (!(__get_SCTLR() & SCTLR_C_Msk)) { + L1C_InvalidateDCacheAll(); + __set_SCTLR(__get_SCTLR() | SCTLR_C_Msk); + barrier_dsync_fence_full(); + } + } +} + +/** + * 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. + */ +static void event_bus_export(void) +{ + uint32_t temp; + + /* set X bit (bit 4) in cp15 PMSR */ + __get_CP(15, 0, temp, 9, 12, 0); + temp |= BIT(4); + __set_CP(15, 0, temp, 9, 12, 0); +} + +void soc_platform_init(void) +{ + const int pll_retries = 5; + resetSource_t rstSrc; + + /* XXX: removing this delay makes the CPU stuck */ + for (volatile uint64_t i = 0; i < 0xfffff; i++) { + /* wait */ + } + + rstSrc = get_reset_source(); + + switch (rstSrc) { + case POWERON_RESET: + /* Add condition to check whether PLL can be started successfully */ + if (_errata_SSWF021_45_both_plls(pll_retries) != 0U) { + /* Put system in a safe state */ + /* Handle PLL failure */ + } + + case DEBUG_RESET: + case EXT_RESET: + /** + * Check if there were ESM group3 errors during power-up. + * These could occur during eFuse auto-load or during reads from flash OTP + * during power-up. Device operation is not reliable and not recommended + * in this case. + */ + if (sys_read32(REG_ESM_SR1_2) != 0U) { + /* Handle group3 notification */ + } + + /** + * Configure system response to error conditions signaled to the ESM group1. + * This function can be configured from the ESM tab of HALCoGen + */ + esm_init(); + break; + + case OSC_FAILURE_RESET: + break; + + case WATCHDOG_RESET: + case WATCHDOG2_RESET: + break; + + case CPU0_RESET: + break; + + case SW_RESET: + break; + + default: + break; + } + + event_bus_export(); + _mpuInit_(); + cache_enable(); + system_init(); +} diff --git a/hercules/tms570lc43/source/soc_pll_errata.c b/hercules/tms570lc43/source/soc_pll_errata.c new file mode 100644 index 0000000..726ea3b --- /dev/null +++ b/hercules/tms570lc43/source/soc_pll_errata.c @@ -0,0 +1,227 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 2025 ispace, inc. + * + * 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 +#include "soc_internal.h" +#include "soc_defaults.h" + +#define ESM_SR1_PLL1SLIP 0x400U +#define ESM_SR4_PLL2SLIP 0x400U + +#define dcc1CNT1_CLKSRC_PLL1 0x0000A000U +#define dcc1CNT1_CLKSRC_PLL2 0x0000A001U + +enum dcc1clocksource { + 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 */ + + DCC1_CNT1_PLL1 = 0x0U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 0 */ + DCC1_CNT1_PLL2 = 0x1U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 1 */ + DCC1_CNT1_LF_LPO = 0x2U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 2 */ + DCC1_CNT1_HF_LPO = 0x3U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 3 */ + DCC1_CNT1_EXTCLKIN1 = 0x5U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 4 */ + DCC1_CNT1_EXTCLKIN2 = 0x6U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 6 */ + DCC1_CNT1_VCLK = 0x8U, /**< Alias for DCC1 CNT 1 CLOCK SOURCE 8 */ + DCC1_CNT1_N2HET1_31 = 0xAU /**< Alias for DCC1 CNT 1 CLOCK SOURCE 9 */ +}; + +#define REG_DCC_GCTRL (DRV_DCC + 0x0000) /**< 0x0000: DCC Control */ +#define REG_DCC_REV (DRV_DCC + 0x0004) /**< 0x0004: DCC Revision Id */ +#define REG_DCC_CNT0SEED (DRV_DCC + 0x0008) /**< 0x0008: DCC Counter0 Seed */ +#define REG_DCC_VALID0SEED (DRV_DCC + 0x000C) /**< 0x000C: DCC Valid0 Seed */ +#define REG_DCC_CNT1SEED (DRV_DCC + 0x0010) /**< 0x0010: DCC Counter1 Seed */ +#define REG_DCC_STAT (DRV_DCC + 0x0014) /**< 0x0014: DCC Status */ +#define REG_DCC_CNT0 (DRV_DCC + 0x0018) /**< 0x0018: DCC Counter0 Value */ +#define REG_DCC_VALID0 (DRV_DCC + 0x001C) /**< 0x001C: DCC Valid0 Value */ +#define REG_DCC_CNT1 (DRV_DCC + 0x0020) /**< 0x0020: DCC Counter1 Value */ +#define REG_DCC_CNT1CLKSRC (DRV_DCC + 0x0024) /**< 0x0024: DCC Counter1 Clock Source */ +#define REG_DCC_CNT0CLKSRC (DRV_DCC + 0x0028) /**< 0x0028: DCC Counter0 Clock Source */ + +static uint32_t disable_plls(uint32_t plls) +{ + uint32_t timeout, failCode; + + sys_write32(plls, REG_SYS1_CSDISSET); + failCode = 0U; + timeout = 0x10U; + timeout--; + + while (((sys_read32(REG_SYS1_CSVSTAT) & (plls)) != 0U) && (timeout != 0U)) { + /* Clear ESM and GLBSTAT PLL slip flags */ + sys_write32(0x00000300U, REG_SYS1_GBLSTAT); + + if ((plls & CSDIS_SRC_PLL1) == CSDIS_SRC_PLL1) { + sys_write32(ESM_SR1_PLL1SLIP, REG_ESM_SR1_0); + } + if ((plls & CSDIS_SRC_PLL2) == CSDIS_SRC_PLL2) { + sys_write32(ESM_SR4_PLL2SLIP, REG_ESM_SR4_0); + } + + timeout--; + /* Wait */ + } + + if (timeout == 0U) { + failCode = 4U; + } else { + failCode = 0U; + } + + return failCode; +} + +static uint32_t check_frequency(uint32_t cnt1_clksrc) +{ + uint32_t val; + + /* Setup DCC1 */ + /** DCC1 Global Control register configuration */ + val = (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 */ + sys_write32(val, REG_DCC_GCTRL); + + /* Clear ERR and DONE bits */ + sys_write32(3, REG_DCC_STAT); + + /** DCC1 Clock0 Counter Seed value configuration */ + sys_write32(68U, REG_DCC_CNT0SEED); + + /** DCC1 Clock0 Valid Counter Seed value configuration */ + sys_write32(4U, REG_DCC_VALID0SEED); + + /** DCC1 Clock1 Counter Seed value configuration */ + sys_write32(972U, REG_DCC_CNT1SEED); + + /** DCC1 Clock1 Source 1 Select */ + val = (uint32_t)((uint32_t)10U << 12U) | /** DCC Enable / Disable Key */ + (uint32_t) cnt1_clksrc; /** DCC1 Clock Source 1 */ + sys_write32(val, REG_DCC_CNT1CLKSRC); + + val = (uint32_t)DCC1_CNT0_OSCIN; /** DCC1 Clock Source 0 */ + sys_write32(val, REG_DCC_CNT0CLKSRC); + + /** DCC1 Global Control register configuration */ + val = (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 */ + sys_write32(val, REG_DCC_GCTRL); + + while (sys_read32(REG_DCC_STAT) == 0U) { + /* Wait */ + } + + return (sys_read32(REG_DCC_STAT) & 0x01U); +} + +uint32_t _errata_SSWF021_45_both_plls(uint32_t count) +{ + uint32_t fail_code, retries, clk_cntl_sav; + + clk_cntl_sav = sys_read32(REG_SYS1_CLKCNTL); + + /* First set VCLK2 = HCLK */ + sys_write32(clk_cntl_sav & 0x000F0100U, REG_SYS1_CLKCNTL); + /* Now set VCLK = HCLK and enable peripherals */ + sys_write32(CLKCNTL_PENA, REG_SYS1_CLKCNTL); + + fail_code = 0U; + + for (retries = 0U; retries < count; retries++) { + fail_code = 0U; + + /* Disable PLL1 and PLL2 */ + fail_code = disable_plls(CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2); + + if (fail_code != 0U) { + break; + } + + /* Clear Global Status Register */ + sys_write32(0x00000301U, REG_SYS1_GBLSTAT); + /* Clear the ESM PLL slip flags */ + sys_write32(ESM_SR1_PLL1SLIP, REG_ESM_SR1_0); + sys_write32(ESM_SR4_PLL2SLIP, REG_ESM_SR4_0); + /* set both PLLs to OSCIN/1*27/(2*1) */ + sys_write32(0x20001A00U, REG_SYS1_PLLCTL1); + sys_write32(0x3FC0723DU, REG_SYS1_PLLCTL2); + sys_write32(0x20001A00U, REG_SYS2_PLLCTL3); + sys_write32(CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2, REG_SYS1_CSDISCLR); + + /* Check for (PLL1 valid or PLL1 slip) and (PLL2 valid or PLL2 slip) */ + while ((((sys_read32(REG_SYS1_CSVSTAT) & CSDIS_SRC_PLL1) == 0U) + && ((sys_read32(REG_ESM_SR1_0) & ESM_SR1_PLL1SLIP) == 0U)) + || (((sys_read32(REG_SYS1_CSVSTAT) & CSDIS_SRC_PLL2) == 0U) + && ((sys_read32(REG_ESM_SR4_0) & ESM_SR4_PLL2SLIP) == 0U))) { + /* Wait */ + } + + /* If PLL1 valid, check the frequency */ + if (((sys_read32(REG_ESM_SR1_0) & ESM_SR1_PLL1SLIP) != 0U) + || ((sys_read32(REG_SYS1_GBLSTAT) & 0x00000300U) != 0U)) { + fail_code |= 1U; + } else { + fail_code |= check_frequency(dcc1CNT1_CLKSRC_PLL1); + } + + /* If PLL2 valid, check the frequency */ + if (((sys_read32(REG_ESM_SR4_0) & ESM_SR4_PLL2SLIP) != 0U) + || ((sys_read32(REG_SYS1_GBLSTAT) & 0x00000300U) != 0U)) { + fail_code |= 2U; + } else { + fail_code |= (check_frequency(dcc1CNT1_CLKSRC_PLL2) << 1U); + } + + if (fail_code == 0U) { + break; + } + } + + /* To avoid MISRA violation 382S (void)missing for discarded return value */ + fail_code = disable_plls(CSDIS_SRC_PLL1 | CSDIS_SRC_PLL2); + /* restore CLKCNTL, VCLKR and PENA first */ + sys_write32(clk_cntl_sav & 0x000F0100U, REG_SYS1_CLKCNTL); + /* restore CLKCNTL, VCLK2R */ + sys_write32(clk_cntl_sav, REG_SYS1_CLKCNTL); + + return fail_code; +}