blob: f6304edee5feaf072a0c80c8b225bf2ec11ffc1c [file] [log] [blame]
/****************************************************************************
* arch/arm/src/tms570/tms570_clockconfig.c
*
* Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Some logic in this file was inspired/leveraged from TI's Project0 which
* has a compatible BSD license:
*
* Copyright (c) 2012, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name NuttX 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include "arm_internal.h"
#include "hardware/tms570_esm.h"
#include "hardware/tms570_sys.h"
#include "hardware/tms570_sys2.h"
#include "hardware/tms570_pcr.h"
#include "hardware/tms570_flash.h"
#include "hardware/tms570_iomm.h"
#include "hardware/tms570_pinmux.h"
#include "tms570_selftest.h"
#include "tms570_clockconfig.h"
#include <arch/board/board.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef BOARD_VCLK_DIVIDER
# error BOARD_VCLK_DIVIDER is not defined
#endif
#if BOARD_VCLK_DIVIDER == 1
# define SYS_CLKCNTL_VCLKR SYS_CLKCNTL_VCLKR_DIV1
#elif BOARD_VCLK_DIVIDER == 2
# define SYS_CLKCNTL_VCLKR SYS_CLKCNTL_VCLKR_DIV2
#else
# error Invalid value for BOARD_VCLK_DIVIDER
#endif
#ifndef BOARD_VCLK2_DIVIDER
# error BOARD_VCLK2_DIVIDER is not defined
#endif
#if BOARD_VCLK2_DIVIDER == 1
# define SYS_CLKCNTL_VCLKR2 SYS_CLKCNTL_VCLKR2_DIV1
#elif BOARD_VCLK2_DIVIDER == 2
# define SYS_CLKCNTL_VCLKR2 SYS_CLKCNTL_VCLKR2_DIV2
#else
# error Invalid value for SYS_CLKCNTL_VCLKR2_DIV2
#endif
#ifndef BOARD_RTICLK_DIVIDER
# error BOARD_RTICLK_DIVIDER is not defined
#endif
#if BOARD_RTICLK_DIVIDER == 1
# define SYS_RCLKSRC_RTI1DIV SYS_RCLKSRC_RTI1DIV_DIV1
#elif BOARD_RTICLK_DIVIDER == 2
# define SYS_RCLKSRC_RTI1DIV SYS_RCLKSRC_RTI1DIV_DIV2
#elif BOARD_RTICLK_DIVIDER == 4
# define SYS_RCLKSRC_RTI1DIV SYS_RCLKSRC_RTI1DIV_DIV4
#elif BOARD_RTICLK_DIVIDER == 8
# define SYS_RCLKSRC_RTI1DIV SYS_RCLKSRC_RTI1DIV_DIV8
#else
# error Invalid value for BOARD_RTICLK_DIVIDER
#endif
/****************************************************************************
* Private Data
****************************************************************************/
static const struct tms570_pinmux_s g_pinmux_table[] =
{
BOARD_PINMUX_INITIALIZER
};
#define NPINMUX (sizeof(g_pinmux_table) / sizeof(struct tms570_pinmux_s))
/****************************************************************************
* Private Functions
****************************************************************************/
#define ESM_SR1_PLL1SLIP 0x400
#define ESM_SR4_PLL2SLIP 0x400
#define DCC1CNT1_CLKSRC_PLL1 0x0000a000u
#define DCC1CNT1_CLKSRC_PLL2 0x0000a001u
/****************************************************************************
* Name: check_frequency
*
* Description:
* This function is used to verify is the Main Clock frequency correct
****************************************************************************/
static uint32_t check_frequency(uint32_t cnt1_clksrc)
{
uint32_t regval = 0;
/* Setup DCC1: Global Control register configuration */
regval = (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 */
putreg32(regval, TMS570_DCC_BASE);
/* Clear ERR and DONE bits */
regval = 3u;
putreg32(regval, TMS570_DCC_BASE + 0x14);
/* DCC1 Clock0 Counter Seed value configuration */
regval = 68u;
putreg32(regval, TMS570_DCC_BASE + 0x08);
/* DCC1 Clock0 Valid Counter Seed value configuration */
regval = 4u;
putreg32(regval, TMS570_DCC_BASE + 0x0c);
/* DCC1 Clock1 Counter Seed value configuration */
regval = 972u;
putreg32(regval, TMS570_DCC_BASE + 0x10);
/* DCC1 Clock1 Source 1 Select */
regval = (uint32_t)((uint32_t)10u << 12u) | /* DCC Enable / Disable Key */
(uint32_t) cnt1_clksrc; /* DCC1 Clock Source 1 */
putreg32(regval, TMS570_DCC_BASE + 0x24);
regval = (uint32_t)15; /* DCC1 Clock Source 0 */
putreg32(regval, TMS570_DCC_BASE + 0x28);
/* DCC1 Global Control register configuration */
regval = (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 */
putreg32(regval, TMS570_DCC_BASE);
while (getreg32(TMS570_DCC_BASE + 0x14) == 0u)
{
/* Wait */
}
return (getreg32(TMS570_DCC_BASE + 0x14) & 0x01u);
}
/****************************************************************************
* Name: _errata_sswf021_45_both_plls
*
* Description:
* This function is used to verify that PLL1 and PLL2 lock after
* system start-up. If PLL does not lock after system start-up
* and PLL slip occur then this function should be called at the
* beginning of tms570_clockconfig. (Errata sheet TMS570)
*
****************************************************************************/
uint32_t _errata_sswf021_45_both_plls(uint32_t count)
{
uint32_t failcode = 0u;
uint32_t retries;
uint32_t clkcntrlsave;
uint32_t regval;
/* Save CLKCNTL, */
clkcntrlsave = getreg32(TMS570_SYS_CLKCNTL);
/* First set VCLK2 = HCLK */
regval = clkcntrlsave & 0x000f0100u;
putreg32(regval, TMS570_SYS_CLKCNTL);
/* Now set VCLK = HCLK and enable peripherals */
regval = SYS_CLKCNTL_PENA;
putreg32(regval, TMS570_SYS_CLKCNTL);
for (retries = 0u; (retries < count) || (count == 0u); retries++)
{
failcode = 0u;
/* Disable PLL1 and PLL2 */
regval = 0x00000002u | 0x00000040u;
putreg32(regval, TMS570_SYS_CSDISSET);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != regval)
{
}
/* Clear Global Status Register */
regval = 0x00000301u;
putreg32(regval, TMS570_SYS_GLBSTAT);
/* Clear the ESM PLL slip flags */
putreg32(ESM_SR1_PLL1SLIP, TMS570_ESM_SR1);
putreg32(ESM_SR4_PLL2SLIP, TMS570_ESM_SR4);
/* Set both PLLs to OSCIN/1*27/(2*1) */
regval = 0x20001a00u;
putreg32(regval, TMS570_SYS_PLLCTL1);
regval = 0x3fc0723du;
putreg32(regval, TMS570_SYS_PLLCTL2);
regval = 0x20001a00u;
putreg32(regval, 0xffffe100);
regval = 0x00000002u | 0x00000040u;
putreg32(regval, TMS570_SYS_CSDISCLR);
/* Check for (PLL1 valid or PLL1 slip) and (PLL2 valid or PLL2 slip) */
while ((((getreg32(TMS570_SYS_CSVSTAT) & SYS_CLKSRC_PLL1) == 0u) &&
((getreg32(TMS570_ESM_SR1) & ESM_SR1_PLL1SLIP) == 0u)) ||
(((getreg32(TMS570_SYS_CSVSTAT) & SYS_CLKSRC_PLL2) == 0u) &&
((getreg32(TMS570_ESM_SR4) & ESM_SR4_PLL2SLIP) == 0u)))
{
/* Wait */
}
/* If PLL1 valid, check the frequency */
if ((getreg32(TMS570_ESM_SR1) & ESM_SR1_PLL1SLIP) != 0u)
{
failcode |= 1u;
}
else
{
failcode |= check_frequency(DCC1CNT1_CLKSRC_PLL1);
}
/* If PLL2 valid, check the frequency */
if ((getreg32(TMS570_ESM_SR4) & ESM_SR4_PLL2SLIP) != 0u)
{
failcode |= 2u;
}
else
{
failcode |= (check_frequency(DCC1CNT1_CLKSRC_PLL2) << 1U);
}
if (failcode == 0u)
{
break;
}
}
/* Disable plls */
regval = 0x00000002u | 0x00000040u;
putreg32(regval, TMS570_SYS_CSDISSET);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != regval)
{
}
/* Restore CLKCNTL, VCLKR and PENA first */
clkcntrlsave = getreg32(TMS570_SYS_CLKCNTL);
/* First set VCLK2 = HCLK */
regval = clkcntrlsave & 0x000f0100u;
putreg32(regval, TMS570_SYS_CLKCNTL);
putreg32(clkcntrlsave, TMS570_SYS_CLKCNTL);
return failcode;
}
/****************************************************************************
* Name: tms570_pll_setup
*
* Description:
* Configure PLL control registers. The PLL takes (127 + 1024 NR)
* oscillator cycles to acquire lock. This initialization sequence
* performs all the actions that are not required to be done at full
* application speed while the PLL locks.
*
****************************************************************************/
static void tms570_pll_setup(void)
{
uint32_t regval;
/* Configure PLL control registers */
/* Setup pll control register 1
*
* REFCLKDIV controls input clock divider:
*
* NR = REFCLKDIV+1
* Fintclk = Fclkin / NR
*
* PLLMUL controls multipler on divided input clock (Fintclk):
*
* Non-modulated:
* NF = (PLLMUL + 256) / 256
* Modulated:
* NF = (PLLMUL + MULMOD + 256) / 256
*
* Foutputclk = Fintclk x NF (150MHz - 550MHz)
*
* ODPLL controls internal PLL output divider:
*
* OD = ODPLL+1
* Fpostodclk = Foutputclock / OD
*
* Final divisor, R, controls PLL output:
*
* R = PLLDIV + 1
* Fpllclock = Fpostodclk / R
*
* Or:
*
* Fpllclock = = (Fclkin / NR) x NF / OD / R
*
* For example, if the clock source is a 16MHz crystal, then
*
* Fclkin = 16,000,000
* NR = 6 (REFCLKDIV=5)
* NF = 120 (PLLMUL = 119 * 256)
* OD = 1 (ODPLL = 0)
* R = 32 (PLLDIV=31)
*
* Then:
*
* Fintclk = 16 MHz / 6 = 2.667 MHz
* Foutputclock = 2.667 MHz * 120 = 320 MHz
* Fpostodclock = 320 MHz / 2 = 160 MHz
* Fpllclock = 160 MHz / 2 = 80 MHz
*
* NOTE: That R is temporary set to the maximum (32) here.
*/
/* Turn off PLL1 and PLL2 */
regval = SYS_CSDIS_CLKSRC_PLL1 | SYS_CSDIS_CLKSRC_PLL2;
putreg32(regval, TMS570_SYS_CSDISSET);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != regval)
{
}
/* Check for OSC failure */
regval = getreg32(TMS570_SYS_GLBSTAT);
if ((regval & SYS_GLBSTAT_OSC_ERR_MASK) == SYS_GLBSTAT_OSC_ERR_MASK)
{
regval = SYS_GHVSRC_GHVSRC_LPOHIGH | SYS_GHVSRC_HVLPM_LPOHIGH |
SYS_GHVSRC_GHVWAKE_LPOHIGH;
putreg32(regval, TMS570_SYS_GHVSRC);
regval = SYS_CSDIS_CLKSRC_PLL1 | SYS_CSDIS_CLKSRC_PLL2 |
SYS_CSDIS_CLKSRC_OSC;
putreg32(regval, TMS570_SYS_CSDISSET);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != regval)
{
}
putreg32(SYS_GLBSTAT_OSC_ERR_CLR, TMS570_SYS_GLBSTAT);
regval = SYS_CSDIS_CLKSRC_OSC;
putreg32(regval, TMS570_SYS_CSDISCLR);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != regval)
{
}
}
/* Setup pll control register 1 */
regval = SYS_PLLCTL1_PLLMUL((BOARD_PLL_NF - 1) << 8) |
SYS_PLLCTL1_REFCLKDIV(BOARD_PLL_NR - 1) |
SYS_PLLCTL1_PLLDIV_MAX |
(SYS_PLLCTL1_MASKSLIP_ENABLE);
putreg32(regval, TMS570_SYS_PLLCTL1);
/* Setup pll control register 2 */
regval = SYS_PLLCTL2_SPRAMOUNT(61) |
SYS_PLLCTL2_ODPLL(BOARD_PLL_OD - 1) |
SYS_PLLCTL2_MULMOD(7) |
SYS_PLLCTL2_SPRRATE(255);
putreg32(regval, TMS570_SYS_PLLCTL2);
/* Enable PLL(s) to start up or Lock.
*
* On wakeup, only clock sources 0, 4, and 5 are enabled: Oscillator, Low
* and high Frequency LPO. Clear bit 1 to enable the PLL. Only the
* external clock remains disabled.
*/
regval = SYS_CSDIS_CLKSRC_PLL1 | SYS_CSDIS_CLKSRC_PLL2;
putreg32(regval, TMS570_SYS_CSDISCLR);
while ((getreg32(TMS570_SYS_CSDIS) & regval) != 0)
{
}
}
/****************************************************************************
* Name: tms570_peripheral_initialize
*
* Description:
* Release peripherals from reset and enable clocks to all peripherals.
*
****************************************************************************/
static void tms570_peripheral_initialize(void)
{
uint32_t regval;
uint32_t clkcntl;
/* Disable Peripherals by clearing the PENA bit in the CLKCNTRL register
* before peripheral powerup
*/
clkcntl = getreg32(TMS570_SYS_CLKCNTL);
clkcntl &= ~SYS_CLKCNTL_PENA;
putreg32(clkcntl, TMS570_SYS_CLKCNTL);
/* Release peripherals from reset and enable clocks to all peripherals.
* Power-up all peripherals by clearing the power down bit for each
* quadrant of each peripheral.
*
* REVISIT: Should we only enable peripherals that are configured?
*/
regval = PCR_PSPWERDWN0_PS0_QALL | PCR_PSPWERDWN0_PS1_QALL |
PCR_PSPWERDWN0_PS2_QALL | PCR_PSPWERDWN0_PS3_QALL |
PCR_PSPWERDWN0_PS4_QALL | PCR_PSPWERDWN0_PS5_QALL |
PCR_PSPWERDWN0_PS6_QALL | PCR_PSPWERDWN0_PS7_QALL;
putreg32(regval, TMS570_PCR_PSPWRDWNCLR0);
regval = PCR_PSPWERDWN1_PS8_QALL | PCR_PSPWERDWN1_PS9_QALL |
PCR_PSPWERDWN1_PS10_QALL | PCR_PSPWERDWN1_PS11_QALL |
PCR_PSPWERDWN1_PS12_QALL | PCR_PSPWERDWN1_PS13_QALL |
PCR_PSPWERDWN1_PS14_QALL | PCR_PSPWERDWN1_PS15_QALL;
putreg32(regval, TMS570_PCR_PSPWRDWNCLR1);
regval = PCR_PSPWERDWN2_PS16_QALL | PCR_PSPWERDWN2_PS17_QALL |
PCR_PSPWERDWN2_PS18_QALL | PCR_PSPWERDWN2_PS19_QALL |
PCR_PSPWERDWN2_PS20_QALL | PCR_PSPWERDWN2_PS21_QALL |
PCR_PSPWERDWN2_PS22_QALL | PCR_PSPWERDWN2_PS23_QALL;
putreg32(regval, TMS570_PCR_PSPWRDWNCLR2);
regval = PCR_PSPWERDWN3_PS24_QALL | PCR_PSPWERDWN3_PS25_QALL |
PCR_PSPWERDWN3_PS26_QALL | PCR_PSPWERDWN3_PS27_QALL |
PCR_PSPWERDWN3_PS28_QALL | PCR_PSPWERDWN3_PS29_QALL |
PCR_PSPWERDWN3_PS30_QALL | PCR_PSPWERDWN3_PS31_QALL;
putreg32(regval, TMS570_PCR_PSPWRDWNCLR3);
/* Enable Peripherals */
clkcntl |= SYS_CLKCNTL_PENA;
putreg32(clkcntl, TMS570_SYS_CLKCNTL);
}
/****************************************************************************
* Name: tms570_pin_multiplex
*
* Description:
* Configure the field for a single pin in a PINMMR register
*
****************************************************************************/
static void tms570_pin_multiplex(const struct tms570_pinmux_s *pinmux)
{
uintptr_t regaddr;
uint32_t regval;
regaddr = TMS570_IOMM_PINMMR(pinmux->mmrndx);
regval = getreg32(regaddr);
regval &= ~(0xff << pinmux->shift);
regval |= ((uint32_t)(pinmux->value) << pinmux->shift);
putreg32(regval, regaddr);
}
/****************************************************************************
* Name: tms570_io_multiplex
*
* Description:
* Configure the all pins in the board-provided pinmux table.
*
****************************************************************************/
static void tms570_io_multiplex(void)
{
int i;
/* Enable access to pin multiplexing registers */
putreg32(IOMM_KICK0_UNLOCK, TMS570_IOMM_KICK0);
putreg32(IOMM_KICK1_UNLOCK, TMS570_IOMM_KICK1);
/* Configure each pin selected by the board-specific logic */
for (i = 0; i < NPINMUX; i++)
{
tms570_pin_multiplex(&g_pinmux_table[i]);
}
/* Disable access to pin multiplexing registers */
putreg32(IOMM_KICK0_LOCK, TMS570_IOMM_KICK0);
putreg32(IOMM_KICK1_LOCK, TMS570_IOMM_KICK1);
}
/****************************************************************************
* Name: tms570_lpo_trim
*
* Description:
* Configure the LPO such that HF LPO is as close to 10MHz as possible.
*
****************************************************************************/
static void tms570_lpo_trim(void)
{
uint32_t regval;
uint32_t lotrim;
/* The LPO trim value may be available in TI OTP */
lotrim = (getreg32(TMS570_TITCM_LPOTRIM) & TMS570_TITCM_LPOTRIM_MASK) >>
TMS570_TITCM_LPOTRIM_SHIFT;
/* Use if the LPO trim value TI OTP if programmed. Otherwise, use a
* default value.
*/
if (lotrim != 0xffff)
{
regval = SYS_LPOMONCTL_BIASENABLE | lotrim;
}
else
{
regval = SYS_LPOMONCTL_BIASENABLE |
SYS_LPOMONCTL_HFTRIM_100p00 |
SYS_LPOMONCTL_100p00;
}
putreg32(regval, TMS570_SYS_LPOMONCTL);
}
/****************************************************************************
* Name: tms570_flash_setup
*
* Description:
* Set up flash address and data wait states based on the target CPU clock
* frequency The number of address and data wait states for the target CPU
* clock frequency are specified in the specific part's datasheet.
*
****************************************************************************/
static void tms570_flash_setup(void)
{
uint32_t regval;
/* Setup flash read mode, address wait states and data wait states
*
* ENPIPE=1, Bit 0, Enable pipeline mode.
* ASWSTEN=0/1, Bit 1, Address Setup Wait State is enabled/disabled.
* RWAIT=BOARD_RWAIT, Bits 8-11, Wait states added to FLASH read access
*/
regval = FLASH_FRDCNTL_ENPIPE | FLASH_FRDCNTL_RWAIT(BOARD_RWAIT);
#if defined(BOARD_ASWAIT) && BOARD_ASWAIT > 0
regval |= FLASH_FRDCNTL_ASWSTEN;
#endif
putreg32(regval, TMS570_FLASH_FRDCNTL);
/* Setup flash access wait states for bank 7
*
* AUTOSTART_GRACE=2, Bits 0-7, Auto-suspend Startup Grace Period
* AUTOSUSPEN=0, Bit 8, Auto suspend is disabled.
* EWAIT=4, Bits 16-19, EEPROM wait states
*/
putreg32(FLASH_FSMWRENA_ENABLE, TMS570_FLASH_FSMWRENA);
regval = FLASH_EEPROMCFG_GRACE(2) | FLASH_EEPROMCFG_EWAIT(BOARD_EWAIT);
putreg32(regval, TMS570_FLASH_EEPROMCFG);
#if 0
putreg32(FLASH_FSMWRENA_DISABLE, TMS570_FLASH_FSMWRENA);
#endif
putreg32(0x0a, TMS570_FLASH_FSMWRENA);
/* Setup flash bank power modes */
regval = FLASH_FBFALLBACK_BANKPWR0_ACTIV |
FLASH_FBFALLBACK_BANKPWR1_ACTIV |
FLASH_FBFALLBACK_BANKPWR7_ACTIV;
putreg32(regval, TMS570_FLASH_FBFALLBACK);
}
/****************************************************************************
* Name: tms570_clocksrc_configure
*
* Description:
* Finalize PLL configuration, enable and configure clocks sources.
*
****************************************************************************/
static void tms570_clocksrc_configure(void)
{
uint32_t regval;
uint32_t csvstat;
uint32_t csdis;
/* Disable / Enable clock domains. Writing a '1' to the CDDIS register
* turns the clock off.
*
* GCLK Bit 0 On
* HCLK/VCLK_sys Bit 1 On
* VCLK_periph Bit 2 On
* VCLK2 Bit 3 On
* VCLKA1 Bit 4 On
* RTICLK1 Bit 6 On
* TCLK_EQEP Bit 9 On
*/
putreg32(0, TMS570_SYS_CDDISSET);
/* Work Around for Errata SYS#46: Errata Description: Clock Source
* Switching Not Qualified with Clock Source Enable And Clock Source Valid
* Workaround: Always check the CSDIS register to make sure the clock
* source is turned on and check the CSVSTAT register to make sure the
* clock source is valid. Then write to GHVSRC to switch the clock.
*/
do
{
/* Get the set of valid clocks */
csvstat = getreg32(TMS570_SYS_CSVSTAT);
/* Get the (inverted) state of each clock. Inverted so that '1' means
* ON not OFF.
*/
csdis = (getreg32(TMS570_SYS_CSDIS) ^ SYS_CSDIS_CLKSROFFALL) &
SYS_CSDIS_CLKSROFFALL;
}
while ((csvstat & csdis) != csdis);
regval = getreg32(TMS570_SYS_PLLCTL1);
regval &= ~SYS_PLLCTL1_PLLDIV_MASK;
regval |= SYS_PLLCTL1_PLLDIV(BOARD_PLL_R - 1);
putreg32(regval, TMS570_SYS_PLLCTL1);
/* Map device clock domains to desired sources and configure top-level
* dividers. All clock domains were working off the default clock sources
* until this point.
*
* Setup GCLK, HCLK and VCLK clock source for normal operation, power down
* mode and after wakeup
*/
regval = SYS_GHVSRC_GHVSRC_PLL1 | SYS_GHVSRC_HVLPM_PLL1 |
SYS_GHVSRC_GHVWAKE_PLL1;
putreg32(regval, TMS570_SYS_GHVSRC);
/* Setup RTICLK1 and RTICLK2 clocks */
regval = SYS_RCLKSRC_RTI1SRC_VCLK;
putreg32(regval, TMS570_SYS_RCLKSRC);
/* 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
*/
/* Setup asynchronous peripheral clock sources for AVCLK1 */
#if defined(CONFIG_ARCH_CHIP_TMS570LS3137ZWT)
regval = SYS_VCLKASRC_VCLKA2S_VCLK | SYS_VCLKASRC_VCLKA1S_VCLK;
#else
regval = SYS_VCLKASRC_VCLKA1S_VCLK;
#endif
putreg32(regval, TMS570_SYS_VCLKASRC);
#if defined(CONFIG_ARCH_CHIP_TMS570LS3137ZWT)
regval = SYS_VCLKASRC_VCLKA4S_VCLK | SYS_VCLKASRC_VCLKA3R_VCLK;
putreg32(regval, TMS570_SYS2_VCLKACON1);
#endif
/* Setup synchronous peripheral clock dividers for VCLK1, VCLK2, VCLK3 */
regval = getreg32(TMS570_SYS_CLKCNTL);
regval &= ~(SYS_CLKCNTL_VCLKR2_MASK);
regval |= SYS_CLKCNTL_VCLKR2;
putreg32(regval, TMS570_SYS_CLKCNTL);
regval = getreg32(TMS570_SYS_CLKCNTL);
regval &= ~(SYS_CLKCNTL_VCLKR_MASK);
regval |= SYS_CLKCNTL_VCLKR;
putreg32(regval, TMS570_SYS_CLKCNTL);
#if defined(CONFIG_ARCH_CHIP_TMS570LS3137ZWT)
regval = getreg32(TMS570_SYS2_CLK2CNTRL);
regval &= ~(SYS_CLKC2NTL_VCLK3R_MASK);
regval |= SYS_CLK2CNTL_VCLK3R_DIV2;
putreg32(regval, TMS570_SYS2_CLK2CNTRL);
#endif
}
/****************************************************************************
* Name: tms570_eclk_configure
*
* Description:
* Configure the External Clock (ECLK) pin.
*
****************************************************************************/
static void tms570_eclk_configure(void)
{
uint32_t regval;
/* Configure ECLK pins
*
* PC1 0=ECLK is in GIO mode
* PC4 0=ECLK pin is driven to logic low
* PC2 1=ECLK pin is an output
* PC7 0=CLK pin is configured in push/pull mode
* PC8 0=ECLK pull enable is active
* PC9 1=ECLK pull up is selected, when pull up/pull down logic is enabled
*/
putreg32(0, TMS570_SYS_PC1);
putreg32(0, TMS570_SYS_PC4);
putreg32(SYS_PC2_ECPCLKDIR, TMS570_SYS_PC2);
putreg32(0, TMS570_SYS_PC7);
putreg32(0, TMS570_SYS_PC8);
putreg32(SYS_PC9_ECPCLKPS, TMS570_SYS_PC9);
/* Setup ECLK:
*
* ECPDIV=7 Bits 0-15, ECP divider value = 8
* ECPINSEL=0 Bits 16-17, Select ECP input clock source is tied low
* ECPCOS=0 Bit 23, ECLK output is disabled in suspend mode
* ECPINSEL=0 Bit 24, VCLK is selected as the ECP clock source
*/
regval = SYS_ECPCNTL_ECPDIV(8 - 1) | SYS_ECPCNTL_ECPINSEL_LOW;
putreg32(regval, TMS570_SYS_ECPCNTL);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tms570_clockconfig
*
* Description:
* Called to initialize TMS570 clocking. This does whatever setup is
* needed to put the SoC in a usable state. This includes, but is not
* limited to, the initialization of clocking using the settings in the
* board.h header file.
*
****************************************************************************/
void tms570_clockconfig(void)
{
#ifdef CONFIG_TMS570_SELFTEST
int check;
#endif /* CONFIG_TMS570_SELFTEST */
/* Configure PLL control registers and enable PLLs. */
tms570_pll_setup();
#ifdef CONFIG_TMS570_SELFTEST
/* Run eFuse controller start-up checks and start eFuse controller ECC
* self-test.
*/
tms570_efc_selftest_start();
#endif /* CONFIG_TMS570_SELFTEST */
/* Enable clocks to peripherals and release peripheral reset */
tms570_peripheral_initialize();
/* Configure device-level multiplexing and I/O multiplexing */
tms570_io_multiplex();
#ifdef CONFIG_TMS570_SELFTEST
/* Wait for eFuse controller self-test to complete and check results */
check = tms570_efc_selftest_complete();
DEBUGASSERT(check == 0);
UNUSED(check);
#endif /* CONFIG_TMS570_SELFTEST */
/* Set up flash address and data wait states. */
tms570_flash_setup();
/* Configure the LPO such that HF LPO is as close to 10MHz as possible */
tms570_lpo_trim();
/* Finalize PLL configuration, enable and configure clocks sources. */
tms570_clocksrc_configure();
/* Configure ECLK */
tms570_eclk_configure();
}