rt-thread/bsp/bluetrum/libraries/hal_libraries/bmsis/source/system_ab32vgx.c

431 lines
12 KiB
C
Raw Normal View History

/*
* Copyright (c) 2020-2020, BLUETRUM Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ab32vgx.h"
#ifndef ALIGN
#define ALIGN(n) __attribute__((aligned(n)))
#endif // ALIGN
typedef struct _sys_t {
uint8_t cnt_1us; //delay 1us cnt
uint8_t main_start; //Main是否已启动
uint8_t clk_sel; //system clock select
uint8_t sys_clk;
// uint8_t aupll_type; //区分AUPLL的频率
uint16_t rand_seed;
uint32_t uart0baud; //UART0BAUD
} sys_t;
AT(.text.sys_clk.table)
const uint8_t sysclk_sel_tbl[] = {
OSCDIV_2M, //SYS_2M
PLL0DIV_12M, //SYS_12M
OSCDIV_13M, //SYS_13M
PLL0DIV_24M, //SYS_24M
OSCDIV_26M, //SYS_26M
PLL0DIV_30M, //SYS_30M
PLL0DIV_48M, //SYS_48M
PLL0DIV_60M, //SYS_60M
PLL0DIV_80M, //SYS_80M
PLL0DIV_120M, //SYS_120M
};
AT(.text.sys_clk.table)
const uint8_t sysclk_index[] = {
2,
12,
13,
24,
26,
30,
48,
60,
80,
120,
};
sys_t sys = {0};
void my_printf(const char *format, ...);
AT(.com_text.delay)
static void delay_us(uint16_t nus)
{
int i;
for (i = 0; i < nus*10; i++) {
asm("nop");
}
}
AT(.text.sys_clk)
uint8_t get_clksel_val(uint8_t val)
{
return sysclk_sel_tbl[val];
}
AT(.text.sys_clk)
uint8_t get_cur_sysclk(void)
{
return sys.sys_clk;
}
uint32_t get_sysclk_nhz(void)
{
return sysclk_index[sys.sys_clk] * 1000000;
}
////AT(.com_text.set_flash_safety)
//static ALWAYS_INLINE void set_flash_safety(uint32_t sys_clk)
//{
// SPI0CON |= BIT(10);
// if (sys_clk > SYS_48M) {
// SPI0CON |= BIT(3); //2bit mode
// spiflash_init(0x3b, 1); //dummy = 1
// } else {
// SPI0CON &= ~BIT(3); //2bit mode
// spiflash_init(0x0b, 1); //dummy = 0
// }
//}
AT(.text.sys_clk)
uint8_t get_sd_rate(void)
{
return 0; //unit: M
}
AT(.text.sys_clk)
uint8_t set_sd_baud(uint8_t sd_rate)
{
uint8_t sd0baud=0;
uint8_t sys_clk=0;
if(sd_rate > 14){//不支持超过14M
return 0;
}
if (sys.sys_clk <= SYSCLK_26M) {
sys_clk=26;
}else if (sys.sys_clk == SYSCLK_48M) {
sys_clk=48;
} else if (sys.sys_clk <= SYSCLK_60M) {
sys_clk=52;
} else if (sys.sys_clk == SYSCLK_80M) {
sys_clk=80;
} else if (sys.sys_clk <= SYSCLK_120M) {
sys_clk=120;
}
sd0baud = sys_clk/sd_rate-1;
if(sys_clk%sd_rate*2/sd_rate) {
sd0baud=sd0baud+1;
}
return sd0baud;
}
void update_sd0baud(void)
{
if (!(SD0CON & BIT(0))) {
return;
}
uint8_t sd_rate=get_sd_rate();
if(sd_rate){
uint8_t sd0baud=set_sd_baud(sd_rate);
if(sd0baud){
SD0BAUD=sd0baud;
return ;
}
}
if (sys.sys_clk <= SYSCLK_30M) {
SD0BAUD = 1;
} else if (sys.sys_clk <= SYSCLK_60M) {
SD0BAUD = 3;
} else if (sys.sys_clk == SYSCLK_80M) {
SD0BAUD = 5;
} else if (sys.sys_clk <= SYSCLK_120M) {
SD0BAUD = 9;
}
}
AT(.text.sys_clk)
uint8_t sysclk_update_baud(uint8_t baud)
{
uint8_t sd_rate=get_sd_rate();
if(baud>20||!sd_rate) {
if (sys.sys_clk == SYSCLK_120M) {
return ((uint16_t)(baud + 1) * 25 / 10 - 1);
} else if (sys.sys_clk >= SYSCLK_80M) {
return ((baud + 1) * 2 - 1);
} else if (sys.sys_clk <= SYSCLK_30M) {
return (((baud + 1) >> 1) - 1);
}
} else if (sd_rate){
return set_sd_baud(sd_rate);
}
return baud;
}
//客户可能用到UART0(使用26M时钟源)做通信,这里可选设置系统时钟时不改波特率
WEAK void update_uart0baud_in_sysclk(uint32_t uart_baud)
{
if(UART0CON & BIT(0)) {
while (!(UART0CON & BIT(8)));
}
UART0BAUD = (uart_baud << 16) | uart_baud;
}
void set_sys_uart0baud(uint32_t baud)
{
sys.uart0baud = baud;
}
//切系统时钟前,先设置模块时钟分频较大值,保证模块不会超频的情况
AT(.com_text.sys)
void set_peripherals_clkdiv_safety(void)
{
uint32_t clkcon3 = CLKCON3;
uint32_t clkcon2 = CLKCON2;
//src clkdiv
clkcon3 &= ~0xf0; //reset src clkdiv
clkcon3 |= (1 << 4); //src clk = sys_clk / (n+1)
//sbcenc硬件要小于48M
clkcon3 &= ~(0x0f << 12); //reset sbcenc clkdiv
clkcon3 |= (2 << 12); //src clk = sys_clk / (n+1)
//aec ram硬件要小于50M
clkcon3 &= ~0x0f; //reset aec clkdiv
clkcon3 &= ~(0x0f << 19); //reset plc clkdiv
clkcon3 &= ~(0x0f << 23); //reset cvsd clkdiv
clkcon3 |= 0x02; //aec clk = sys_clk / (n+1)
clkcon3 |= (2 << 19); //plc clk = sys_clk / (n+1)
clkcon3 |= (2 << 23); //cvsd clk = sys_clk / (n+1)
//audec硬件要小于48M
clkcon2 &= ~(0x0f << 13); //reset audec clkdiv
clkcon2 |= (2 << 13); //audec clk = sys_clk / (n+1)
CLKCON3 = clkcon3;
CLKCON2 = clkcon2;
}
//根据实际系统时钟,设置合适的模块时钟分频
void set_peripherals_clkdiv(void)
{
uint32_t clkcon3 = CLKCON3;
uint32_t clkcon2 = CLKCON2;
uint32_t clkdiv;
uint8_t sys_clk = sys.sys_clk;
//src clkdiv
clkcon3 &= ~0xf0; //reset src clkdiv
if (sys_clk > SYSCLK_80M) {
clkcon3 |= (1 << 4); //src clk = sys_clk / (n+1)
}
//sbcec硬件要小于48M
clkcon3 &= ~(0x0f << 12);
if (sys_clk > SYSCLK_80M) {
clkcon3 |= (2 << 12);
} else if (sys_clk >= SYSCLK_60M) {
clkcon3 |= (1 << 12);
}
//aec ram硬件要小于50M
clkcon3 &= ~0x0f; //reset aec clkdiv
clkcon3 &= ~(0x0f << 19); //reset plc clkdiv
clkcon3 &= ~(0x0f << 23); //reset cvsd clkdiv
if (sys_clk > SYSCLK_80M) {
clkdiv = 2;
} else if (sys_clk >= SYSCLK_60M) {
clkdiv = 1;
} else {
clkdiv = 0;
}
clkcon3 |= clkdiv; //aec clk = sys_clk / (n+1)
clkcon3 |= (clkdiv << 19); //plc clk = sys_clk / (n+1)
clkcon3 |= (clkdiv << 23); //cvsd clk = sys_clk / (n+1)
//audec硬件要小于48M
clkcon2 &= ~(0x0f << 13); //reset audec clkdiv
if (sys_clk > SYSCLK_80M) {
clkdiv = 2;
} else if (sys_clk >= SYSCLK_60M) {
clkdiv = 1;
} else {
clkdiv = 0;
}
clkcon2 |= (clkdiv << 13); //audec clk = sys_clk / (n+1)
CLKCON3 = clkcon3;
CLKCON2 = clkcon2;
// if (sys_clk <= SYS_48M) {
// PWRCON0 = (PWRCON0 & ~0xf) | (sys_trim.vddcore); //VDDCORE减一档
// }
// vddcore_other_offset();
}
ALIGN(512) //注意超过512byte时要用lock cache
static void set_sysclk_do(uint32_t sys_clk, uint32_t clk_sel, uint32_t spll_div, uint32_t spi_baud, uint32_t spi1baud)
{
uint32_t cpu_ie;
cpu_ie = PICCON & BIT(0);
PICCONCLR = BIT(0); //关中断,切换系统时钟
set_peripherals_clkdiv_safety();
CLKCON0 &= ~(BIT(2) | BIT(3)); //sysclk sel rc2m
CLKCON2 &= ~(0x1f << 8); //reset spll div
if(clk_sel <= PLL0DIV_120M) {
//sys_clk来源PLL0的分频配置
CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6)); //sys_pll select pll0out
if (PLL0DIV != (240 * 65536 / 26)) {
PLL0DIV = 240 * 65536 / 26; //pll: 240M, XOSC: 26M
PLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));
PLL0CON |= BIT(3); //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)
PLL0CON |= BIT(20); //update pll0div to pll0_clk
CLKCON3 &= ~(7 << 16);
CLKCON3 |= (4 << 16); //USB CLK 48M
}
} else if (clk_sel <= OSCDIV_26M) {
//sys_clk来源于XOSC26M时钟分频, 无USB时关闭PLL0
// if (!is_usb_support()) {
// PLL0CON &= ~BIT(18);
// PLL0CON &= ~(BIT(12) | BIT(6)); //close pll0
// }
CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6));
CLKCON0 |= BIT(6); //spll select xosc26m_clk
}
CLKCON2 |= (spll_div << 8);
CLKCON0 |= BIT(3); //sysclk sel spll
SPI0BAUD = spi_baud;
if (CLKGAT1 & BIT(12)) {
SPI1BAUD = spi1baud;
}
// if (spiflash_speed_up_en()) {
// set_flash_safety(sys_clk);
// }
PICCON |= cpu_ie;
}
void set_sysclk(uint32_t sys_clk)
{
uint32_t uart_baud, spll_div = 0, spi_baud = 0, spi1baud;
uint8_t cnt_1us, clk_sel;
clk_sel = get_clksel_val(sys_clk);
if(sys.clk_sel == clk_sel) {
return;
}
// if (sys_clk > SYSCLK_48M) {
// PWRCON0 = (PWRCON0 & ~0xf) | (sys_trim.vddcore + 1); //VDDCORE加一档
// }
// vddcore_other_offset();
// printf("%s: %d, %d\n", __func__, sys_clk, clk_sel);
switch (sys_clk) {
case SYSCLK_12M:
spll_div = 19; //pll0 240M
cnt_1us = 1;
spi_baud = 0;
spi1baud = 0;
break;
case SYSCLK_24M:
spll_div = 9; //pll0 240M
cnt_1us = 2;
spi_baud = 0;
spi1baud = 1;
break;
case SYSCLK_30M:
spll_div = 7; //pll0 240M
cnt_1us = 3;
spi_baud = 1; //Baud Rate =Fsys clock / (SPI_BAUD+1)
spi1baud = 1;
break;
case SYSCLK_48M:
spll_div = 4; //pll0 240M
cnt_1us = 4;
spi_baud = 1; //Baud Rate =Fsys clock / (SPI_BAUD+1)
spi1baud = 3;
break;
case SYSCLK_60M:
spll_div = 3; //pll0 240M
cnt_1us = 5;
spi_baud = 2; //Baud Rate =Fsys clock / (SPI_BAUD+1)
spi1baud = 3;
break;
case SYSCLK_80M:
spll_div = 2; //pll0 240M
cnt_1us = 7;
spi_baud = 3; //Baud Rate =Fsys clock / (SPI_BAUD+1)
spi1baud = 4;
break;
case SYSCLK_120M:
spll_div = 1; //pll0 240M
cnt_1us = 10;
spi_baud = 4; //Baud Rate =Fsys clock / (SPI_BAUD+1) //spiclk 120/5 = 24M
spi1baud = 9;
break;
case SYSCLK_26M:
spll_div = 0;
cnt_1us = 3;
spi_baud = 1;
spi1baud = 1;
break;
case SYSCLK_13M:
spll_div = 1;
cnt_1us = 1;
spi_baud = 0;
spi1baud = 0;
break;
case SYSCLK_2M:
spll_div = 1;
cnt_1us = 1;
spi_baud = 0;
spi1baud = 0;
break;
default:
return;
}
//先判断PLL0是否打开
if(clk_sel <= PLL0DIV_120M) {
if (!(PLL0CON & BIT(12))) {
PLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));
PLL0CON |= BIT(3); //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)
PLL0CON |= BIT(12); //enable pll0 ldo
delay_us(100); //delay 100us
PLL0DIV = 240 * 65536 / 26; //pll0: 240M, XOSC: 26M
PLL0CON |= BIT(20); //update pll0div to pll0_clk
PLL0CON |= BIT(6); //enable analog pll0
PLL0CON |= BIT(18); //pll0 sdm enable
delay_us(1000); //wait pll0 stable
}
}
sys.cnt_1us = cnt_1us;
sys.sys_clk = sys_clk;
sys.clk_sel = clk_sel;
uart_baud = (((get_sysclk_nhz() + (sys.uart0baud / 2)) / sys.uart0baud) - 1);
set_sysclk_do(sys_clk, clk_sel,spll_div, spi_baud, spi1baud);
set_peripherals_clkdiv();
update_sd0baud(); //更新下SD0BAUD
update_uart0baud_in_sysclk(uart_baud);
}