soc: riscv: bouffalolab: Add bl60x series cpu

Add initial version.

Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2021-08-02 23:04:17 -03:00 committed by Benjamin Cabé
commit 3c45c8b5cf
20 changed files with 676 additions and 0 deletions

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2021-2025 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_HAL_BFLB_GLB_H_
#define ZEPHYR_HAL_BFLB_GLB_H_
#ifdef CONFIG_SOC_SERIES_BL60X
#include <bl602_glb.h>
#endif
#endif /* ZEPHYR_HAL_BFLB_GLB_H_ */

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2021-2025 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_HAL_BFLB_HBN_H_
#define ZEPHYR_HAL_BFLB_HBN_H_
#ifdef CONFIG_SOC_SERIES_BL60X
#include <bl602_hbn.h>
#endif
#endif /* ZEPHYR_HAL_BFLB_HBN_H_ */

View file

@ -0,0 +1,6 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(common)
add_subdirectory(${SOC_SERIES})

12
soc/bouffalolab/Kconfig Normal file
View file

@ -0,0 +1,12 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_BOUFFALOLAB_BFLB
select HAS_BFLB_HAL
if SOC_FAMILY_BOUFFALOLAB_BFLB
rsource "*/Kconfig"
endif # SOC_FAMILY_BOUFFALOLAB_BFLB

View file

@ -0,0 +1,12 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
if SOC_FAMILY_BOUFFALOLAB_BFLB
config SYS_CLOCK_HW_CYCLES_PER_SEC
default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency)
rsource "*/Kconfig.defconfig"
endif # SOC_FAMILY_BOUFFALOLAB_BFLB

View file

@ -0,0 +1,11 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_BOUFFALOLAB_BFLB
bool
config SOC_FAMILY
default "bouffalolab_bflb" if SOC_FAMILY_BOUFFALOLAB_BFLB
rsource "*/Kconfig.soc"

View file

@ -0,0 +1,13 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
zephyr_include_directories(.)
zephyr_sources(soc.c)
zephyr_linker_sources_ifdef(CONFIG_SOC_SERIES_BL60X RODATA rodata.ld)
set(SOC_LINKER_SCRIPT
${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld
CACHE INTERNAL ""
)

View file

@ -0,0 +1,18 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
config SOC_SERIES_BL60X
select RISCV
select RISCV_MACHINE_TIMER
select RISCV_ISA_RV32I
select RISCV_ISA_EXT_M
select RISCV_ISA_EXT_A
select RISCV_ISA_EXT_C
select RISCV_ISA_EXT_ZICSR
select RISCV_ISA_EXT_ZIFENCEI
select ATOMIC_OPERATIONS_C
select CPU_HAS_FPU
select INCLUDE_RESET_VECTOR
select SOC_EARLY_INIT_HOOK
select XIP

View file

@ -0,0 +1,10 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
if SOC_SERIES_BL60X
config NUM_IRQS
default 80
endif # SOC_SERIES_BL60X

View file

@ -0,0 +1,49 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
config SOC_SERIES_BL60X
bool
select SOC_FAMILY_BOUFFALOLAB_BFLB
help
Enable support for BouffaloLab BL6xx MCU series
config SOC_SERIES
default "bl60x" if SOC_SERIES_BL60X
config SOC_BL602C00Q2I
bool
select SOC_SERIES_BL60X
config SOC_BL602C20Q2I
bool
select SOC_SERIES_BL60X
config SOC_BL602C20Q2IS
bool
select SOC_SERIES_BL60X
config SOC_BL602C40Q2IS
bool
select SOC_SERIES_BL60X
config SOC_BL602l10Q2H
bool
select SOC_SERIES_BL60X
config SOC_BL602l20Q2H
bool
select SOC_SERIES_BL60X
config SOC_BL604E20Q2I
bool
select SOC_SERIES_BL60X
config SOC
default "bl602c00q2i" if SOC_BL602C00Q2I
default "bl602c20q2i" if SOC_BL602C20Q2I
default "bl602c20q2is" if SOC_BL602C20Q2IS
default "bl602c40q2is" if SOC_BL602C40Q2IS
default "bl602l10q2h" if SOC_BL602l10Q2H
default "bl602l20q2h" if SOC_BL602l20Q2H
default "bl604e20q2i" if SOC_BL604E20Q2I

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2021-2025 ATL Electronics
*
* SPDX-License-Identifier: Apache-2.0
*/
KEEP(*(SORT_NONE( EXCLUDE_FILE( *bl602_glb.o \
*bl602_pds.o \
*bl602_common.o \
*bl602_sf_cfg.o \
*bl602_sf_cfg_ext*.o* \
*bl602_sf_ctrl.o \
*bl602_sflash.o \
*bl602_sflash_ext*.o* \
*bl602_xip_sflash.o \
*bl602_xip_sflash_ext*.o* \
*bl602_ef_ctrl.o) .rodata*)))

122
soc/bouffalolab/bl60x/soc.c Normal file
View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2021-2025 ATL Electronics
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Bouffalo Lab RISC-V MCU series initialization code
*/
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/irq.h>
#include <bflb_hbn.h>
#include <bflb_glb.h>
#include <clic.h>
#define ROOT_FCLK_DIV (0)
#define ROOT_BCLK_DIV (1)
#define ROOT_UART_CLOCK_DIV (0)
static void system_bor_init(void)
{
HBN_BOR_CFG_Type borCfg = { 1 /* pu_bor */, 0 /* irq_bor_en */,
1 /* bor_vth */, 1 /* bor_sel */ };
HBN_Set_BOR_Cfg(&borCfg);
}
static uint32_t mtimer_get_clk_src_div(void)
{
return ((SystemCoreClockGet() / (GLB_Get_BCLK_Div() + 1))
/ 1000 / 1000 - 1);
}
static void system_clock_init(void)
{
GLB_Set_System_CLK(GLB_PLL_XTAL_40M, GLB_SYS_CLK_PLL160M);
GLB_Set_System_CLK_Div(ROOT_FCLK_DIV, ROOT_BCLK_DIV);
GLB_Set_MTimer_CLK(1, GLB_MTIMER_CLK_BCLK, mtimer_get_clk_src_div());
}
static void peripheral_clock_init(void)
{
GLB_Set_UART_CLK(1, HBN_UART_CLK_160M, ROOT_UART_CLOCK_DIV);
}
void soc_early_init_hook(void)
{
uint32_t key;
uint32_t *p;
uint32_t i = 0;
uint32_t tmp = 0;
key = irq_lock();
__disable_irq();
/* disable hardware_pullup_pull_down (reg_en_hw_pu_pd = 0) */
tmp = BL_RD_REG(HBN_BASE, HBN_IRQ_MODE);
tmp = BL_CLR_REG_BIT(tmp, HBN_REG_EN_HW_PU_PD);
BL_WR_REG(HBN_BASE, HBN_IRQ_MODE, tmp);
/* GLB_Set_EM_Sel(GLB_EM_0KB); */
tmp = BL_RD_REG(GLB_BASE, GLB_SEAM_MISC);
tmp = BL_SET_REG_BITS_VAL(tmp, GLB_EM_SEL, GLB_EM_0KB);
BL_WR_REG(GLB_BASE, GLB_SEAM_MISC, tmp);
/* Fix 26M xtal clkpll_sdmin */
tmp = BL_RD_REG(PDS_BASE, PDS_CLKPLL_SDM);
if (BL_GET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN) == 0x49D39D) {
tmp = BL_SET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN, 0x49D89E);
BL_WR_REG(PDS_BASE, PDS_CLKPLL_SDM, tmp);
}
/* Restore default setting*/
/* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); */
tmp = BL_RD_REG(GLB_BASE, GLB_PARM);
tmp = BL_SET_REG_BITS_VAL(tmp, GLB_UART_SWAP_SET, UART_SIG_SWAP_NONE);
BL_WR_REG(GLB_BASE, GLB_PARM, tmp);
/* GLB_JTAG_Sig_Swap_Set(JTAG_SIG_SWAP_NONE); */
tmp = BL_RD_REG(GLB_BASE, GLB_PARM);
tmp = BL_SET_REG_BITS_VAL(tmp, GLB_JTAG_SWAP_SET, JTAG_SIG_SWAP_NONE);
BL_WR_REG(GLB_BASE, GLB_PARM, tmp);
/* CLear all interrupt */
p = (uint32_t *)(CLIC_HART0_ADDR + CLIC_INTIE);
for (i = 0; i < (IRQn_LAST + 3) / 4; i++) {
p[i] = 0;
}
p = (uint32_t *)(CLIC_HART0_ADDR + CLIC_INTIP);
for (i = 0; i < (IRQn_LAST + 3) / 4; i++) {
p[i] = 0;
}
/* init bor for all platform */
system_bor_init();
/* global IRQ enable */
__enable_irq();
system_clock_init();
peripheral_clock_init();
irq_unlock(key);
}
/* identify flash config automatically */
extern BL_Err_Type flash_init(void);
void System_Post_Init(void)
{
PDS_Trim_RC32M();
HBN_Trim_RC32K();
flash_init();
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2021-2025 ATL Electronics
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Board configuration macros
*
* This header file is used to specify and describe board-level aspects
*/
#ifndef _SOC__H_
#define _SOC__H_
#include <zephyr/sys/util.h>
#include <../common/soc_common.h>
#ifndef _ASMLANGUAGE
/* Add include for DTS generated information */
#include <zephyr/devicetree.h>
#if defined(CONFIG_SOC_SERIES_BL60X)
#include <bl602.h>
#else
#error Library does not support the specified device.
#endif
/* clang-format off */
/* RISC-V Machine Timer configuration */
#define RISCV_MTIME_BASE 0x0200BFF8
#define RISCV_MTIMECMP_BASE 0x02004000
/* lib-c hooks required RAM defined variables */
#define RISCV_RAM_BASE DT_SRAM_BASE_ADDRESS
#define RISCV_RAM_SIZE KB(DT_SRAM_SIZE)
#define SOC_BOUFFALOLAB_BL_PLL160_FREQ_HZ (160000000)
#define SOC_BOUFFALOLAB_BL_HCLK_FREQ_HZ \
DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
/* clang-format on */
#endif /* !_ASMLANGUAGE */
#endif /* _SOC__H_ */

View file

@ -0,0 +1,11 @@
# Copyright (c) 2021-2025 ATL Electronics
#
# SPDX-License-Identifier: Apache-2.0
zephyr_include_directories(.)
zephyr_sources(
soc_irq.S
soc_common_irq.c
vector.S
)

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021-2025 ATL Electronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SIFIVE_CLIC_H
#define _SIFIVE_CLIC_H
#define CLIC_CTRL_ADDR (DT_REG_ADDR(DT_NODELABEL(clic)))
#define CLIC_HART0_OFFSET (0x800000U)
#define CLIC_HART0_ADDR (CLIC_CTRL_ADDR + CLIC_HART0_OFFSET)
#define CLIC_MSIP 0x0000
#define CLIC_MSIP_size 0x4
#define CLIC_MTIMECMP 0x4000
#define CLIC_MTIMECMP_size 0x8
#define CLIC_MTIME 0xBFF8
#define CLIC_MTIME_size 0x8
#define CLIC_INTIP 0x000
#define CLIC_INTIE 0x400
#define CLIC_INTCFG 0x800
#define CLIC_CFG 0xc00
#endif /* _SIFIVE_CLIC_H */

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2021-2025 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file interrupt management code for riscv SOCs supporting the SiFive clic
*/
#ifndef __SOC_COMMON_H_
#define __SOC_COMMON_H_
/* clang-format off */
/* IRQ numbers */
#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */
#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */
#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */
/* ECALL Exception numbers */
#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */
#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */
/* SOC-specific MCAUSE bitfields */
#ifdef CONFIG_64BIT
/* Interrupt Mask */
#define SOC_MCAUSE_IRQ_MASK (1 << 63)
/* Exception code Mask */
#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFFFFFFFFFF
#else
/* Interrupt Mask */
#define SOC_MCAUSE_IRQ_MASK (1 << 31)
/* Exception code Mask */
#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF
#endif
/* SOC-Specific EXIT ISR command */
#define SOC_ERET mret
/* CLINT Base Address */
#define CLIC_TIMER_ENABLE_ADDRESS (0x02800407)
/* In mstatus register */
#define SOC_MIE_MSIE (0x1 << 3) /* Machine Software Interrupt Enable */
/* IRQ 0-15 : (exception:interrupt=0) */
#define SOC_IRQ_IAMISALIGNED (0) /* Instruction Address Misaligned */
#define SOC_IRQ_IAFAULT (1) /* Instruction Address Fault */
#define SOC_IRQ_IINSTRUCTION (2) /* Illegal Instruction */
#define SOC_IRQ_BPOINT (3) /* Break Point */
#define SOC_IRQ_LAMISALIGNED (4) /* Load Address Misaligned */
#define SOC_IRQ_LAFAULT (5) /* Load Access Fault */
#define SOC_IRQ_SAMISALIGNED (6) /* Store/AMO Address Misaligned */
#define SOC_IRQ_SAFAULT (7) /* Store/AMO Access Fault */
#define SOC_IRQ_ECALLU (8) /* Environment Call from U-mode */
/* 9-10: Reserved */
#define SOC_IRQ_ECALLM (11) /* Environment Call from M-mode */
/* 12-15: Reserved */
/* IRQ 16- : (async event:interrupt=1) */
#define SOC_IRQ_NUM_BASE (16)
#define SOC_IRQ_ASYNC (16)
/* Machine Software Int */
#define SOC_IRQ_MSOFT (SOC_IRQ_ASYNC + RISCV_MACHINE_SOFT_IRQ)
/* Machine Timer Int */
#define SOC_IRQ_MTIMER (SOC_IRQ_ASYNC + RISCV_MACHINE_TIMER_IRQ)
/* Machine External Int */
#define SOC_IRQ_MEXT (SOC_IRQ_ASYNC + RISCV_MACHINE_EXT_IRQ)
/* Machine Global External Interrupt */
#define SOC_NR_MGEI_IRQS (64)
/* Total number of IRQs */
#define SOC_NR_IRQS (SOC_NR_MGEI_IRQS + SOC_IRQ_NUM_BASE)
/* clang-format on */
#endif /* __SOC_COMMON_H_ */

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2021-2025 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief interrupt management code for riscv SOCs supporting the SiFive clic
*/
#include <zephyr/irq.h>
#include <soc.h>
#include <clic.h>
/* clang-format off */
static void clic_irq_enable(unsigned int irq)
{
*(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 1;
}
static void clic_irq_disable(unsigned int irq)
{
*(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 0;
}
void arch_irq_enable(unsigned int irq)
{
uint32_t mie;
if (irq == SOC_IRQ_MSOFT) {
/* Read mstatus & set machine software interrupt enable in mie */
__asm__ volatile("csrrs %0, mie, %1"
: "=r"(mie)
: "r"(BIT(RISCV_MACHINE_SOFT_IRQ)));
} else if (irq == SOC_IRQ_MTIMER) {
*(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 1;
/* Read mstatus & set machine timer interrupt enable in mie */
__asm__ volatile("csrrs %0, mie, %1"
: "=r"(mie)
: "r"(BIT(RISCV_MACHINE_TIMER_IRQ)
| BIT(RISCV_MACHINE_EXT_IRQ)));
} else {
clic_irq_enable(irq - SOC_IRQ_ASYNC);
}
}
void arch_irq_disable(unsigned int irq)
{
uint32_t mie;
if (irq == SOC_IRQ_MSOFT) {
/* Read mstatus & set machine software interrupt enable in mie */
__asm__ volatile("csrrc %0, mie, %1"
: "=r"(mie)
: "r"(BIT(RISCV_MACHINE_SOFT_IRQ)));
} else if (irq == SOC_IRQ_MTIMER) {
*(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 0;
/* Read mstatus & set machine timer interrupt enable in mie */
__asm__ volatile("csrrc %0, mie, %1"
: "=r"(mie)
: "r"(BIT(RISCV_MACHINE_TIMER_IRQ)
| BIT(RISCV_MACHINE_EXT_IRQ)));
} else {
clic_irq_disable(irq - SOC_IRQ_ASYNC);
}
}
void arch_irq_priority_set(unsigned int irq, unsigned int prio)
{
ARG_UNUSED(irq);
ARG_UNUSED(prio);
}
int arch_irq_is_enabled(unsigned int irq)
{
uint32_t mie;
/* Enable MEIE (machine external interrupt enable) */
__asm__ volatile("csrrs %0, mie, %1"
: "=r"(mie)
: "r"(BIT(RISCV_MACHINE_EXT_IRQ)));
/* Read mstatus & set machine interrupt enable (MIE) in mstatus */
__asm__ volatile("csrrs %0, mstatus, %1"
: "=r"(mie)
: "r"(MSTATUS_MIE));
return !!(mie & SOC_MIE_MSIE);
}
/* clang-format on */

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* common interrupt management code for riscv SOCs supporting the riscv
* privileged architecture specification
*/
#include <zephyr/kernel_structs.h>
#include <offsets.h>
#include <zephyr/toolchain.h>
#include <zephyr/linker/sections.h>
#include <soc.h>
/* exports */
GTEXT(__soc_handle_irq)
/*
* SOC-specific function to handle pending IRQ number generating the interrupt.
* Exception number is given as parameter via register a0.
*/
SECTION_FUNC(exception.other, __soc_handle_irq)
/* Clear exception number from CSR mip register */
li t1, 1
sll t0, t1, a0
csrrc t1, mip, t0
/* Return */
jalr x0, ra
/*
* __soc_is_irq is defined as .weak to allow re-implementation by
* SOCs that does not truly follow the riscv privilege specification.
*/
WTEXT(__soc_is_irq)
/*
* SOC-specific function to determine if the exception is the result of a
* an interrupt or an exception
* return 1 (interrupt) or 0 (exception)
*
*/
SECTION_FUNC(exception.other, __soc_is_irq)
/* Read mcause and check if interrupt bit is set */
csrr t0, mcause
li t1, SOC_MCAUSE_IRQ_MASK
and t0, t0, t1
/* If interrupt bit is not set, return with 0 */
addi a0, x0, 0
beqz t0, not_interrupt
addi a0, a0, 1
not_interrupt:
/* return */
jalr x0, ra

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2021-2025 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/toolchain.h>
#include <zephyr/arch/riscv/csr.h>
/* exports */
GTEXT(__start)
/* imports */
GTEXT(__initialize)
GTEXT(_isr_wrapper)
SECTION_FUNC(vectors, __start)
.cfi_startproc
.option norvc
/* Inform the debugger that there is nowhere to backtrace */
.cfi_undefined ra
/* Disable interrupts */
li t0, MSTATUS_MIE
csrc mstatus, t0
/*
* Set mtvec (Machine Trap-Vector Base-Address Register)
* CLINT Direct mode
*/
la t0, _isr_wrapper
csrw mtvec, t0
/* Jump to __initialize */
tail __initialize
.cfi_endproc

13
soc/bouffalolab/soc.yml Normal file
View file

@ -0,0 +1,13 @@
family:
- name: bouffalolab_bflb
series:
- name: bl60x
socs:
- name: bl602c00q2i
- name: bl602c20q2i
- name: bl602c20q2is
- name: bl602c40q2is
- name: bl602l10q2h
- name: bl602l20q2h
- name: bl604e20q2i
vendor: bflb