2021-02-17 13:47:50 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
|
|
|
* Public License v2.1. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @ingroup cpu_gd32v
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @brief GD32V Clock initialization
|
|
|
|
*
|
|
|
|
* @author Koen Zandberg <koen@bergzand.net>
|
|
|
|
*
|
|
|
|
* Heavily based on the stm32f1 connectivity line clock initialization
|
|
|
|
*/
|
|
|
|
#include "kernel_defines.h"
|
|
|
|
#include "irq.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "periph_conf.h"
|
|
|
|
|
|
|
|
#define CLOCK_AHB_DIV 0 /* Max speed at 108 MHz */
|
|
|
|
#define CLOCK_APB1_DIV (0x04 | 0) /* Max speed at 54 MHz */
|
|
|
|
#define CLOCK_APB2_DIV (0x0 | 0) /* Max speed at 108 MHz */
|
|
|
|
|
|
|
|
#define CLOCK_AHB_DIV_CONF (CLOCK_AHB_DIV << RCU_CFG0_AHBPSC_Pos)
|
|
|
|
#define CLOCK_APB1_DIV_CONF (CLOCK_APB1_DIV << RCU_CFG0_APB1PSC_Pos)
|
|
|
|
#define CLOCK_APB2_DIV_CONF (CLOCK_APB2_DIV << RCU_CFG0_APB2PSC_Pos)
|
|
|
|
|
|
|
|
#define PREDV0_CONF 1 /* Divide by 2 */
|
2023-01-08 09:54:13 +01:00
|
|
|
#ifdef CONFIG_BOARD_HAS_HXTAL
|
2021-02-17 13:47:50 +01:00
|
|
|
#define PLL_MULT_FACTOR (CLOCK_CORECLOCK / \
|
2023-01-09 21:51:28 +01:00
|
|
|
(CONFIG_CLOCK_HXTAL / (PREDV0_CONF + 1)) - 1)
|
2023-01-08 09:54:13 +01:00
|
|
|
#else
|
|
|
|
#define PLL_MULT_FACTOR (CLOCK_CORECLOCK / (MHZ(8) / 2 ) - 1)
|
|
|
|
#endif
|
2021-02-17 13:47:50 +01:00
|
|
|
|
|
|
|
#define RCU_CFG0_SCS_IRC8 (0 << RCU_CFG0_SCS_Pos)
|
|
|
|
#define RCU_CFG0_SCS_HXTAL (1 << RCU_CFG0_SCS_Pos)
|
|
|
|
#define RCU_CFG0_SCS_PLL (2 << RCU_CFG0_SCS_Pos)
|
|
|
|
|
2023-03-20 12:04:17 +01:00
|
|
|
#define RCU_CFG0_SCSS_IRC8 (0 << RCU_CFG0_SCSS_Pos)
|
|
|
|
#define RCU_CFG0_SCSS_HXTAL (1 << RCU_CFG0_SCSS_Pos)
|
|
|
|
#define RCU_CFG0_SCSS_PLL (2 << RCU_CFG0_SCSS_Pos)
|
|
|
|
|
2021-02-17 13:47:50 +01:00
|
|
|
#define ENABLE_DEBUG 0
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
void periph_clk_en(bus_t bus, uint32_t mask)
|
|
|
|
{
|
|
|
|
switch (bus) {
|
|
|
|
case AHB:
|
|
|
|
cpu_reg_enable_bits(&RCU->AHBEN, mask);
|
|
|
|
break;
|
|
|
|
case APB1:
|
|
|
|
cpu_reg_enable_bits(&RCU->APB1EN, mask);
|
|
|
|
break;
|
|
|
|
case APB2:
|
|
|
|
cpu_reg_enable_bits(&RCU->APB2EN, mask);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG("unsupported bus %d\n", (int)bus);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void periph_clk_dis(bus_t bus, uint32_t mask)
|
|
|
|
{
|
|
|
|
switch (bus) {
|
|
|
|
case AHB:
|
|
|
|
cpu_reg_disable_bits(&RCU->AHBEN, mask);
|
|
|
|
break;
|
|
|
|
case APB1:
|
|
|
|
cpu_reg_disable_bits(&RCU->APB1EN, mask);
|
|
|
|
break;
|
|
|
|
case APB2:
|
|
|
|
cpu_reg_disable_bits(&RCU->APB2EN, mask);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG("unsupported bus %d\n", (int)bus);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t periph_apb_clk(bus_t bus)
|
|
|
|
{
|
|
|
|
switch (bus) {
|
|
|
|
case AHB:
|
|
|
|
return CLOCK_AHB;
|
|
|
|
case APB1:
|
|
|
|
return CLOCK_APB1;
|
|
|
|
case APB2:
|
|
|
|
return CLOCK_APB2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gd32v_enable_irc8(void)
|
|
|
|
{
|
|
|
|
cpu_reg_enable_bits(&RCU->CTL, RCU_CTL_IRC8MEN_Msk);
|
|
|
|
while (!(RCU->CTL & RCU_CTL_IRC8MSTB_Msk)) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gd32v_disable_irc8(void)
|
|
|
|
{
|
|
|
|
RCU->CTL &= ~(RCU_CTL_IRC8MEN_Msk);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gd32vf103_clock_init(void)
|
|
|
|
{
|
|
|
|
unsigned is = irq_disable();
|
|
|
|
|
|
|
|
/* enable HSI clock for the duration of initialization */
|
|
|
|
gd32v_enable_irc8();
|
|
|
|
|
|
|
|
/* use HSI as system clock while we do any further configuration and
|
|
|
|
* configure the AHB and APB clock dividers as configure by the board */
|
|
|
|
RCU->CFG0 = (RCU_CFG0_SCS_IRC8 | CLOCK_AHB_DIV_CONF |
|
|
|
|
CLOCK_APB1_DIV_CONF | CLOCK_APB2_DIV_CONF);
|
2023-03-20 12:04:17 +01:00
|
|
|
while ((RCU->CFG0 & RCU_CFG0_SCSS_Msk) != RCU_CFG0_SCSS_IRC8) {}
|
2021-02-17 13:47:50 +01:00
|
|
|
|
|
|
|
/* disable all active clocks except IRC8 -> resets the clk configuration */
|
2023-01-08 10:38:36 +01:00
|
|
|
RCU->CTL &= (RCU_CTL_IRC8MCALIB_Msk | RCU_CTL_IRC8MADJ_Msk);
|
|
|
|
RCU->CTL |= RCU_CTL_IRC8MEN_Msk;
|
2021-02-17 13:47:50 +01:00
|
|
|
|
2023-03-20 12:07:57 +01:00
|
|
|
/* reset PLL multiplier, required when configured before, e.g. in riotboot */
|
|
|
|
RCU->CFG0 &= ~(RCU_CFG0_PLLMF_3_0_Msk | RCU_CFG0_PLLMF_4_Msk);
|
|
|
|
|
2021-02-17 13:47:50 +01:00
|
|
|
if (IS_ACTIVE(CONFIG_BOARD_HAS_HXTAL)) {
|
2023-01-08 09:54:13 +01:00
|
|
|
/* if the board has an HXTAL, HXTAL is used as PLL input and PREDEV0 is set */
|
2021-02-17 13:47:50 +01:00
|
|
|
cpu_reg_enable_bits(&RCU->CTL, RCU_CTL_HXTALEN_Msk);
|
|
|
|
while (!(RCU->CTL & RCU_CTL_HXTALSTB_Msk)) {}
|
|
|
|
|
2023-01-08 09:54:13 +01:00
|
|
|
RCU->CFG1 = PREDV0_CONF;
|
|
|
|
RCU->CFG0 |= RCU_CFG0_PLLSEL_Msk;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* if the board doesn't have HXTAL, IRCM8/2 is used as PLL input */
|
|
|
|
RCU->CFG0 &= ~RCU_CFG0_PLLSEL_Msk;
|
|
|
|
}
|
|
|
|
RCU->CFG0 |= ((PLL_MULT_FACTOR & 0xf) << RCU_CFG0_PLLMF_3_0_Pos) |
|
2021-02-17 13:47:50 +01:00
|
|
|
((PLL_MULT_FACTOR & 0x10) << (RCU_CFG0_PLLMF_4_Pos - 4));
|
|
|
|
|
2023-01-08 09:54:13 +01:00
|
|
|
RCU->CTL |= RCU_CTL_PLLEN_Msk;
|
2021-02-17 13:47:50 +01:00
|
|
|
|
|
|
|
/* Wait for PLL to stabilize */
|
|
|
|
while ((RCU->CTL & RCU_CTL_PLLSTB_Msk) != RCU_CTL_PLLSTB_Msk) {}
|
|
|
|
|
|
|
|
/* Switch clock input */
|
|
|
|
RCU->CFG0 |= RCU_CFG0_SCS_PLL;
|
|
|
|
|
|
|
|
RCU->AHBEN &= ~RCU_AHBEN_FMCSPEN_Msk;
|
|
|
|
|
2023-03-20 12:04:17 +01:00
|
|
|
while ((RCU->CFG0 & RCU_CFG0_SCSS_Msk) != RCU_CFG0_SCSS_PLL) {}
|
2023-01-08 09:54:13 +01:00
|
|
|
|
|
|
|
if (IS_ACTIVE(CONFIG_BOARD_HAS_HXTAL)) {
|
|
|
|
/* disable IRCM8 clock if HXTAL is used */
|
|
|
|
gd32v_disable_irc8();
|
|
|
|
}
|
|
|
|
|
2021-02-17 13:47:50 +01:00
|
|
|
irq_restore(is);
|
|
|
|
}
|