Files
rtems/bsps/arm/tms570/start/hwinit-lc4357-hdk.c
2024-06-04 15:50:57 +00:00

334 lines
15 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause */
/**
* @file
*
* @ingroup RTEMSBSPsARMTMS570
*
* @brief This source file contains parts of the system initialization.
*/
/*
* Copyright (C) 2022 Airbus U.S. Space & Defense, Inc
* Copyright (C) 2016 Pavel Pisa <pisa@cmp.felk.cvut.cz>
* Copyright (C) 2009-2015 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 <bsp/tms570.h>
#include <bsp/tms570_hwinit.h>
#include <bsp/tms570-pinmux.h>
typedef enum Tms570ClockDisableSources {
TMS570_CLKDIS_SRC_OSC = 0x01, ///< External high-speed oscillator as clock source
TMS570_CLKDIS_SRC_PLL1 = 0x02,
TMS570_CLKDIS_SRC_RESERVED = 0x04, ///< reserved. not tied to actual clock source
TMS570_CLKDIS_SRC_EXT_CLK1 = 0x08,
TMS570_CLKDIS_SRC_LOW_FREQ_LPO = 0x10,
TMS570_CLKDIS_SRC_HIGH_FREQ_LPO = 0x20,
TMS570_CLKDIS_SRC_PLL2 = 0x40,
TMS570_CLKDIS_SRC_EXT_CLK2 = 0x80,
} Tms570ClockDisableSources;
// Source selection for G, H, and V clocks SYS1.GHVSRC reg
typedef enum Tms570GhvClockSources {
TMS570_SYS_CLK_SRC_OSC = 0U, /**< Alias for oscillator clock Source */
TMS570_SYS_CLK_SRC_PLL1 = 1U, /**< Alias for Pll1 clock Source */
TMS570_SYS_CLK_SRC_EXTERNAL1 = 3U, /**< Alias for external clock Source */
TMS570_SYS_CLK_SRC_LPO_LOW = 4U, /**< Alias for low power oscillator low clock Source */
TMS570_SYS_CLK_SRC_LPO_HIGH = 5U, /**< Alias for low power oscillator high clock Source */
TMS570_SYS_CLK_SRC_PLL2 = 6U, /**< Alias for Pll2 clock Source */
TMS570_SYS_CLK_SRC_EXTERNAL2 = 7U, /**< Alias for external 2 clock Source */
TMS570_SYS_CLK_SRC_VCLK = 9U /**< Alias for synchronous VCLK1 clock Source */
} Tms570GhvClockSources;
/*
* The next construct allows to compute values for individual
* PINMMR registers based on the multiple processing
* complete pin functions list at compile time.
* Each line computes 32-bit value which selects function
* of consecutive four pins. Each pin function is defined
* by single byte.
*/
static const uint32_t tms570_pinmmr_init_data[] = {
TMS570_PINMMR_REG_VAL( 0, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 1, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 2, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 3, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 4, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 5, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 6, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 7, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 8, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 9, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 10, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 11, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 12, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 13, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 14, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 15, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 16, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 17, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 18, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 19, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 20, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 21, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 22, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 23, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 24, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 25, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 26, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 27, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 28, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 29, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 30, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 31, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 32, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 33, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 34, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 35, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 36, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
TMS570_PINMMR_REG_VAL( 37, TMS570LC4357_PINMMR_DEFAULT_INIT_LIST ),
};
void tms570_pinmux_init( void )
{
tms570_bsp_pinmmr_config(tms570_pinmmr_init_data, 0, RTEMS_ARRAY_SIZE(tms570_pinmmr_init_data));
tms570_pin_config_prepare();
TMS570_PINMUX[174] = (TMS570_PINMUX[174] & ~(UINT32_C(0x3) << 8)) | (UINT32_C(0x2) << 8); // emif output-enable bit8= 0, bit9= 1
tms570_pin_config_complete();
/* Set ECLK pin to GPIO input */
TMS570_SYS1.SYSPC1 = 0;
TMS570_SYS1.SYSPC2 = 0;
}
void tms570_emif_sdram_init( void )
{
uint32_t dummy;
/* Do not run attempt to initialize SDRAM when code is running from it */
if ( tms570_running_from_sdram() )
return;
// Following the initialization procedure as described in EMIF-errata #5 for the tms570lc43
// at EMIF clock rates >= 40Mhz
// Note step one of this procedure is running this EMIF initialization sequence before PLL
// and clocks are mapped/enabled
// For additional details on startup procedure see tms570lc43 TRM s21.2.5.5.B
// Set SDRAM timings. These are dependent on the EMIF CLK rate, which = VCLK3
// Set these based on the final EMIF clock rate once PLL & VCLK is enabled
TMS570_EMIF.SDTIMR = (uint32_t)1U << 27U|
(uint32_t)0U << 24U|
(uint32_t)0U << 20U|
(uint32_t)0U << 19U|
(uint32_t)1U << 16U|
(uint32_t)1U << 12U|
(uint32_t)1U << 8U|
(uint32_t)0U << 4U;
/* Minimum number of ECLKOUT cycles from Self-Refresh exit to any command */
// Also set this based on the final EMIF clk
TMS570_EMIF.SDSRETR = 2;
// Program the RR Field of SDRCR to provide 200us of initialization time
// Per Errata#5, for EMIF startup, set this based on the non-VLCK3 clk rate.
// The Errata is this register must be calculated as `SDRCR = 200us * EMIF_CLK`
// (typically this would be `SDRCR = (200us * EMIF_CLK) / 8` )
// Since the PLL's arent enabled yet, EMIF_CLK would be EXT_OSCIN / 2
TMS570_EMIF.SDRCR = 1600;
TMS570_EMIF.SDCR = ((uint32_t)0U << 31U)|
((uint32_t)1U << 14U)|
((uint32_t)2U << 9U)|
((uint32_t)1U << 8U)|
((uint32_t)2U << 4U)|
((uint32_t)0); // pagesize = 256
// Read of SDRAM memory location causes processor to wait until SDRAM Initialization completes
dummy = *(volatile uint32_t*)TMS570_MEMORY_SDRAM_ORIGIN;
(void) dummy;
// Program the RR field to the default Refresh Interval of the SDRAM
// Program this to the correct interval for the VCLK3/EMIF_CLK rate
// Do this in the typical way per TRM: SDRCR = ((200us * EMIF_CLK) / 8) + 1
TMS570_EMIF.SDRCR = 1251;
/* Place the EMIF in Self Refresh Mode For Clock Change */
/* Must only write to the upper byte of the SDCR to avoid */
/* a second initialization sequence */
/* The byte address depends on endian (0x3U in LE, 0x00 in BE32) */
*((volatile unsigned char *)(&TMS570_EMIF.SDCR) + 0x0U) = 0x80;
}
/**
* @brief Setup all system PLLs (HCG:setupPLL)
*
*/
void tms570_pll_init( void )
{
//based on HalCoGen setupPLL method
uint32_t pll12_dis = TMS570_CLKDIS_SRC_PLL1 | TMS570_CLKDIS_SRC_PLL2;
/* Disable PLL1 and PLL2 */
TMS570_SYS1.CSDISSET = pll12_dis;
/*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
while ( ( TMS570_SYS1.CSDIS & pll12_dis ) != pll12_dis ) {
/* Wait */
}
/* Clear Global Status Register */
TMS570_SYS1.GLBSTAT = 0x301U;
// Configure PLL control registers
/** - Setup pll control register 1:
* - Disable reset on oscillator slip (ROS)
* - Enable bypass on pll slip
* TODO: desired: switches to OSC when PLL slip detected
* - setup Pll output clock divider to max before Lock
* - Disable reset on oscillator fail
* - Setup reference clock divider
* - Setup Pll multiplier
*
* - PLL1: 16MHz OSC in -> 300MHz PLL1 out
*/
TMS570_SYS1.PLLCTL1 = (TMS570_SYS1_PLLCTL1_ROS * 0)
| (uint32_t)0x40000000U
| TMS570_SYS1_PLLCTL1_PLLDIV(0x1F)
| (TMS570_SYS1_PLLCTL1_ROF * 0)
| TMS570_SYS1_PLLCTL1_REFCLKDIV(4U - 1U)
| TMS570_SYS1_PLLCTL1_PLLMUL((75U - 1U) << 8);
/** - Setup pll control register 2
* - Setup spreading rate
* - Setup bandwidth adjustment
* - Setup internal Pll output divider
* - Setup spreading amount
*/
TMS570_SYS1.PLLCTL2 = ((uint32_t)255U << 22U)
| ((uint32_t)7U << 12U)
| ((uint32_t)(1U - 1U) << 9U)
| 61U;
// Initialize Pll2
/** - Setup pll2 control register :
* - setup Pll output clock divider to max before Lock
* - Setup reference clock divider
* - Setup internal Pll output divider
* - Setup Pll multiplier
*/
TMS570_SYS2.PLLCTL3 = TMS570_SYS2_PLLCTL3_ODPLL2(1U - 1U)
| TMS570_SYS2_PLLCTL3_PLLDIV2(0x1FU)
| TMS570_SYS2_PLLCTL3_REFCLKDIV2(8U - 1U)
| TMS570_SYS2_PLLCTL3_PLLMUL2(( 150U - 1U) << 8 );
// Enable PLL(s) to start up or Lock
// Enable all clock sources except the following
TMS570_SYS1.CSDIS = (TMS570_CLKDIS_SRC_EXT_CLK2 | TMS570_CLKDIS_SRC_EXT_CLK1 | TMS570_CLKDIS_SRC_RESERVED);
}
void tms570_map_clock_init(void)
{
// based on HalCoGen mapClocks method
uint32_t sys_csvstat, sys_csdis;
TMS570_SYS2.HCLKCNTL = 1U;
/** @b Initialize @b Clock @b Tree: */
/** - Disable / Enable clock domain */
TMS570_SYS1.CDDIS = ( 0U << 4U ) | /* AVCLK 1 ON */
( 1U << 5U ) | /* AVCLK 2 OFF */
( 0U << 8U ) | /* VCLK3 ON */
( 0U << 9U ) | /* VCLK4 ON */
( 0U << 10U ) | /* AVCLK 3 ON */
( 0U << 11U ); /* AVCLK 4 ON */
/* Work Around for Errata SYS#46:
* Despite this being a LS3137 errata, hardware testing on the LC4357 indicates this wait is still necessary
*/
sys_csvstat = TMS570_SYS1.CSVSTAT;
sys_csdis = TMS570_SYS1.CSDIS;
while ( ( sys_csvstat & ( ( sys_csdis ^ 0xFFU ) & 0xFFU ) ) !=
( ( sys_csdis ^ 0xFFU ) & 0xFFU ) ) {
sys_csvstat = TMS570_SYS1.CSVSTAT;
sys_csdis = TMS570_SYS1.CSDIS;
}
TMS570_SYS1.GHVSRC = TMS570_SYS1_GHVSRC_GHVWAKE(TMS570_SYS_CLK_SRC_PLL1)
| TMS570_SYS1_GHVSRC_HVLPM(TMS570_SYS_CLK_SRC_PLL1)
| TMS570_SYS1_GHVSRC_GHVSRC(TMS570_SYS_CLK_SRC_PLL1);
/** - Setup RTICLK1 and RTICLK2 clocks */
TMS570_SYS1.RCLKSRC = ((uint32_t)1U << 24U) /* RTI2 divider (Not applicable for lock-step device) */
| ((uint32_t)TMS570_SYS_CLK_SRC_VCLK << 16U) /* RTI2 clock source (Not applicable for lock-step device) Field not in TRM? */
| ((uint32_t)1U << 8U) /* RTI1 divider */
| ((uint32_t)TMS570_SYS_CLK_SRC_VCLK << 0U); /* RTI1 clock source */
/** - Setup asynchronous peripheral clock sources for AVCLK1 and AVCLK2 */
TMS570_SYS1.VCLKASRC = TMS570_SYS1_VCLKASRC_VCLKA2S(TMS570_SYS_CLK_SRC_VCLK)
| TMS570_SYS1_VCLKASRC_VCLKA1S(TMS570_SYS_CLK_SRC_VCLK);
/** - Setup synchronous peripheral clock dividers for VCLK1, VCLK2, VCLK3 */
// VCLK2 = PLL1 / HCLK_DIV / 2 = 75MHz
TMS570_SYS1.CLKCNTL = (TMS570_SYS1.CLKCNTL & ~TMS570_SYS1_CLKCNTL_VCLK2R(0xF))
| TMS570_SYS1_CLKCNTL_VCLK2R(0x1);
// VLCK1 = PLL1 / HCLK_DIV / 2 = 75MHz
TMS570_SYS1.CLKCNTL = (TMS570_SYS1.CLKCNTL & ~TMS570_SYS1_CLKCNTL_VCLKR(0xF))
| TMS570_SYS1_CLKCNTL_VCLKR(0x1);
// VCLK3 = PLL1 / HCLK_DIV / 3 = 50MHz
TMS570_SYS2.CLK2CNTRL = (TMS570_SYS2.CLK2CNTRL & ~TMS570_SYS2_CLK2CNTRL_VCLK3R(0xF))
| TMS570_SYS2_CLK2CNTRL_VCLK3R(0x2);
TMS570_SYS2.VCLKACON1 = TMS570_SYS2_VCLKACON1_VCLKA4R(1U - 1U)
| (TMS570_SYS2_VCLKACON1_VCLKA4_DIV_CDDIS * 0)
| TMS570_SYS2_VCLKACON1_VCLKA4S(TMS570_SYS_CLK_SRC_VCLK)
| TMS570_SYS2_VCLKACON1_VCLKA3R(1U - 1U)
| (TMS570_SYS2_VCLKACON1_VCLKA3_DIV_CDDIS * 0)
| TMS570_SYS2_VCLKACON1_VCLKA3S(TMS570_SYS_CLK_SRC_VCLK);
/* Now the PLLs are locked and the PLL outputs can be sped up */
/* The R-divider was programmed to be 0xF. Now this divider is changed to programmed value */
TMS570_SYS1.PLLCTL1 = (TMS570_SYS1.PLLCTL1 & 0xE0FFFFFFU) | (uint32_t)((uint32_t)(1U - 1U) << 24U);
/*SAFETYMCUSW 134 S MR:12.2 <APPROVED> " Clear and write to the volatile register " */
TMS570_SYS2.PLLCTL3 = (TMS570_SYS2.PLLCTL3 & 0xE0FFFFFFU) | (uint32_t)((uint32_t)(1U - 1U) << 24U);
/* Enable/Disable Frequency modulation */
TMS570_SYS1.PLLCTL2 |= 0x00000000U;
}