2894 lines
77 KiB
C
2894 lines
77 KiB
C
/****************************************************************************
|
|
* arch/arm/src/s32k1xx/s32k1xx_clockconfig.c
|
|
*
|
|
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
*
|
|
* 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.
|
|
*
|
|
* Much of the logic within this file derives heavily from NXP sample code
|
|
* for the S32K1xx MCUs. That sample code has this licensing information:
|
|
*
|
|
* Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2018 NXP
|
|
* All rights reserved.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY NXP "AS IS" AND ANY EXPRESSED 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 NXP OR ITS 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 <debug.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/power/pm.h>
|
|
|
|
#include "arm_internal.h"
|
|
#include "hardware/s32k1xx_scg.h"
|
|
#include "hardware/s32k1xx_smc.h"
|
|
#include "hardware/s32k1xx_sim.h"
|
|
#include "hardware/s32k1xx_pmc.h"
|
|
#include "s32k1xx_periphclocks.h"
|
|
#include "s32k1xx_clockconfig.h"
|
|
#include "s32k1xx_start.h"
|
|
|
|
#include <arch/board/board.h> /* Include last. May have dependencies */
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* Temporary system clock source configurations. */
|
|
|
|
#define TMP_SIRC_CLK 0
|
|
#define TMP_FIRC_CLK 1
|
|
#define TMP_SOSC_CLK 2
|
|
#define TMP_SPLL_CLK 3
|
|
|
|
#define TMP_SYS_DIV 0
|
|
#define TMP_BUS_DIV 1
|
|
#define TMP_SLOW_DIV 2
|
|
|
|
#define TMP_SYS_CLK_NO 4
|
|
#define TMP_SYS_DIV_NO 3
|
|
|
|
/* Supports arrays of maximum clock frequencies of system clocks in all
|
|
* power modes
|
|
*/
|
|
|
|
#define MODES_MAX_NO 7
|
|
#define SYS_CLK_MAX_NO 3
|
|
#define CORE_CLK_INDEX 0
|
|
#define BUS_CLK_INDEX 1
|
|
#define SLOW_CLK_INDEX 2
|
|
|
|
/* Time to wait for clocks to stabilize, ie., number of cycles when core
|
|
* runs at maximum speed - 112 MHz.
|
|
*/
|
|
|
|
#define SIRC_STABILIZATION_TIMEOUT 100
|
|
#define FIRC_STABILIZATION_TIMEOUT 20
|
|
#define SOSC_STABILIZATION_TIMEOUT 3205000
|
|
#define SPLL_STABILIZATION_TIMEOUT 1000
|
|
|
|
/* System PLL reference clock after SCG_SPLLCFG[PREDIV] should be in the
|
|
* range of SCG_SPLL_REF_MIN to SCG_SPLL_REF_MAX.
|
|
*/
|
|
|
|
#define SCG_SPLL_REF_MIN 8000000
|
|
#define SCG_SPLL_REF_MAX 32000000
|
|
|
|
/* Power management definitions */
|
|
|
|
#ifndef OK
|
|
#define OK 0
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Function Declarations
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_PM
|
|
static void up_pm_notify(struct pm_callback_s *cb, int dowmin,
|
|
enum pm_state_e pmstate);
|
|
static int up_pm_prepare(struct pm_callback_s *cb, int domain,
|
|
enum pm_state_e pmstate);
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const uint8_t g_tmp_sysclk[TMP_SYS_CLK_NO][TMP_SYS_DIV_NO] =
|
|
{
|
|
{
|
|
1, /* SIRC SYS_CLK divider, range 1..16 */
|
|
1, /* SIRC BUS_CLK divider, range 1..16 */
|
|
2 /* SIRC SLOW_CLK divider, range 1..16 */
|
|
},
|
|
{
|
|
1, /* FIRC SYS_CLK divider, range 1..16 */
|
|
2, /* FIRC BUS_CLK divider, range 1..16 */
|
|
4 /* FIRC SLOW_CLK divider, range 1..16 */
|
|
},
|
|
{
|
|
1, /* SOSC SYS_CLK divider, range 1..16 */
|
|
2, /* SOSC BUS_CLK divider, range 1..16 */
|
|
2 /* SOSC SLOW_CLK divider, range 1..16 */
|
|
},
|
|
{
|
|
3, /* SPLL SYS_CLK divider, range 1..16 */
|
|
2, /* SPLL BUS_CLK divider, range 1..16 */
|
|
2 /* SPLL SLOW_CLK divider, range 1..16 */
|
|
}
|
|
};
|
|
|
|
/* The maximum clock frequencies of system clocks in all power modes */
|
|
|
|
/* SYS_CLK BUS_CLK SLOW_CLK */
|
|
|
|
static const uint32_t g_vlpr_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] =
|
|
{
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SOSC */
|
|
{ 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SIRC */
|
|
{ 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is FIRC */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SPLL */
|
|
};
|
|
|
|
/* SYS_CLK BUS_CLK SLOW_CLK */
|
|
|
|
static const uint32_t g_run_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] =
|
|
{
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is SOSC */
|
|
{ 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is SIRC */
|
|
{ 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is FIRC */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 80000000ul, 40000000ul, 26670000ul }, /* Maximum frequencies when system clock is SPLL */
|
|
};
|
|
#ifdef CONFIG_S32K1XX_HAVE_HSRUN
|
|
|
|
/* SYS_CLK BUS_CLK SLOW_CLK */
|
|
|
|
static const uint32_t g_hsrun_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] =
|
|
{
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SOSC */
|
|
{ 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SIRC */
|
|
{ 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is FIRC */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 0ul, 0ul, 0ul }, /* Invalid entry */
|
|
{ 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SPLL */
|
|
};
|
|
#endif
|
|
|
|
#if 0 /* Not currently used */
|
|
static uint32_t g_rtc_clkin; /* RTC CLKIN clock */
|
|
#endif
|
|
|
|
#if 0 /* Not currently used */
|
|
static uint32_t g_tclkfreq[NUMBER_OF_TCLK_INPUTS]; /* TCLKx clocks */
|
|
#endif
|
|
|
|
#ifdef CONFIG_PM
|
|
static struct pm_callback_s g_clock_pmcb =
|
|
{
|
|
.notify = up_pm_notify,
|
|
.prepare = up_pm_prepare,
|
|
};
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_scgclk_source
|
|
*
|
|
* Description:
|
|
* Gets SCG current system clock source
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The current system clock source.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline uint32_t s32k1xx_get_scgclk_source(void)
|
|
{
|
|
return ((getreg32(S32K1XX_SCG_CSR) & SCG_CSR_SCS_MASK) >>
|
|
SCG_CSR_SCS_SHIFT);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_soscfreq
|
|
*
|
|
* Description:
|
|
* Gets SCG System OSC clock frequency (SOSC).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The SOSC frequency. Zero is returned if the SOSC is invalid.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t s32k1xx_get_soscfreq(void)
|
|
{
|
|
/* Check if the SOSC is valid */
|
|
|
|
if ((getreg32(S32K1XX_SCG_SOSCCSR) & SCG_SOSCCSR_SOSCVLD) != 0)
|
|
{
|
|
return BOARD_XTAL_FREQUENCY;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_sircfreq
|
|
*
|
|
* Description:
|
|
* Gets SCG Slow IRC clock frequency (SIRC).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The SIRC frequency. Zero is returned if the SIRC is invalid.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t s32k1xx_get_sircfreq(void)
|
|
{
|
|
/* Check if the SIRC is valid */
|
|
|
|
if ((getreg32(S32K1XX_SCG_SIRCCSR) & SCG_SIRCCSR_SIRCVLD) != 0)
|
|
{
|
|
/* Only high range is supported */
|
|
|
|
if ((getreg32(S32K1XX_SCG_SIRCCFG) & SCG_SIRCCFG_RANGE) != 0)
|
|
{
|
|
return SCG_SIRC_HIGHRANGE_FREQUENCY;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_fircfreq
|
|
*
|
|
* Description:
|
|
* Gets SCG Fast IRC clock frequency (FIRC).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The FIRC frequency. Zero is returned if the FIRC is invalid.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t s32k1xx_get_fircfreq(void)
|
|
{
|
|
/* Check if the FIRC is valid */
|
|
|
|
if ((getreg32(S32K1XX_SCG_FIRCCSR) & SCG_FIRCCSR_FIRCVLD) != 0)
|
|
{
|
|
return SCG_FIRC_FREQUENCY0;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_spllfreq
|
|
*
|
|
* Description:
|
|
* Gets SCG System PLL clock frequency (SPLL).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The SPLL frequency. Zero is returned if the SPLL is invalid.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
static uint32_t s32k1xx_get_spllfreq(void)
|
|
{
|
|
uint32_t freq;
|
|
uint32_t regval;
|
|
uint32_t prediv;
|
|
uint32_t mult;
|
|
|
|
/* Check if the SPLL is valid */
|
|
|
|
if ((getreg32(S32K1XX_SCG_SPLLCSR) & SCG_SPLLCSR_SPLLVLD) != 0)
|
|
{
|
|
/* Get System Oscillator frequency. */
|
|
|
|
freq = s32k1xx_get_soscfreq();
|
|
if (freq != 0)
|
|
{
|
|
regval = getreg32(S32K1XX_SCG_SPLLCFG);
|
|
prediv = ((regval & SCG_SPLLCFG_PREDIV_MASK) >>
|
|
SCG_SPLLCFG_PREDIV_SHIFT) + 1;
|
|
mult = ((regval & SCG_SPLLCFG_MULT_MASK) >>
|
|
SCG_SPLLCFG_MULT_SHIFT) + 16;
|
|
|
|
freq /= prediv;
|
|
freq *= mult;
|
|
freq >>= 1; /* Divide VCO by 2. */
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_srcfreq
|
|
*
|
|
* Description:
|
|
* Return the clock source frequency.
|
|
*
|
|
* Input Parameters:
|
|
* src - Identities the clock source
|
|
*
|
|
* Returned Values:
|
|
* The requested clock source frequency. Zero is returned on any error.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t s32k1xx_get_srcfreq(enum scg_system_clock_src_e src)
|
|
{
|
|
uint32_t srcfreq = 0;
|
|
|
|
switch (src)
|
|
{
|
|
case SCG_SYSTEM_CLOCK_SRC_SYS_OSC:
|
|
srcfreq = s32k1xx_get_soscfreq();
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_SRC_SIRC:
|
|
srcfreq = s32k1xx_get_sircfreq();
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_SRC_FIRC:
|
|
srcfreq = s32k1xx_get_fircfreq();
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
case SCG_SYSTEM_CLOCK_SRC_SYS_PLL:
|
|
srcfreq = s32k1xx_get_spllfreq();
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return srcfreq;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_set_sysclk_cfg
|
|
*
|
|
* Description:
|
|
* This function sets the system configuration for the specified mode.
|
|
*
|
|
* Input Parameters:
|
|
* mode -
|
|
* config -
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int
|
|
s32k1xx_set_sysclk_cfg(enum scg_system_clock_mode_e mode,
|
|
const struct scg_system_clock_config_s *config)
|
|
{
|
|
uint32_t srcfreq = 0;
|
|
uint32_t sysfreq_mul = (uint32_t)config->divcore;
|
|
uint32_t busfreq_mul = (uint32_t)config->divcore *
|
|
(uint32_t)config->divbus;
|
|
uint32_t slowfreq_mul = (uint32_t)config->divcore *
|
|
(uint32_t)config->divslow;
|
|
uint32_t regval;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(mode != SCG_SYSTEM_CLOCK_MODE_CURRENT);
|
|
|
|
srcfreq = s32k1xx_get_srcfreq(config->src) >> 4;
|
|
|
|
switch (mode)
|
|
{
|
|
case SCG_SYSTEM_CLOCK_MODE_RUN: /* Run mode */
|
|
|
|
/* Verify the frequencies of sys, bus and slow clocks. */
|
|
|
|
if ((srcfreq > (sysfreq_mul *
|
|
(g_run_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (busfreq_mul *
|
|
(g_run_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (slowfreq_mul *
|
|
(g_run_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >>
|
|
4))))
|
|
{
|
|
/* Configuration for the next system clock source is not
|
|
* valid.
|
|
*/
|
|
|
|
ret = -EINVAL;
|
|
}
|
|
else
|
|
{
|
|
regval = (((uint32_t)config->src << SCG_RCCR_SCS_SHIFT) |
|
|
SCG_RCCR_DIVCORE(config->divcore) |
|
|
SCG_RCCR_DIVBUS(config->divbus) |
|
|
SCG_RCCR_DIVSLOW(config->divslow));
|
|
putreg32(regval, S32K1XX_SCG_RCCR);
|
|
}
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_MODE_VLPR: /* Very Low Power Run mode */
|
|
DEBUGASSERT(SCG_SYSTEM_CLOCK_SRC_SIRC == config->src);
|
|
|
|
/* Verify the frequencies of sys, bus and slow clocks. */
|
|
|
|
if ((srcfreq > (sysfreq_mul *
|
|
(g_vlpr_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (busfreq_mul *
|
|
(g_vlpr_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (slowfreq_mul *
|
|
(g_vlpr_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >>
|
|
4))))
|
|
{
|
|
/* Configuration for the next system clock source is not
|
|
* valid.
|
|
*/
|
|
|
|
ret = -EINVAL;
|
|
}
|
|
else
|
|
{
|
|
regval = (((uint32_t)config->src << SCG_VCCR_SCS_SHIFT) |
|
|
SCG_VCCR_DIVCORE(config->divcore) |
|
|
SCG_VCCR_DIVBUS(config->divbus) |
|
|
SCG_VCCR_DIVSLOW(config->divslow));
|
|
putreg32(regval, S32K1XX_SCG_VCCR);
|
|
}
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_HSRUN
|
|
case SCG_SYSTEM_CLOCK_MODE_HSRUN: /* High Speed Run mode. */
|
|
DEBUGASSERT(SCG_SYSTEM_CLOCK_SRC_FIRC == config->src ||
|
|
SCG_SYSTEM_CLOCK_SRC_SYS_PLL == config->src);
|
|
|
|
/* Verify the frequencies of sys, bus and slow clocks. */
|
|
|
|
if ((srcfreq > (sysfreq_mul *
|
|
(g_hsrun_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (busfreq_mul *
|
|
(g_hsrun_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >>
|
|
4))) ||
|
|
(srcfreq > (slowfreq_mul *
|
|
(g_hsrun_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >>
|
|
4))))
|
|
{
|
|
/* Configuration for the next system clock source is not
|
|
* valid.
|
|
*/
|
|
|
|
ret = -EINVAL;
|
|
}
|
|
else
|
|
{
|
|
regval = (((uint32_t)config->src << SCG_HCCR_SCS_SHIFT) |
|
|
SCG_HCCR_DIVCORE(config->divcore) |
|
|
SCG_HCCR_DIVBUS(config->divbus) |
|
|
SCG_HCCR_DIVSLOW(config->divslow));
|
|
putreg32(regval, S32K1XX_SCG_HCCR);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
|
|
/* Invalid mode */
|
|
|
|
DEBUGPANIC();
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_transition_systemclock
|
|
*
|
|
* Description:
|
|
* Transition to a new system clock.
|
|
*
|
|
* Input Parameters:
|
|
* cfg - Describes the new system clock configuration
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int
|
|
s32k1xx_transition_systemclock(const struct scg_system_clock_config_s *cfg)
|
|
{
|
|
enum scg_system_clock_mode_e run_mode;
|
|
uint32_t timeout;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(cfg != NULL && cfg->src != SCG_SYSTEM_CLOCK_SRC_NONE);
|
|
|
|
/* Get and convert Run mode from SMC to SCG defines */
|
|
|
|
run_mode = s32k1xx_get_runmode();
|
|
|
|
/* Check the current mode */
|
|
|
|
DEBUGASSERT(run_mode != SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
/* Update run mode configuration */
|
|
|
|
ret = s32k1xx_set_sysclk_cfg(run_mode, cfg);
|
|
if (ret == OK)
|
|
{
|
|
/* Wait for system clock to transition.
|
|
*
|
|
* e10777: The SCG_RCCR[SCS] and SCG_HCCR[SCS] may have a corrupted
|
|
* status during the interval when the system clock is switching.
|
|
* Workaround: The SCS field should be read twice by the software to
|
|
* ensure the system clock switch has completed.
|
|
*/
|
|
|
|
#if 1 /* Errata E10777 */
|
|
timeout = 10;
|
|
#else
|
|
timeout = 1;
|
|
#endif
|
|
|
|
do
|
|
{
|
|
timeout--;
|
|
}
|
|
while (s32k1xx_get_scgclk_source() != cfg->src && timeout > 0);
|
|
|
|
if (timeout == 0)
|
|
{
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_firc_config
|
|
*
|
|
* Description:
|
|
* Configures FIRC module based on provided configuration.
|
|
*
|
|
* Input Parameters:
|
|
* firccfg - Describes the desired FORC configuration.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_firc_config(bool enable,
|
|
const struct scg_firc_config_s *firccfg)
|
|
{
|
|
uint32_t regval;
|
|
int32_t timeout;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(firccfg != NULL);
|
|
|
|
/* If clock is used by system, return error. */
|
|
|
|
regval = getreg32(S32K1XX_SCG_FIRCCSR);
|
|
if ((regval & SCG_FIRCCSR_FIRCSEL) != 0)
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
|
|
/* Disable the FIRC */
|
|
|
|
else
|
|
{
|
|
/* Clear LK bit field */
|
|
|
|
regval &= ~SCG_FIRCCSR_LK;
|
|
putreg32(regval, S32K1XX_SCG_FIRCCSR);
|
|
|
|
/* Disable monitor, disable clock and clear error. */
|
|
|
|
putreg32(SCG_FIRCCSR_FIRCERR, S32K1XX_SCG_FIRCCSR);
|
|
}
|
|
|
|
/* Configure FIRC. */
|
|
|
|
if (enable && (ret == OK))
|
|
{
|
|
/* Now start to set up FIRC clock. */
|
|
|
|
/* Step 1. Setup dividers. */
|
|
|
|
regval = SCG_FIRCDIV_FIRCDIV1(firccfg->div1) |
|
|
SCG_FIRCDIV_FIRCDIV2(firccfg->div2);
|
|
putreg32(regval, S32K1XX_SCG_FIRCDIV);
|
|
|
|
/* Step 2. Set FIRC configuration. */
|
|
|
|
if (firccfg->range == 0)
|
|
{
|
|
regval = 0;
|
|
}
|
|
else
|
|
{
|
|
regval = SCG_FIRCCFG_48MHZ; /* REVISIT: Also zero */
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SCG_FIRCCFG);
|
|
|
|
/* Step 3. Enable clock, config regulator and locking feature. */
|
|
|
|
regval = SCG_FIRCCSR_FIRCEN;
|
|
|
|
if (!firccfg->regulator)
|
|
{
|
|
regval |= SCG_FIRCCSR_FIRCREGOFF;
|
|
}
|
|
|
|
if (firccfg->locked)
|
|
{
|
|
regval |= SCG_FIRCCSR_LK;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SCG_FIRCCSR);
|
|
|
|
/* Wait for FIRC to initialize */
|
|
|
|
for (timeout = FIRC_STABILIZATION_TIMEOUT;
|
|
s32k1xx_get_fircfreq() == 0 && timeout > 0;
|
|
timeout--)
|
|
{
|
|
}
|
|
|
|
if (timeout <= 0)
|
|
{
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_firc_clocksource
|
|
*
|
|
* Description:
|
|
* Configure to the FIRC clock source.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_firc_clocksource(void)
|
|
{
|
|
struct scg_system_clock_config_s firccfg;
|
|
int ret = OK;
|
|
|
|
/* If the current system clock source is not FIRC:
|
|
* 1. Enable FIRC (if it's not enabled)
|
|
* 2. Switch to FIRC.
|
|
*/
|
|
|
|
if (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_FIRC)
|
|
{
|
|
/* If FIRC is not on, then FIRC is configured with the default
|
|
* configuration
|
|
*/
|
|
|
|
if (s32k1xx_get_fircfreq() == 0)
|
|
{
|
|
ret = s32k1xx_firc_config(true, NULL);
|
|
}
|
|
|
|
/* FIRC is enabled, transition the system clock source to FIRC. */
|
|
|
|
if (ret == OK)
|
|
{
|
|
firccfg.src = SCG_SYSTEM_CLOCK_SRC_FIRC;
|
|
firccfg.divcore = g_tmp_sysclk[TMP_FIRC_CLK][TMP_SYS_DIV];
|
|
firccfg.divbus = g_tmp_sysclk[TMP_FIRC_CLK][TMP_BUS_DIV];
|
|
firccfg.divslow = g_tmp_sysclk[TMP_FIRC_CLK][TMP_SLOW_DIV];
|
|
ret = s32k1xx_transition_systemclock(&firccfg);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_sirc_config
|
|
*
|
|
* Description:
|
|
* Configures SIRC module based on provided configuration.
|
|
*
|
|
* Input Parameters:
|
|
* sirccfg - Describes the desired SIRC configuration.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_sirc_config(bool enable,
|
|
const struct scg_sirc_config_s *sirccfg)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t timeout;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(sirccfg != NULL);
|
|
|
|
/* If clock is used by system, return error. */
|
|
|
|
regval = getreg32(S32K1XX_SCG_SIRCCSR);
|
|
if ((regval & SCG_SIRCCSR_SIRCSEL) != 0)
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
|
|
/* Disable SIRC */
|
|
|
|
else
|
|
{
|
|
/* Clear LK bit field */
|
|
|
|
regval &= ~SCG_SIRCCSR_LK;
|
|
putreg32(regval, S32K1XX_SCG_SIRCCSR);
|
|
|
|
/* Disable monitor, disable clock and clear error. */
|
|
|
|
putreg32(0, S32K1XX_SCG_SIRCCSR);
|
|
}
|
|
|
|
/* Configure SIRC. */
|
|
|
|
if (enable && (ret == OK))
|
|
{
|
|
/* Now start to set up SIRC clock. */
|
|
|
|
/* Step 1. Setup dividers. */
|
|
|
|
regval = SCG_SIRCDIV_SIRCDIV1(sirccfg->div1) |
|
|
SCG_SIRCDIV_SIRCDIV2(sirccfg->div2);
|
|
putreg32(regval, S32K1XX_SCG_SIRCDIV);
|
|
|
|
/* Step 2. Set SIRC configuration: frequency range. */
|
|
|
|
if (sirccfg->range == SCG_SIRC_RANGE_HIGH)
|
|
{
|
|
regval = SCG_SIRCCFG_HIGHRANGE;
|
|
}
|
|
else
|
|
{
|
|
regval = SCG_SIRCCFG_LOWRANGE;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SCG_SIRCCFG);
|
|
|
|
/* Step 3. Set SIRC control: enable clock, configure source in STOP
|
|
* and VLP modes, configure lock feature.
|
|
*/
|
|
|
|
regval = SCG_SIRCCSR_SIRCEN;
|
|
|
|
if (sirccfg->stopmode)
|
|
{
|
|
regval |= SCG_SIRCCSR_SIRCSTEN;
|
|
}
|
|
|
|
if (sirccfg->lowpower)
|
|
{
|
|
regval |= SCG_SIRCCSR_SIRCLPEN;
|
|
}
|
|
|
|
if (sirccfg->locked)
|
|
{
|
|
regval |= SCG_SIRCCSR_LK;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SCG_SIRCCSR);
|
|
|
|
/* Wait for SIRC to initialize */
|
|
|
|
for (timeout = SIRC_STABILIZATION_TIMEOUT;
|
|
s32k1xx_get_sircfreq() == 0 && timeout > 0;
|
|
timeout--)
|
|
{
|
|
}
|
|
|
|
if (timeout <= 0)
|
|
{
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(CONFIG_VLPR_STANDBY) || defined(CONFIG_VLPR_SLEEP)
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_sirc_clocksource
|
|
*
|
|
* Description:
|
|
* Configure to the SIRC clock source.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_sirc_clocksource(void)
|
|
{
|
|
struct scg_system_clock_config_s sirccfg;
|
|
int ret = OK;
|
|
|
|
/* If the current system clock source is not SIRC:
|
|
* 1. Enable SIRC (if it's not enabled)
|
|
* 2. Switch to SIRC.
|
|
*/
|
|
|
|
if (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC)
|
|
{
|
|
/* If SIRC is not on, then SIRC is configured with the default
|
|
* configuration
|
|
*/
|
|
|
|
if (s32k1xx_get_sircfreq() == 0)
|
|
{
|
|
ret = s32k1xx_sirc_config(true, NULL);
|
|
}
|
|
|
|
/* SIRC is enabled, transition the system clock source to SIRC. */
|
|
|
|
if (ret == OK)
|
|
{
|
|
sirccfg.src = SCG_SYSTEM_CLOCK_SRC_SIRC;
|
|
sirccfg.divcore = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SYS_DIV];
|
|
sirccfg.divbus = g_tmp_sysclk[TMP_SIRC_CLK][TMP_BUS_DIV];
|
|
sirccfg.divslow = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SLOW_DIV];
|
|
ret = s32k1xx_transition_systemclock(&sirccfg);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_sosc_config
|
|
*
|
|
* Description:
|
|
* CConfigures SOSC module based on provided configuration.
|
|
*
|
|
* Input Parameters:
|
|
* sosccfg - Describes the desired SOSC configuration.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_sosc_config(bool enable,
|
|
const struct scg_sosc_config_s *sosccfg)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t timeout;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(sosccfg != NULL);
|
|
|
|
/* If clock is used by system, return error. */
|
|
|
|
regval = getreg32(S32K1XX_SCG_SOSCCSR);
|
|
if ((regval & SCG_SOSCCSR_SOSCSEL) != 0)
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
|
|
/* Disable SOSC */
|
|
|
|
else
|
|
{
|
|
/* Clear LK bit field */
|
|
|
|
regval &= ~SCG_SOSCCSR_LK;
|
|
putreg32(regval, S32K1XX_SCG_SOSCCSR);
|
|
|
|
/* Disable monitor, disable clock and clear error. */
|
|
|
|
putreg32(SCG_SOSCCSR_SOSCERR, S32K1XX_SCG_SOSCCSR);
|
|
}
|
|
|
|
/* Configure the SOSC */
|
|
|
|
if (enable && (ret == OK))
|
|
{
|
|
/* Now start to set up OSC clock */
|
|
|
|
/* Step 1. Setup dividers. */
|
|
|
|
regval = SCG_SOSCDIV_SOSCDIV1(sosccfg->div1) |
|
|
SCG_SOSCDIV_SOSCDIV2(sosccfg->div2);
|
|
putreg32(regval, S32K1XX_SCG_SOSCDIV);
|
|
|
|
/* Step 2. Set OSC configuration. */
|
|
|
|
regval = SCG_SOSCCFG_RANGE(sosccfg->range);
|
|
|
|
if (sosccfg->gain == SCG_SOSC_GAIN_HIGH)
|
|
{
|
|
regval |= SCG_SOSCCFG_HGO;
|
|
}
|
|
|
|
if (sosccfg->extref == SCG_SOSC_REF_OSC)
|
|
{
|
|
regval |= SCG_SOSCCFG_EREFS;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SCG_SOSCCFG);
|
|
|
|
/* Step 3. Enable clock, configure monitor, lock register. */
|
|
|
|
regval = SCG_SOSCCSR_SOSCEN;
|
|
|
|
if (sosccfg->locked)
|
|
{
|
|
regval |= SCG_SOSCCSR_LK;
|
|
}
|
|
|
|
switch (sosccfg->mode)
|
|
{
|
|
case SCG_SOSC_MONITOR_DISABLE:
|
|
{
|
|
putreg32(regval, S32K1XX_SCG_SOSCCSR);
|
|
}
|
|
break;
|
|
|
|
case SCG_SOSC_MONITOR_INT:
|
|
{
|
|
regval |= SCG_SOSCCSR_SOSCCM;
|
|
putreg32(regval, S32K1XX_SCG_SOSCCSR);
|
|
}
|
|
break;
|
|
|
|
case SCG_SOSC_MONITOR_RESET:
|
|
{
|
|
regval |= SCG_SOSCCSR_SOSCCM | SCG_SOSCCSR_SOSCCMRE;
|
|
putreg32(regval, S32K1XX_SCG_SOSCCSR);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid monitor mode */
|
|
|
|
DEBUGPANIC();
|
|
break;
|
|
}
|
|
|
|
/* Wait for System OSC to initialize */
|
|
|
|
for (timeout = SOSC_STABILIZATION_TIMEOUT;
|
|
s32k1xx_get_soscfreq() == 0 && timeout > 0;
|
|
timeout--)
|
|
{
|
|
}
|
|
|
|
if (timeout <= 0)
|
|
{
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_spll_config
|
|
*
|
|
* Description:
|
|
* Configures SPLL module based on provided configuration.
|
|
*
|
|
* Input Parameters:
|
|
* spllccfg - Describes the desired SPLL configuration.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
static int s32k1xx_spll_config(bool enable,
|
|
const struct scg_spll_config_s *spllcfg)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t srcfreq;
|
|
uint32_t timeout;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(spllcfg != NULL);
|
|
|
|
/* If clock is used by system, return error. */
|
|
|
|
regval = getreg32(S32K1XX_SCG_SPLLCSR);
|
|
if ((regval & SCG_SPLLCSR_SPLLSEL) != 0)
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
|
|
/* Disable the SPLL. */
|
|
|
|
else
|
|
{
|
|
/* Clear LK bit field */
|
|
|
|
regval &= ~SCG_SPLLCSR_LK;
|
|
putreg32(regval, S32K1XX_SCG_SPLLCSR);
|
|
|
|
/* Disable monitor, disable clock and clear error. */
|
|
|
|
putreg32(SCG_SPLLCSR_SPLLERR, S32K1XX_SCG_SPLLCSR);
|
|
}
|
|
|
|
/* Configure SPLL */
|
|
|
|
if (enable && (ret == OK))
|
|
{
|
|
/* Get clock source frequency. */
|
|
|
|
srcfreq = s32k1xx_get_soscfreq();
|
|
DEBUGASSERT(srcfreq != 0);
|
|
|
|
/* Pre-divider checking. */
|
|
|
|
srcfreq /= spllcfg->prediv;
|
|
DEBUGASSERT(srcfreq >= SCG_SPLL_REF_MIN &&
|
|
srcfreq <= SCG_SPLL_REF_MAX);
|
|
|
|
/* Now start to set up PLL clock. */
|
|
|
|
regval = SCG_SPLLDIV_SPLLDIV1(spllcfg->div1) |
|
|
SCG_SPLLDIV_SPLLDIV2(spllcfg->div2);
|
|
putreg32(regval, S32K1XX_SCG_SPLLDIV);
|
|
|
|
/* Step 2. Set PLL configuration. */
|
|
|
|
regval = SCG_SPLLCFG_PREDIV(spllcfg->prediv) |
|
|
SCG_SPLLCFG_MULT(spllcfg->mult);
|
|
putreg32(regval, S32K1XX_SCG_SPLLCFG);
|
|
|
|
/* Step 3.
|
|
* Enable clock, configure monitor, lock register.
|
|
*/
|
|
|
|
regval = SCG_SPLLCSR_SPLLEN;
|
|
|
|
if (spllcfg->locked)
|
|
{
|
|
regval |= SCG_SPLLCSR_LK;
|
|
}
|
|
|
|
switch (spllcfg->mode)
|
|
{
|
|
case SCG_SPLL_MONITOR_DISABLE:
|
|
{
|
|
putreg32(regval, S32K1XX_SCG_SPLLCSR);
|
|
}
|
|
break;
|
|
|
|
case SCG_SPLL_MONITOR_INT:
|
|
{
|
|
regval |= SCG_SPLLCSR_SPLLCM;
|
|
putreg32(regval, S32K1XX_SCG_SPLLCSR);
|
|
}
|
|
break;
|
|
|
|
case SCG_SPLL_MONITOR_RESET:
|
|
{
|
|
regval |= (SCG_SPLLCSR_SPLLCM | SCG_SPLLCSR_SPLLCMRE);
|
|
putreg32(regval, S32K1XX_SCG_SPLLCSR);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid monitor mode */
|
|
|
|
DEBUGPANIC();
|
|
break;
|
|
}
|
|
|
|
/* Wait for System PLL to initialize */
|
|
|
|
for (timeout = SPLL_STABILIZATION_TIMEOUT;
|
|
s32k1xx_get_spllfreq() == 0 && timeout > 0;
|
|
timeout--)
|
|
{
|
|
}
|
|
|
|
if (timeout <= 0)
|
|
{
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_configure_scgmodules
|
|
*
|
|
* Description:
|
|
* Configures all modules from SCG (SIRC, FIRC, SOSC and SPLL)
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_configure_scgmodules(const struct scg_config_s *scgcfg)
|
|
{
|
|
struct scg_system_clock_config_s sysclkcfg;
|
|
const struct scg_system_clock_config_s *next;
|
|
int ret = OK;
|
|
|
|
/* Configure all clock sources that are different from the current system
|
|
* clock source FIRC (SIRC, SOSC, SPLL).
|
|
*/
|
|
|
|
ret = s32k1xx_sirc_config(scgcfg->sirc.initialize, &scgcfg->sirc);
|
|
if (ret == OK)
|
|
{
|
|
ret = s32k1xx_sosc_config(scgcfg->sosc.initialize, &scgcfg->sosc);
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
if (ret == OK)
|
|
{
|
|
ret = s32k1xx_spll_config(scgcfg->spll.initialize, &scgcfg->spll);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Get the next system clock source */
|
|
|
|
switch (s32k1xx_get_runmode())
|
|
{
|
|
case SCG_SYSTEM_CLOCK_MODE_RUN:
|
|
{
|
|
next = &scgcfg->clockmode.rccr;
|
|
}
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_MODE_VLPR:
|
|
{
|
|
next = &scgcfg->clockmode.vccr;
|
|
}
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_HSRUN
|
|
case SCG_SYSTEM_CLOCK_MODE_HSRUN:
|
|
{
|
|
next = &scgcfg->clockmode.hccr;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
DEBUGPANIC();
|
|
next = NULL;
|
|
break;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* The current system clock source is FIRC. Verify whether the next
|
|
* system clock source is FIRC.
|
|
*/
|
|
|
|
if (next->src == SCG_SYSTEM_CLOCK_SRC_FIRC)
|
|
{
|
|
/* If they are the same, search for a temporary system clock source
|
|
* (use one of the following sources: SPLL, SOSC, SIRC). Assume
|
|
* that a temporary clock is not found ret = -ENOENT.
|
|
*/
|
|
|
|
ret = -ENOENT;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
/* SPLL is enabled */
|
|
|
|
if (scgcfg->spll.initialize && (ret == -ENOENT))
|
|
{
|
|
sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SYS_PLL;
|
|
sysclkcfg.divcore = g_tmp_sysclk[TMP_SPLL_CLK][TMP_SYS_DIV];
|
|
sysclkcfg.divbus = g_tmp_sysclk[TMP_SPLL_CLK][TMP_BUS_DIV];
|
|
sysclkcfg.divslow = g_tmp_sysclk[TMP_SPLL_CLK][TMP_SLOW_DIV];
|
|
ret = s32k1xx_transition_systemclock(&sysclkcfg);
|
|
}
|
|
#endif
|
|
|
|
/* SOSC is enabled and SPLL configuration for system clock source
|
|
* is not valid
|
|
*/
|
|
|
|
if (scgcfg->sosc.initialize && (ret == -ENOENT))
|
|
{
|
|
sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SYS_OSC;
|
|
sysclkcfg.divcore = g_tmp_sysclk[TMP_SOSC_CLK][TMP_SYS_DIV];
|
|
sysclkcfg.divbus = g_tmp_sysclk[TMP_SOSC_CLK][TMP_BUS_DIV];
|
|
sysclkcfg.divslow = g_tmp_sysclk[TMP_SOSC_CLK][TMP_SLOW_DIV];
|
|
ret = s32k1xx_transition_systemclock(&sysclkcfg);
|
|
}
|
|
|
|
/* SIRC is enabled and SOSC configuration for system clock
|
|
* source is not valid
|
|
*/
|
|
|
|
if (scgcfg->sirc.initialize && (ret == -ENOENT))
|
|
{
|
|
sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SIRC;
|
|
sysclkcfg.divcore = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SYS_DIV];
|
|
sysclkcfg.divbus = g_tmp_sysclk[TMP_SIRC_CLK][TMP_BUS_DIV];
|
|
sysclkcfg.divslow = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SLOW_DIV];
|
|
ret = s32k1xx_transition_systemclock(&sysclkcfg);
|
|
}
|
|
|
|
/* Transitioned to a temporary system clock source. */
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Configure the remaining clock source (FIRC). */
|
|
|
|
ret = s32k1xx_firc_config(scgcfg->firc.initialize,
|
|
&scgcfg->firc);
|
|
if (ret == OK)
|
|
{
|
|
/* Transition to the next system clock source. */
|
|
|
|
sysclkcfg.src = next->src;
|
|
sysclkcfg.divcore = next->divcore;
|
|
sysclkcfg.divbus = next->divbus;
|
|
sysclkcfg.divslow = next->divslow;
|
|
ret = s32k1xx_transition_systemclock(&sysclkcfg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Transition to the next system clock source. */
|
|
|
|
sysclkcfg.src = next->src;
|
|
sysclkcfg.divcore = next->divcore;
|
|
sysclkcfg.divbus = next->divbus;
|
|
sysclkcfg.divslow = next->divslow;
|
|
ret = s32k1xx_transition_systemclock(&sysclkcfg);
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Configure the remaining clock source (FIRC) */
|
|
|
|
ret = s32k1xx_firc_config(scgcfg->firc.initialize,
|
|
&scgcfg->firc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_scg_config
|
|
*
|
|
* Description:
|
|
* Configure SCG clocking.
|
|
*
|
|
* Input Parameters:
|
|
* scgcfg - Describes the new SCG clock configuration
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_scg_config(const struct scg_config_s *scgcfg)
|
|
{
|
|
uint32_t regval;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(scgcfg != NULL);
|
|
|
|
/* Configure a temporary system clock source: FIRC if enabled */
|
|
|
|
ret = s32k1xx_firc_clocksource();
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Configure clock sources from SCG */
|
|
|
|
ret = s32k1xx_configure_scgmodules(scgcfg);
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Configure RTC. */
|
|
|
|
#if 0 /* Not used */
|
|
if (scgcfg->rtc.initialize)
|
|
{
|
|
/* RTC Clock settings. */
|
|
|
|
g_rtc_clkin = scgcfg->rtc.clkin;
|
|
}
|
|
#endif
|
|
|
|
/* Configure SCG ClockOut. */
|
|
|
|
if (scgcfg->clockout.initialize)
|
|
{
|
|
/* ClockOut settings. */
|
|
|
|
regval = getreg32(S32K1XX_SCG_CLKOUTCNFG);
|
|
regval &= ~SCG_CLKOUTCNFG_CLKOUTSEL_MASK;
|
|
regval |= SCG_CLKOUTCNFG_CLKOUTSEL(scgcfg->clockout.source);
|
|
putreg32(regval, S32K1XX_SCG_CLKOUTCNFG);
|
|
}
|
|
|
|
/* Configure SCG clock modes. */
|
|
|
|
if (scgcfg->clockmode.initialize)
|
|
{
|
|
/* Configure SCG clock modes */
|
|
|
|
ret = s32k1xx_set_sysclk_cfg(SCG_SYSTEM_CLOCK_MODE_RUN,
|
|
&scgcfg->clockmode.rccr);
|
|
if (ret == OK)
|
|
{
|
|
ret = s32k1xx_set_sysclk_cfg(SCG_SYSTEM_CLOCK_MODE_VLPR,
|
|
&scgcfg->clockmode.vccr);
|
|
}
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_HSRUN
|
|
if (ret == OK)
|
|
{
|
|
ret = s32k1xx_set_sysclk_cfg(SCG_SYSTEM_CLOCK_MODE_HSRUN,
|
|
&scgcfg->clockmode.hccr);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_sim_config
|
|
*
|
|
* Description:
|
|
* Configure PCC clocking.
|
|
*
|
|
* Input Parameters:
|
|
* simcfg - Describes the new SIM clock configuration
|
|
*
|
|
* Returned Value:
|
|
* None.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void s32k1xx_sim_config(const struct sim_clock_config_s *simcfg)
|
|
{
|
|
uint32_t regval;
|
|
#ifdef CONFIG_S32K1XX_HAVE_QSPI
|
|
int i;
|
|
#endif
|
|
|
|
DEBUGASSERT(simcfg != NULL);
|
|
|
|
/* ClockOut settings. */
|
|
|
|
if (simcfg->clockout.initialize)
|
|
{
|
|
regval = getreg32(S32K1XX_SIM_CHIPCTL);
|
|
regval &= ~(SIM_CHIPCTL_CLKOUTEN | SIM_CHIPCTL_CLKOUTDIV_MASK |
|
|
SIM_CHIPCTL_CLKOUTSEL_MASK);
|
|
|
|
if (simcfg->clockout.enable)
|
|
{
|
|
regval |= SIM_CHIPCTL_CLKOUTEN;
|
|
}
|
|
|
|
regval |= SIM_CHIPCTL_CLKOUTSEL(simcfg->clockout.source);
|
|
regval |= SIM_CHIPCTL_CLKOUTDIV(simcfg->clockout.divider);
|
|
putreg32(regval, S32K1XX_SIM_CHIPCTL);
|
|
}
|
|
|
|
/* Low Power Clock settings from SIM. */
|
|
|
|
if (simcfg->lpoclk.initialize)
|
|
{
|
|
regval = getreg32(S32K1XX_SIM_LPOCLKS);
|
|
regval &= ~(SIM_LPOCLKS_LPO1KCLKEN | SIM_LPOCLKS_LPO32KCLKEN |
|
|
SIM_LPOCLKS_LPOCLKSEL_MASK | SIM_LPOCLKS_RTCCLKSEL_MASK);
|
|
|
|
if (simcfg->lpoclk.lpo1k)
|
|
{
|
|
regval |= SIM_LPOCLKS_LPO1KCLKEN;
|
|
}
|
|
|
|
if (simcfg->lpoclk.lpo32k)
|
|
{
|
|
regval |= SIM_LPOCLKS_LPO32KCLKEN;
|
|
}
|
|
|
|
regval |= SIM_LPOCLKS_LPOCLKSEL(simcfg->lpoclk.lpo_source);
|
|
regval |= SIM_LPOCLKS_RTCCLKSEL(simcfg->lpoclk.rtc_source);
|
|
|
|
putreg32(regval, S32K1XX_SIM_LPOCLKS);
|
|
}
|
|
|
|
/* Platform Gate Clock settings. */
|
|
|
|
if (simcfg->platgate.initialize)
|
|
{
|
|
regval = getreg32(S32K1XX_SIM_PLATCGC);
|
|
regval &= ~(SIM_PLATCGC_CGCMSCM | SIM_PLATCGC_CGCMPU |
|
|
SIM_PLATCGC_CGCDMA | SIM_PLATCGC_CGCERM |
|
|
SIM_PLATCGC_CGCEIM);
|
|
|
|
if (simcfg->platgate.mscm)
|
|
{
|
|
regval |= SIM_PLATCGC_CGCMSCM;
|
|
}
|
|
|
|
if (simcfg->platgate.mpu)
|
|
{
|
|
regval |= SIM_PLATCGC_CGCMPU;
|
|
}
|
|
|
|
if (simcfg->platgate.dma)
|
|
{
|
|
regval |= SIM_PLATCGC_CGCDMA;
|
|
}
|
|
|
|
if (simcfg->platgate.erm)
|
|
{
|
|
regval |= SIM_PLATCGC_CGCERM;
|
|
}
|
|
|
|
if (simcfg->platgate.eim)
|
|
{
|
|
regval |= SIM_PLATCGC_CGCEIM;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SIM_PLATCGC);
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_QSPI
|
|
regval = getreg32(S32K1XX_SIM_MISCTRL0);
|
|
regval &= ~SIM_MISCTRL0_QSPI_CLK_SEL;
|
|
|
|
if (simcfg->qspirefclk.refclk)
|
|
{
|
|
regval |= SIM_MISCTRL0_QSPI_CLK_SEL;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SIM_MISCTRL0);
|
|
#endif
|
|
}
|
|
|
|
#if 0 /* REVISIT: Not currently used */
|
|
/* TCLK Clock settings. */
|
|
|
|
if (simcfg->tclk.initialize)
|
|
{
|
|
for (i = 0; i < NUMBER_OF_TCLK_INPUTS; i++)
|
|
{
|
|
g_tclkfreq[i] = simcfg->tclk.tclkfreq[i];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Debug trace Clock settings. */
|
|
|
|
if (simcfg->traceclk.initialize)
|
|
{
|
|
/* Disable divider. */
|
|
|
|
putreg32(0, S32K1XX_SIM_CLKDIV4);
|
|
|
|
/* Configure trace source. */
|
|
|
|
regval = getreg32(S32K1XX_SIM_CHIPCTL);
|
|
regval &= ~SIM_CHIPCTL_TRACECLK_SEL;
|
|
|
|
if (simcfg->traceclk.source)
|
|
{
|
|
regval |= SIM_CHIPCTL_TRACECLK_SEL;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SIM_CHIPCTL);
|
|
|
|
if (simcfg->traceclk.enable)
|
|
{
|
|
regval = SIM_CLKDIV4_TRACEDIVEN |
|
|
SIM_CLKDIV4_TRACEDIV(simcfg->traceclk.divider);
|
|
|
|
if (simcfg->traceclk.fraction)
|
|
{
|
|
regval |= SIM_CLKDIV4_TRACEFRAC;
|
|
}
|
|
|
|
putreg32(regval, S32K1XX_SIM_CLKDIV4);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_pmc_config
|
|
*
|
|
* Description:
|
|
* Configure PMC clocking.
|
|
*
|
|
* Input Parameters:
|
|
* pmccfg - Describes the new PMC clock configuration
|
|
*
|
|
* Returned Value:
|
|
* None.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void s32k1xx_pmc_config(const struct pmc_config_s *pmccfg)
|
|
{
|
|
uint8_t regval;
|
|
|
|
DEBUGASSERT(pmccfg != NULL);
|
|
|
|
/* Low Power Clock settings from PMC. */
|
|
|
|
if (pmccfg->lpoclk.initialize)
|
|
{
|
|
/* Enable/disable the low power oscillator. */
|
|
|
|
regval = getreg8(S32K1XX_PMC_REGSC);
|
|
|
|
if (pmccfg->lpoclk.enable)
|
|
{
|
|
regval &= ~PMC_REGSC_LPODIS;
|
|
}
|
|
else
|
|
{
|
|
regval |= PMC_REGSC_LPODIS;
|
|
}
|
|
|
|
/* Enable Biasing (needed for VLPR mode, no effect in RUN mode) */
|
|
|
|
regval |= PMC_REGSC_BIASEN;
|
|
|
|
putreg8(regval, S32K1XX_PMC_REGSC);
|
|
|
|
/* Write trimming value. */
|
|
|
|
putreg8(pmccfg->lpoclk.trim & PMC_LPOTRIM_MASK, S32K1XX_PMC_LPOTRIM);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_allow_vlprmode
|
|
*
|
|
* Description:
|
|
* allow the very low power run mode.
|
|
*
|
|
* Input Parameters:
|
|
* allow - true if allowed, false otherwise.
|
|
*
|
|
* Returned Value:
|
|
* none.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void s32k1xx_allow_vlprmode(bool allow)
|
|
{
|
|
uint32_t regval;
|
|
|
|
/* get the SMC_PMPROT register */
|
|
|
|
regval = getreg32(S32K1XX_SMC_PMPROT);
|
|
|
|
/* mask the AVLP bit */
|
|
|
|
regval &= ~SMC_PMPROT_AVLP;
|
|
|
|
/* set the new bit */
|
|
|
|
regval |= (allow << SMC_PMPROT_AVLP_SHIFT);
|
|
|
|
/* set the registervalue */
|
|
|
|
putreg32(regval, S32K1XX_SMC_PMPROT);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: up_pm_notify
|
|
*
|
|
* Description:
|
|
* Notify the driver of new power state. This callback is called after
|
|
* all drivers have had the opportunity to prepare for the new power state.
|
|
*
|
|
* Input Parameters:
|
|
*
|
|
* cb - Returned to the driver. The driver version of the callback
|
|
* structure may include additional, driver-specific state data at
|
|
* the end of the structure.
|
|
*
|
|
* pmstate - Identifies the new PM state
|
|
*
|
|
* Returned Value:
|
|
* None - The driver already agreed to transition to the low power
|
|
* consumption state when when it returned OK to the prepare() call.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_PM
|
|
static void up_pm_notify(struct pm_callback_s *cb, int domain,
|
|
enum pm_state_e pmstate)
|
|
{
|
|
int return_value;
|
|
|
|
/* check if the transition is from the IDLE domain to the NORMAL domain */
|
|
|
|
if (pm_querystate(PM_IDLE_DOMAIN) == PM_IDLE &&
|
|
pmstate == PM_NORMAL)
|
|
{
|
|
/* return */
|
|
|
|
return;
|
|
}
|
|
|
|
/* check what the new power state is */
|
|
|
|
switch (pmstate)
|
|
{
|
|
/* if it needs to be set to RUN mode */
|
|
|
|
case(PM_NORMAL):
|
|
{
|
|
/* Logic for PM_NORMAL goes here */
|
|
|
|
/* change the microcontroller to RUN mode */
|
|
|
|
/* and wait until in RUN mode */
|
|
|
|
return_value = (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
|
|
|
|
/* check for debug assertion */
|
|
|
|
DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
/* enable all clock sources again if needed */
|
|
|
|
/* these could be the FIRC, PPL, and SOSC */
|
|
|
|
/* check if the FIRC was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.firc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
|
|
{
|
|
/* enable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(true,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the FIRC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
|
|
{
|
|
/* disable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(false,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.sosc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
|
|
{
|
|
/* disable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.spll.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(true,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
|
|
{
|
|
/* disable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(false,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the RCCR clock source is enabled */
|
|
|
|
if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
|
|
!= 0)
|
|
{
|
|
/* change the system clock back to the configured clock */
|
|
|
|
/* and wait until clock changed */
|
|
|
|
if (s32k1xx_transition_systemclock(
|
|
&g_initial_clkconfig.scg.clockmode.rccr))
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
}
|
|
|
|
/* if it is 0 */
|
|
|
|
else
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
|
|
/* calculate the new clock ticks */
|
|
|
|
up_timer_initialize();
|
|
}
|
|
break;
|
|
|
|
case(PM_IDLE):
|
|
{
|
|
/* Logic for PM_IDLE goes here */
|
|
}
|
|
break;
|
|
|
|
/* if it needs to be set to VLPR mode */
|
|
|
|
case(PM_STANDBY):
|
|
{
|
|
/* Logic for PM_STANDBY goes here */
|
|
|
|
#ifdef CONFIG_RUN_STANDBY
|
|
|
|
/* change the microcontroller to RUN mode */
|
|
|
|
/* and wait until in RUN mode */
|
|
|
|
return_value =
|
|
(int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
|
|
DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
/* enable all clock sources again if needed */
|
|
|
|
/* these could be the FIRC, PPL, and SOSC */
|
|
|
|
/* check if the FIRC was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.firc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
|
|
{
|
|
/* enable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(true,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the FIRC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
|
|
{
|
|
/* disable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(false,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.sosc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
|
|
{
|
|
/* disable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL was enabled and
|
|
* it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.spll.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(true,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
|
|
{
|
|
/* disable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(false,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the RCCR clock source is enabled */
|
|
|
|
if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
|
|
!= 0)
|
|
{
|
|
/* change the system clock back to the configured clock */
|
|
|
|
/* and wait until clock changed */
|
|
|
|
if (s32k1xx_transition_systemclock(
|
|
&g_initial_clkconfig.scg.clockmode.rccr))
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
}
|
|
|
|
/* if it is 0 */
|
|
|
|
else
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
|
|
#endif /* CONFIG_RUN_STANDBY */
|
|
|
|
#ifdef CONFIG_VLPR_STANDBY
|
|
|
|
/* set the system clock to the SIRC 8MHz freq */
|
|
|
|
/* this freq will change to the predefined vccr settings
|
|
* when the mode change occures
|
|
*/
|
|
|
|
/* and wait until system clock changed */
|
|
|
|
return_value = s32k1xx_sirc_clocksource();
|
|
DEBUGASSERT(!return_value);
|
|
|
|
/* disable the other clock sources if not already disabled */
|
|
|
|
/* these are the FIRC, PPL, and SOSC */
|
|
|
|
/* check if the SPLL is enabled */
|
|
|
|
if (s32k1xx_get_spllfreq() != 0)
|
|
{
|
|
/* disable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(false,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC is enabled */
|
|
|
|
if (s32k1xx_get_soscfreq() != 0)
|
|
{
|
|
/* disable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the FIRC is enabled */
|
|
|
|
if (s32k1xx_get_fircfreq() != 0)
|
|
{
|
|
/* disable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(false,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
#ifdef CONFIG_ARCH_CHIP_S32K11X
|
|
/* TODO make sure CMU is gated? (only for S32k11x) */
|
|
|
|
#error Make sure CMU is gated
|
|
#endif
|
|
|
|
/* change the microcontroller to VLPR mode */
|
|
|
|
/* and wait until it is in that runmode */
|
|
|
|
return_value =
|
|
(int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_VLPR);
|
|
DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
#endif /* CONFIG_VLPR_STANDBY */
|
|
|
|
/* calculate the new clock ticks */
|
|
|
|
up_timer_initialize();
|
|
}
|
|
break;
|
|
|
|
case(PM_SLEEP):
|
|
{
|
|
/* Logic for PM_SLEEP goes here */
|
|
|
|
#ifdef CONFIG_RUN_SLEEP
|
|
|
|
/* change the microcontroller to RUN mode */
|
|
|
|
/* and wait until in RUN mode */
|
|
|
|
return_value = (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
|
|
DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
/* enable all clock sources again if needed */
|
|
|
|
/* these could be the FIRC, PPL, and SOSC */
|
|
|
|
/* check if the FIRC was enabled
|
|
* and it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.firc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
|
|
{
|
|
/* enable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(true,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the FIRC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
|
|
{
|
|
/* disable FIRC */
|
|
|
|
return_value = s32k1xx_firc_config(false,
|
|
&g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC was enabled
|
|
* and it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.sosc.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
|
|
{
|
|
/* disable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL was enabled
|
|
* and it is not the system clock source
|
|
*/
|
|
|
|
if (g_initial_clkconfig.scg.spll.initialize &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
|
|
(s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
|
|
{
|
|
/* enable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(true,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SPLL needs to be disabled and if it is enabled */
|
|
|
|
else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
|
|
(s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
|
|
{
|
|
/* disable SPLL */
|
|
|
|
return_value = s32k1xx_spll_config(false,
|
|
&g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the RCCR clock source is enabled */
|
|
|
|
if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
|
|
!= 0)
|
|
{
|
|
/* change the system clock back to the configured clock */
|
|
|
|
/* and wait until clock changed */
|
|
|
|
if (s32k1xx_transition_systemclock(
|
|
&g_initial_clkconfig.scg.clockmode.rccr))
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
}
|
|
|
|
/* if it is 0 */
|
|
|
|
else
|
|
{
|
|
/* error */
|
|
|
|
DEBUGPANIC();
|
|
}
|
|
|
|
#endif /* CONFIG_RUN_SLEEP */
|
|
|
|
#ifdef CONFIG_VLPR_SLEEP
|
|
|
|
/* set the system clock to the SIRC 8MHz freq */
|
|
|
|
/* this freq will change to the predefined vccr settings
|
|
* when the mode change occures
|
|
*/
|
|
|
|
/* and wait until system clock changed */
|
|
|
|
return_value = s32k1xx_sirc_clocksource();
|
|
DEBUGASSERT(!return_value);
|
|
|
|
/* disable the other clock sources if not already disabled */
|
|
|
|
/* these are the FIRC, PPL, and SOSC */
|
|
|
|
/* check if the SPLL is enabled */
|
|
|
|
if (s32k1xx_get_spllfreq() != 0)
|
|
{
|
|
/* disable SPLL */
|
|
|
|
return_value =
|
|
s32k1xx_spll_config(false, &g_initial_clkconfig.scg.spll);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the SOSC is enabled */
|
|
|
|
if (s32k1xx_get_soscfreq() != 0)
|
|
{
|
|
/* disable SOSC */
|
|
|
|
return_value =
|
|
s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
/* check if the FIRC is enabled */
|
|
|
|
if (s32k1xx_get_fircfreq() != 0)
|
|
{
|
|
/* disable FIRC */
|
|
|
|
return_value =
|
|
s32k1xx_firc_config(false, &g_initial_clkconfig.scg.firc);
|
|
DEBUGASSERT(!return_value);
|
|
}
|
|
|
|
#ifdef CONFIG_ARCH_CHIP_S32K11X
|
|
/* TODO make sure CMU is gated? (only for S32k11x) */
|
|
|
|
#error Make sure CMU is gated
|
|
#endif
|
|
/* change the microcontroller to VLPR mode */
|
|
|
|
/* and wait until it is in that runmode */
|
|
|
|
return_value =
|
|
(int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_VLPR);
|
|
DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
|
|
|
|
#endif /* CONFIG_VLPR_SLEEP */
|
|
|
|
/* calculate the new clock ticks */
|
|
|
|
up_timer_initialize();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Should not get here */
|
|
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: up_pm_prepare
|
|
*
|
|
* Description:
|
|
* Request the driver to prepare for a new power state. This is a warning
|
|
* that the system is about to enter into a new power state. The driver
|
|
* should begin whatever operations that may be required to enter power
|
|
* state. The driver may abort the state change mode by returning a
|
|
* non-zero value from the callback function.
|
|
*
|
|
* Input Parameters:
|
|
*
|
|
* cb - Returned to the driver. The driver version of the callback
|
|
* structure may include additional, driver-specific state data at
|
|
* the end of the structure.
|
|
*
|
|
* pmstate - Identifies the new PM state
|
|
*
|
|
* Returned Value:
|
|
* Zero - (OK) means the event was successfully processed and that the
|
|
* driver is prepared for the PM state change.
|
|
*
|
|
* Non-zero - means that the driver is not prepared to perform the tasks
|
|
* needed achieve this power setting and will cause the state
|
|
* change to be aborted. NOTE: The prepare() method will also
|
|
* be called when reverting from lower back to higher power
|
|
* consumption modes (say because another driver refused a
|
|
* lower power state change). Drivers are not permitted to
|
|
* return non-zero values when reverting back to higher power
|
|
* consumption modes!
|
|
*
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_PM
|
|
static int up_pm_prepare(struct pm_callback_s *cb, int domain,
|
|
enum pm_state_e pmstate)
|
|
{
|
|
/* Logic to prepare for a reduced power state goes here. */
|
|
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_runmode
|
|
*
|
|
* Description:
|
|
* Get the current running mode.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* The current running mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
enum scg_system_clock_mode_e s32k1xx_get_runmode(void)
|
|
{
|
|
enum scg_system_clock_mode_e mode;
|
|
|
|
/* Get the current running mode */
|
|
|
|
switch (getreg32(S32K1XX_SMC_PMSTAT) & SMC_PMSTAT_PMSTAT_MASK)
|
|
{
|
|
/* Run mode */
|
|
|
|
case SMC_PMSTAT_PMSTAT_RUN:
|
|
mode = SCG_SYSTEM_CLOCK_MODE_RUN;
|
|
break;
|
|
|
|
/* Very low power run mode */
|
|
|
|
case SMC_PMSTAT_PMSTAT_VLPR:
|
|
mode = SCG_SYSTEM_CLOCK_MODE_VLPR;
|
|
break;
|
|
|
|
/* High speed run mode */
|
|
|
|
case SMC_PMSTAT_PMSTAT_HSRUN:
|
|
mode = SCG_SYSTEM_CLOCK_MODE_HSRUN;
|
|
break;
|
|
|
|
/* This should never happen - core has to be in some run mode to
|
|
* execute code
|
|
*/
|
|
|
|
case SMC_PMSTAT_PMSTAT_VLPS:
|
|
default:
|
|
mode = SCG_SYSTEM_CLOCK_MODE_NONE;
|
|
break;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_set_runmode
|
|
*
|
|
* Description:
|
|
* Set the running mode.
|
|
*
|
|
* Input Parameters:
|
|
* next_run_mode - The next running mode.
|
|
*
|
|
* Returned Value:
|
|
* The current running mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
enum scg_system_clock_mode_e s32k1xx_set_runmode(enum scg_system_clock_mode_e
|
|
next_run_mode)
|
|
{
|
|
enum scg_system_clock_mode_e mode;
|
|
|
|
/* get the current run mode */
|
|
|
|
mode = s32k1xx_get_runmode();
|
|
uint32_t regval;
|
|
|
|
/* check if the current runmode is not the same as the next runmode */
|
|
|
|
if (mode != next_run_mode)
|
|
{
|
|
/* check what the next mode is */
|
|
|
|
switch (next_run_mode)
|
|
{
|
|
/* in case of the RUN mode */
|
|
|
|
/* it will use the clock configuration from S32K1XX_SCG_RCCR */
|
|
|
|
case SCG_SYSTEM_CLOCK_MODE_RUN:
|
|
|
|
/* check if in VLPR mode */
|
|
|
|
if (mode == SCG_SYSTEM_CLOCK_MODE_VLPR)
|
|
{
|
|
/* get the SMC_PMCTRL register */
|
|
|
|
regval = getreg32(S32K1XX_SMC_PMCTRL);
|
|
|
|
/* mask the RUNM bits */
|
|
|
|
regval &= ~SMC_PMCTRL_RUNM_MASK;
|
|
|
|
/* change the mode to RUN mode */
|
|
|
|
regval |= SMC_PMCTRL_RUNM_RUN;
|
|
|
|
/* write the register */
|
|
|
|
putreg32(regval, S32K1XX_SMC_PMCTRL);
|
|
|
|
/* wait until it is in RUN mode */
|
|
|
|
while (s32k1xx_get_runmode() != SCG_SYSTEM_CLOCK_MODE_RUN);
|
|
}
|
|
|
|
break;
|
|
|
|
/* in case of the VLPR mode */
|
|
|
|
/* it will use the clock configuration from S32K1XX_SCG_VCCR */
|
|
|
|
case SCG_SYSTEM_CLOCK_MODE_VLPR:
|
|
|
|
/* check if in RUN mode and VLPR mode is allowed */
|
|
|
|
if ((mode == SCG_SYSTEM_CLOCK_MODE_RUN) &&
|
|
(getreg32(S32K1XX_SMC_PMPROT) & SMC_PMPROT_AVLP))
|
|
{
|
|
/* get the SMC_PMCTRL register */
|
|
|
|
regval = getreg32(S32K1XX_SMC_PMCTRL);
|
|
|
|
/* mask the RUNM bits */
|
|
|
|
regval &= ~SMC_PMCTRL_RUNM_MASK;
|
|
|
|
/* change the mode to VLPR mode */
|
|
|
|
regval |= SMC_PMCTRL_RUNM_VLPR;
|
|
|
|
/* write the register */
|
|
|
|
putreg32(regval, S32K1XX_SMC_PMCTRL);
|
|
|
|
/* wait until it is in VLPR mode */
|
|
|
|
while (s32k1xx_get_runmode() != SCG_SYSTEM_CLOCK_MODE_VLPR);
|
|
}
|
|
break;
|
|
|
|
/* others are not implemented */
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* get the current run mode */
|
|
|
|
mode = s32k1xx_get_runmode();
|
|
}
|
|
|
|
/* return the mode */
|
|
|
|
return mode;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_clockconfig
|
|
*
|
|
* Description:
|
|
* Called to initialize the S32K1XX. This does whatever setup is needed
|
|
* to put the MCU in a usable state. This includes the initialization of
|
|
* clocking using the settings in board.h. This function also performs
|
|
* other low-level chip as necessary.
|
|
*
|
|
* Input Parameters:
|
|
* clkcfg - Describes the new clock configuration
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned a success; A negated errno value is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int s32k1xx_clockconfig(const struct clock_configuration_s *clkcfg)
|
|
{
|
|
int ret;
|
|
|
|
DEBUGASSERT(clkcfg != NULL);
|
|
|
|
/* Set SCG configuration */
|
|
|
|
ret = s32k1xx_scg_config(&clkcfg->scg);
|
|
if (ret >= 0)
|
|
{
|
|
/* Allow the VLPR mode */
|
|
|
|
s32k1xx_allow_vlprmode(true);
|
|
|
|
/* Set PCC configuration */
|
|
|
|
s32k1xx_periphclocks(clkcfg->pcc.count, clkcfg->pcc.pclks);
|
|
|
|
/* Set SIM configuration */
|
|
|
|
s32k1xx_sim_config(&clkcfg->sim);
|
|
|
|
/* Set PMC configuration */
|
|
|
|
s32k1xx_pmc_config(&clkcfg->pmc);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_clock_pm_register
|
|
*
|
|
* Description:
|
|
* This function is called after OS and PM init in order to register to
|
|
* receive power management event callbacks.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Values:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
#ifdef CONFIG_PM
|
|
void s32k1xx_clock_pm_register(void)
|
|
{
|
|
/* Register to receive power management callbacks */
|
|
|
|
pm_register(&g_clock_pmcb);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_coreclk
|
|
*
|
|
* Description:
|
|
* Return the current value of the CORE clock frequency.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Values:
|
|
* The current value of the CORE clock frequency. Zero is returned on any
|
|
* failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
uint32_t s32k1xx_get_coreclk(void)
|
|
{
|
|
uint32_t coreclk = 0;
|
|
uint32_t regval;
|
|
uint32_t divider;
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
uint32_t prediv;
|
|
uint32_t mult;
|
|
#endif
|
|
|
|
/* Get the core clock divider */
|
|
|
|
regval = getreg32(S32K1XX_SCG_CSR);
|
|
divider = ((regval & SCG_CSR_DIVCORE_MASK) >> SCG_CSR_DIVCORE_SHIFT) + 1;
|
|
|
|
/* Handle according to the selection clock source */
|
|
|
|
switch (regval & SCG_CSR_SCS_MASK)
|
|
{
|
|
case SCG_CSR_SCS_SOSC: /* System OSC */
|
|
|
|
coreclk = BOARD_XTAL_FREQUENCY;
|
|
break;
|
|
|
|
case SCG_CSR_SCS_SIRC: /* Slow IRC */
|
|
regval = getreg32(S32K1XX_SCG_SIRCCFG) & SCG_SIRCCFG_RANGE;
|
|
if (regval == SCG_SIRCCFG_LOWRANGE)
|
|
{
|
|
/* Slow IRC low range clock (2 MHz) */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Slow IRC high range clock (8 MHz ) */
|
|
|
|
coreclk = SCG_SIRC_HIGHRANGE_FREQUENCY;
|
|
break;
|
|
|
|
case SCG_CSR_SCS_FIRC: /* Fast IRC */
|
|
regval = getreg32(S32K1XX_SCG_FIRCCFG) & SCG_FIRCCFG_RANGE;
|
|
if (regval != SCG_FIRCCFG_48MHZ)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Fast IRC is trimmed to 48 MHz */
|
|
|
|
coreclk = SCG_FIRC_FREQUENCY0;
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
case SCG_CSR_SPLL_FIRC: /* System PLL */
|
|
|
|
/* Coreclock = Fxtal * mult / (2 * prediv) */
|
|
|
|
regval = getreg32(S32K1XX_SCG_SPLLCFG);
|
|
prediv = ((regval & SCG_SPLLCFG_PREDIV_MASK) >>
|
|
SCG_SPLLCFG_PREDIV_SHIFT) + 1;
|
|
mult = ((regval & SCG_SPLLCFG_MULT_MASK) >>
|
|
SCG_SPLLCFG_MULT_SHIFT) + 16;
|
|
|
|
coreclk = ((BOARD_XTAL_FREQUENCY / 2) * mult) / prediv;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return coreclk / divider;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_sysclk
|
|
*
|
|
* Description:
|
|
* Return the current value of an SCG system clock frequency, these clocks
|
|
* are used for core, platform, external and bus clock domains..
|
|
*
|
|
* Input Parameters:
|
|
* type - Identifies the system clock of interest
|
|
*
|
|
* Returned Values:
|
|
* The current value of the system clock frequency. Zero is returned on
|
|
* any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
uint32_t s32k1xx_get_sysclk(enum scg_system_clock_type_e type)
|
|
{
|
|
enum scg_system_clock_src_e clksrc;
|
|
uint32_t regval;
|
|
uint32_t divider;
|
|
uint32_t freq;
|
|
|
|
/* Get the SCG current system clock source */
|
|
|
|
clksrc = (enum scg_system_clock_src_e)s32k1xx_get_scgclk_source();
|
|
freq = s32k1xx_get_srcfreq(clksrc);
|
|
|
|
/* Adjust to count for the code divider */
|
|
|
|
regval = getreg32(S32K1XX_SCG_CSR);
|
|
divider = ((regval & SCG_CSR_DIVCORE_MASK) >> SCG_CSR_DIVCORE_SHIFT) + 1;
|
|
freq /= divider;
|
|
|
|
/* Handle additional dividers for the clock type */
|
|
|
|
switch (type)
|
|
{
|
|
case SCG_SYSTEM_CLOCK_CORE:
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_BUS:
|
|
divider = ((regval & SCG_CSR_DIVBUS_MASK) >>
|
|
SCG_CSR_DIVBUS_SHIFT) + 1;
|
|
freq /= divider;
|
|
break;
|
|
|
|
case SCG_SYSTEM_CLOCK_SLOW:
|
|
divider = ((regval & SCG_CSR_DIVSLOW_MASK) >>
|
|
SCG_CSR_DIVSLOW_SHIFT) + 1;
|
|
freq /= divider;
|
|
break;
|
|
|
|
default:
|
|
freq = 0;
|
|
break;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_get_asnchfreq
|
|
*
|
|
* Description:
|
|
* Gets SCG asynchronous clock frequency from a clock source.
|
|
*
|
|
* Input Parameters:
|
|
* clksrc - The requested clock source.
|
|
* type - The requested clock type.
|
|
*
|
|
* Returned Value:
|
|
* The frequency of the requested asynchronous clock source.
|
|
*
|
|
****************************************************************************/
|
|
|
|
uint32_t s32k1xx_get_asnchfreq(enum clock_names_e clksrc,
|
|
enum scg_async_clock_type_e type)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t freq = 0;
|
|
uint32_t div = 0;
|
|
|
|
switch (type)
|
|
{
|
|
case SCG_ASYNC_CLOCK_DIV1:
|
|
{
|
|
switch (clksrc)
|
|
{
|
|
case FIRC_CLK:
|
|
{
|
|
freq = s32k1xx_get_fircfreq();
|
|
regval = getreg32(S32K1XX_SCG_FIRCDIV);
|
|
div = (regval & SCG_FIRCDIV_FIRCDIV1_MASK) >>
|
|
SCG_FIRCDIV_FIRCDIV1_SHIFT;
|
|
}
|
|
break;
|
|
|
|
case SIRC_CLK:
|
|
{
|
|
freq = s32k1xx_get_sircfreq();
|
|
regval = getreg32(S32K1XX_SCG_SIRCDIV);
|
|
div = (regval & SCG_SIRCDIV_SIRCDIV1_MASK) >>
|
|
SCG_SIRCDIV_SIRCDIV1_SHIFT;
|
|
}
|
|
break;
|
|
|
|
case SOSC_CLK:
|
|
{
|
|
freq = s32k1xx_get_soscfreq();
|
|
regval = getreg32(S32K1XX_SCG_SOSCDIV);
|
|
div = (regval & SCG_SOSCDIV_SOSCDIV1_MASK) >>
|
|
SCG_SOSCDIV_SOSCDIV1_SHIFT;
|
|
}
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
case SPLL_CLK:
|
|
{
|
|
freq = s32k1xx_get_spllfreq();
|
|
regval = getreg32(S32K1XX_SCG_SPLLDIV);
|
|
div = (regval & SCG_SPLLDIV_SPLLDIV1_MASK) >>
|
|
SCG_SPLLDIV_SPLLDIV1_SHIFT;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
{
|
|
/* Invalid clock source type */
|
|
|
|
freq = 0;
|
|
DEBUGPANIC();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCG_ASYNC_CLOCK_DIV2:
|
|
{
|
|
switch (clksrc)
|
|
{
|
|
case FIRC_CLK:
|
|
{
|
|
freq = s32k1xx_get_fircfreq();
|
|
regval = getreg32(S32K1XX_SCG_FIRCDIV);
|
|
div = (regval & SCG_FIRCDIV_FIRCDIV2_MASK) >>
|
|
SCG_FIRCDIV_FIRCDIV2_SHIFT;
|
|
}
|
|
break;
|
|
|
|
case SIRC_CLK:
|
|
{
|
|
freq = s32k1xx_get_sircfreq();
|
|
regval = getreg32(S32K1XX_SCG_SIRCDIV);
|
|
div = (regval & SCG_SIRCDIV_SIRCDIV2_MASK) >>
|
|
SCG_SIRCDIV_SIRCDIV2_SHIFT;
|
|
}
|
|
break;
|
|
case SOSC_CLK:
|
|
{
|
|
freq = s32k1xx_get_soscfreq();
|
|
regval = getreg32(S32K1XX_SCG_SOSCDIV);
|
|
div = (regval & SCG_SOSCDIV_SOSCDIV2_MASK) >>
|
|
SCG_SOSCDIV_SOSCDIV2_SHIFT;
|
|
}
|
|
break;
|
|
#ifdef CONFIG_S32K1XX_HAVE_SPLL
|
|
case SPLL_CLK:
|
|
{
|
|
freq = s32k1xx_get_spllfreq();
|
|
regval = getreg32(S32K1XX_SCG_SPLLDIV);
|
|
div = (regval & SCG_SPLLDIV_SPLLDIV2_MASK) >>
|
|
SCG_SPLLDIV_SPLLDIV2_SHIFT;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
{
|
|
/* Invalid clock source type */
|
|
|
|
freq = 0;
|
|
DEBUGPANIC();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid async clock source */
|
|
|
|
freq = 0;
|
|
DEBUGPANIC();
|
|
break;
|
|
}
|
|
|
|
if (div != 0)
|
|
{
|
|
freq = (freq >> (div - 1));
|
|
}
|
|
else /* Output disabled. */
|
|
{
|
|
freq = 0;
|
|
}
|
|
|
|
return freq;
|
|
}
|