nuttx/arch/risc-v/src/rv32m1/rv32m1_clockconfig.c
Xiang Xiao 54e630e14d arch: Merge up_arch.h into up_internal.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2022-03-14 09:32:17 +02:00

664 lines
16 KiB
C

/****************************************************************************
* arch/risc-v/src/rv32m1/rv32m1_clockconfig.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <arch/board/board.h>
#include "riscv_internal.h"
#include "chip.h"
#include "hardware/rv32m1_scg.h"
#include "hardware/rv32m1_smc.h"
#include "rv32m1_clockconfig.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: rv32m1_modifyreg32
****************************************************************************/
static void rv32m1_modifyreg32(uint32_t addr, uint32_t bitclr,
uint32_t bitset)
{
uint32_t regval = getreg32(addr);
regval &= ~bitclr;
regval |= bitset;
putreg32(regval, addr);
}
/****************************************************************************
* Name: rv32m1_sircfreq
****************************************************************************/
static unsigned rv32m1_sircfreq(void)
{
uint32_t regval = getreg32(RV32M1_SCG_SIRCCSR);
/* If the SIRC is Invalid or Disabled */
if (!(regval & SCG_SIRCCSR_VLD))
{
return 0u;
}
regval = getreg32(RV32M1_SCG_SIRCCFG) & SCG_SIRCCFG_RANGE_MASK;
if (regval == SCG_SIRCCFG_RANGE_8MHZ)
{
return 8000000u;
}
/* SIRC provides 2 options of frequency: 8MHz and 2MHz,
* In this case, it has to be 2MHz.
*/
return 2000000u;
}
/****************************************************************************
* Name: rv32m1_fircfreq
****************************************************************************/
static unsigned rv32m1_fircfreq(void)
{
uint32_t regval = getreg32(RV32M1_SCG_FIRCCSR);
/* If the FIRC is Invalid or Disabled */
if (!(regval & SCG_FIRCCSR_VLD))
{
return 0u;
}
regval = getreg32(RV32M1_SCG_FIRCCFG) & SCG_FIRCCFG_RANGE_MASK;
if (regval == SCG_FIRCCFG_RANGE_48MHZ)
{
return 48000000u;
}
if (regval == SCG_FIRCCFG_RANGE_52MHZ)
{
return 52000000u;
}
if (regval == SCG_FIRCCFG_RANGE_56MHZ)
{
return 56000000u;
}
/* FIRC provides 4 options of frequency: 48MHz, 52MHz, 56MHz, 60MHz,
* In this case, it has to be 60MHz.
*/
return 60000000u;
}
/****************************************************************************
* Name: rv32m1_lpfllfreq
****************************************************************************/
static unsigned rv32m1_lpfllfreq(void)
{
uint32_t regval = getreg32(RV32M1_SCG_LPFLLCSR);
/* If the LPFLL is Invalid or Disabled */
if (!(regval & SCG_LPFLLCSR_VLD))
{
return 0u;
}
regval = getreg32(RV32M1_SCG_LPFLLCFG) & SCG_LPFLLCFG_RANGE_MASK;
if (regval == SCG_LPFLLCFG_RANGE_48MHZ)
{
return 48000000u;
}
/* LPFLL provides 2 options of frequency: 48MHz, 72MHz,
* In this case, it has to be 72MHz.
*/
return 72000000u;
}
/****************************************************************************
* Name: rv32m1_soscfreq
****************************************************************************/
static unsigned rv32m1_soscfreq(void)
{
uint32_t regval = getreg32(RV32M1_SCG_SOSCCSR);
/* If the SOSC is Invalid or Disabled */
if (!(regval & SCG_SOSCCSR_VLD))
{
return 0u;
}
#ifdef RV32M1_BOARD_XTAL
return RV32M1_BOARD_XTAL;
#else
return 0u;
#endif
}
/****************************************************************************
* Name: rv32m1_lpocfreq
****************************************************************************/
static unsigned rv32m1_lpocfreq(void)
{
return 1000u;
}
/****************************************************************************
* Name: rv32m1_roscfreq
****************************************************************************/
static unsigned rv32m1_roscfreq(void)
{
uint32_t regval = getreg32(RV32M1_SCG_ROSCCSR);
/* If the ROSC is Invalid or Disabled */
if (!(regval & SCG_ROSCCSR_VLD))
{
return 0;
}
return 32768u;
}
/****************************************************************************
* Name: rv32m1_corefreq
****************************************************************************/
static unsigned rv32m1_corefreq(void)
{
uint32_t scs;
uint32_t div;
uint32_t regval = getreg32(RV32M1_SCG_ROSCCSR);
uint32_t freq = 0;
scs = regval & SCG_CSR_SCS_MASK;
switch (scs)
{
case SCG_CSR_SCS_SOSC:
freq = rv32m1_soscfreq();
break;
case SCG_CSR_SCS_SIRC:
freq = rv32m1_sircfreq();
break;
case SCG_CSR_SCS_FIRC:
freq = rv32m1_fircfreq();
break;
case SCG_CSR_SCS_ROSC:
freq = rv32m1_roscfreq();
break;
case SCG_CSR_SCS_LPFLL:
freq = rv32m1_lpfllfreq();
break;
default:
freq = 0;
break;
}
div = (regval & SCG_CSR_DIVCORE_MASK) >> SCG_CSR_DIVCORE_SHIFT;
div += 1;
return freq / div;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rv32m1_clockconfig
****************************************************************************/
void rv32m1_clockconfig(void)
{
/* Initialize SIRC */
putreg32(SCG_SIRCDIV_DIV1_DISABLED |
SCG_SIRCDIV_DIV2_DIVBY1 |
SCG_SIRCDIV_DIV3_DIVBY1 ,
RV32M1_SCG_SIRCDIV);
/* 8MHZ is wanted */
putreg32(SCG_SIRCCFG_RANGE_8MHZ, RV32M1_SCG_SIRCCFG);
/* Enable SIRC with Lower Power Mode support */
rv32m1_modifyreg32(RV32M1_SCG_SIRCCSR, 0,
SCG_SIRCCSR_EN | SCG_SIRCCSR_LPEN);
/* Wait for SIRC to be valid */
while (!(getreg32(RV32M1_SCG_SIRCCSR) & SCG_SIRCCSR_VLD)) ;
/* Switch to SIRC clock as System Clock */
putreg32(SCG_RCCR_SCS_SIRC |
SCG_RCCR_DIVCORE_DIV1 |
SCG_RCCR_DIVSLOW_DIV4 ,
RV32M1_SCG_RCCR);
/* Wait for SIRC as System Clock */
while ((getreg32(RV32M1_SCG_CSR) & SCG_CSR_SCS_MASK) !=
SCG_CSR_SCS_SIRC);
/* Initialize FIRC */
putreg32(SCG_FIRCDIV_DIV1_DIVBY1 |
SCG_FIRCDIV_DIV2_DIVBY1 |
SCG_FIRCDIV_DIV3_DIVBY1 ,
RV32M1_SCG_FIRCDIV);
/* 48MHz is wanted */
putreg32(SCG_FIRCCFG_RANGE_48MHZ, RV32M1_SCG_FIRCCFG);
/* Enable FIRC */
rv32m1_modifyreg32(RV32M1_SCG_FIRCCSR, 0, SCG_FIRCCSR_EN);
/* Wait for FIRC to be valid */
while (!(getreg32(RV32M1_SCG_FIRCCSR) & SCG_FIRCCSR_VLD)) ;
/* Switch FIRC as the RUN Mode System Clock */
putreg32(SCG_RCCR_SCS_FIRC |
SCG_RCCR_DIVCORE_DIV1 |
SCG_RCCR_DIVBUS_DIV1 |
SCG_RCCR_DIVEXT_DIV1 |
SCG_RCCR_DIVSLOW_DIV4 ,
RV32M1_SCG_RCCR);
/* Wait for FIRC as System Clock */
while ((getreg32(RV32M1_SCG_CSR) & SCG_CSR_SCS_MASK) !=
SCG_CSR_SCS_FIRC);
/* Prepare LPFLL for HSRUN Mode */
putreg32(SCG_LPFLLDIV_DIV1_DIVBY1 |
SCG_LPFLLDIV_DIV2_DIVBY1 |
SCG_LPFLLDIV_DIV3_DIVBY1 ,
RV32M1_SCG_LPFLLDIV);
/* 72MHz is wanted */
putreg32(SCG_LPFLLCFG_RANGE_72MHZ, RV32M1_SCG_LPFLLCFG);
/* Trim LPFLL input source */
rv32m1_modifyreg32(RV32M1_SCG_LPFLLTCFG,
SCG_LPFLLTCFG_TRIMDIV_MASK |
SCG_LPFLLTCFG_TRIMSRC_MASK,
SCG_LPFLLTCFG_TRIMDIV_BY4 |
SCG_LPFLLTCFG_TRIMSRC_SIRC);
/* Enable LPFLL */
rv32m1_modifyreg32(RV32M1_SCG_LPFLLCSR, 0, SCG_LPFLLCSR_EN);
/* Wait for LPFLL to be valid */
while (!(getreg32(RV32M1_SCG_LPFLLCSR) & SCG_LPFLLCSR_VLD)) ;
/* Set LPFLL as the HSRUN Mode System Clock */
putreg32(SCG_HCCR_SCS_LPFLL |
SCG_HCCR_DIVCORE_DIV1 |
SCG_HCCR_DIVBUS_DIV1 |
SCG_HCCR_DIVEXT_DIV1 |
SCG_HCCR_DIVSLOW_DIV4 ,
RV32M1_SCG_HCCR);
/* Remove the power mode protection */
putreg32(SMC_PMPROT_PM_ALL_ALLOWED, RV32M1_SMC_PMPROT);
/* Enable HSRUN Mode */
rv32m1_modifyreg32(RV32M1_SMC_PMCTRL,
SMC_PMCTRL_RUNM_MASK,
SMC_PMCTRL_RUNM_HSRUN);
/* Wait for High Speed Run Mode stable */
while ((getreg32(RV32M1_SMC_PMSTAT) & SMC_PMSTAT_PMSTAT_MASK) !=
SMC_PMSTAT_HSRUN);
/* Wait for LPFLL as System Clock */
while ((getreg32(RV32M1_SCG_CSR) & SCG_CSR_SCS_MASK) !=
SCG_CSR_SCS_LPFLL);
}
/****************************************************************************
* Name: rv32m1_clockfreq
*
* Description:
* Query the frequecy of a given clock source.
*
****************************************************************************/
unsigned rv32m1_clockfreq(enum clk_e clk)
{
uint32_t freq;
uint32_t div;
switch (clk)
{
case CLK_SIRC:
return rv32m1_sircfreq();
case CLK_SIRCDIV1:
{
freq = rv32m1_sircfreq();
div = (getreg32(RV32M1_SCG_SIRCDIV) & SCG_SIRCDIV_DIV1_MASK) >>
SCG_SIRCDIV_DIV1_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_SIRCDIV2:
{
freq = rv32m1_sircfreq();
div = (getreg32(RV32M1_SCG_SIRCDIV) & SCG_SIRCDIV_DIV2_MASK) >>
SCG_SIRCDIV_DIV2_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_SIRCDIV3:
{
freq = rv32m1_sircfreq();
div = (getreg32(RV32M1_SCG_SIRCDIV) & SCG_SIRCDIV_DIV3_MASK) >>
SCG_SIRCDIV_DIV3_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_FIRC:
return freq = rv32m1_fircfreq();
case CLK_FIRCDIV1:
{
freq = rv32m1_fircfreq();
div = (getreg32(RV32M1_SCG_FIRCDIV) & SCG_FIRCDIV_DIV1_MASK) >>
SCG_FIRCDIV_DIV1_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_FIRCDIV2:
{
freq = rv32m1_fircfreq();
div = (getreg32(RV32M1_SCG_FIRCDIV) & SCG_FIRCDIV_DIV2_MASK) >>
SCG_FIRCDIV_DIV2_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_FIRCDIV3:
{
freq = rv32m1_fircfreq();
div = (getreg32(RV32M1_SCG_FIRCDIV) & SCG_FIRCDIV_DIV3_MASK) >>
SCG_FIRCDIV_DIV3_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_LPFLL:
return freq = rv32m1_lpfllfreq();
case CLK_LPFLLDIV1:
{
freq = rv32m1_lpfllfreq();
div = (getreg32(RV32M1_SCG_LPFLLDIV) & SCG_LPFLLDIV_DIV1_MASK) >>
SCG_LPFLLDIV_DIV1_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_LPFLLDIV2:
{
freq = rv32m1_lpfllfreq();
div = (getreg32(RV32M1_SCG_LPFLLDIV) & SCG_LPFLLDIV_DIV2_MASK) >>
SCG_LPFLLDIV_DIV2_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_LPFLLDIV3:
{
freq = rv32m1_lpfllfreq();
div = (getreg32(RV32M1_SCG_LPFLLDIV) & SCG_LPFLLDIV_DIV3_MASK) >>
SCG_LPFLLDIV_DIV3_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_SOSC:
return rv32m1_soscfreq();
case CLK_SOSCDIV1:
{
freq = rv32m1_soscfreq();
div = (getreg32(RV32M1_SCG_SOSCDIV) & SCG_SOSCDIV_DIV1_MASK) >>
SCG_LPFLLDIV_DIV1_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_SOSCDIV2:
{
freq = rv32m1_soscfreq();
div = (getreg32(RV32M1_SCG_SOSCDIV) & SCG_SOSCDIV_DIV2_MASK) >>
SCG_LPFLLDIV_DIV2_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_SOSCDIV3:
{
freq = rv32m1_soscfreq();
div = (getreg32(RV32M1_SCG_SOSCDIV) & SCG_SOSCDIV_DIV3_MASK) >>
SCG_LPFLLDIV_DIV3_SHIFT;
/* If div is Zero, the clock source is disabled */
if (div == 0)
{
return 0u;
}
return freq / (1 << (div - 1));
}
break;
case CLK_LPOC:
return rv32m1_lpocfreq();
case CLK_ROSC:
return rv32m1_roscfreq();
case CLK_CORE:
case CLK_PLAT:
case CLK_SYS:
return rv32m1_corefreq();
case CLK_BUS:
{
freq = rv32m1_corefreq();
div = (getreg32(RV32M1_SCG_CSR) & SCG_CSR_DIVBUS_MASK) >>
SCG_CSR_DIVBUS_SHIFT;
div += 1;
return freq / div;
}
break;
case CLK_EXT:
{
freq = rv32m1_corefreq();
div = (getreg32(RV32M1_SCG_CSR) & SCG_CSR_DIVEXT_MASK) >>
SCG_CSR_DIVEXT_SHIFT;
div += 1;
return freq / div;
}
break;
case CLK_SLOW:
{
freq = rv32m1_corefreq();
div = (getreg32(RV32M1_SCG_CSR) & SCG_CSR_DIVSLOW_MASK) >>
SCG_CSR_DIVSLOW_SHIFT;
div += 1;
return freq / div;
}
break;
default:
return 0u;
}
return 0u;
}